Compare commits
216 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2a0d2c43a | |||
| ed66cebb33 | |||
| e915349bc7 | |||
| 02c3bf0302 | |||
| 6537174e1c | |||
| 95cbcdc655 | |||
| 76283bf616 | |||
| 0e5da486a8 | |||
| 6999985333 | |||
| 4d0dc3518c | |||
| d9acf9f01f | |||
| 5eae93e4ab | |||
| c73245a3d9 | |||
| 7a226ad73b | |||
| 9139c1bd0d | |||
| 7cc8b157c0 | |||
| 48b7279b9d | |||
| 33735ffe01 | |||
| 12f0fa1a57 | |||
| b869afd4b2 | |||
| a6ebfe14cc | |||
| 71d5661fe4 | |||
| cf347df937 | |||
| 10967373aa | |||
| b553c0e62a | |||
| da7cfd1551 | |||
| ca1dc3e81e | |||
| 07b95a3c1b | |||
| 63ca8f0a42 | |||
| 9fc25dfe29 | |||
| fcf9f67f5f | |||
| 4d41e46481 | |||
| 58405e3901 | |||
| b7a1abfa2d | |||
| 3ec17b3bdc | |||
| f6eee956a5 | |||
| 55070498db | |||
| 55b5971739 | |||
| fed6eb36c7 | |||
| 2a1b3fd181 | |||
| a74237306f | |||
| c50c71a33c | |||
| ab9e452d40 | |||
| 59bcaca96b | |||
| f8cc1a0b4b | |||
| ba9606694d | |||
| 0aded84207 | |||
| 097fc30201 | |||
| 5b71e64a77 | |||
| eba2e7b669 | |||
| 0e4d82b680 | |||
| bdc57af40c | |||
| 544f9e6104 | |||
| e524a98418 | |||
| 4eea9e5d7b | |||
| 12ee7e45f1 | |||
| 8da0d0871c | |||
| 7f51e49b08 | |||
| 20d035d78c | |||
| f9d6093051 | |||
| 6561ecfcf5 | |||
| a6a5be0ad4 | |||
| 643704e318 | |||
| 488bd82db0 | |||
| 3f98310004 | |||
| 6179563e0b | |||
| d92f2e2f20 | |||
| 8add6b12f5 | |||
| 18b5301c0d | |||
| 3f4b22fef5 | |||
| e4eb1b5943 | |||
| 3ac92f243c | |||
| 384ce42a45 | |||
| 05af2a49ed | |||
| c8207fbc15 | |||
| b1fe363f2f | |||
| 16913e0163 | |||
| 91a91562c2 | |||
| 2e456cea8f | |||
| 981f54a78e | |||
| a68f7a0426 | |||
| 99768cffbe | |||
| ae6c9c154c | |||
| 5ba219a1d0 | |||
| 3ac64db2ae | |||
| fc641d39b6 | |||
| 7c29cdb685 | |||
| 367e2219e3 | |||
| 1f4445a096 | |||
| ae5ae96e62 | |||
| 803b78f196 | |||
| dc5fabe3a9 | |||
| 1692996979 | |||
| 3791ca788b | |||
| 4ba13912b7 | |||
| 2aa4baa5f8 | |||
| 834241dfb5 | |||
| d897251c17 | |||
| e0f73f51ee | |||
| a73b08eba5 | |||
| 2048e8b173 | |||
| c1e01eee35 | |||
| 3bf6b3dee9 | |||
| 6ec2a395e1 | |||
| 468ad6f79e | |||
| a5a6732508 | |||
| 1e457650f3 | |||
| 75f0939b44 | |||
| 33cd1e0767 | |||
| 561c409d59 | |||
| 606b6fe64f | |||
| 4447c3e445 | |||
| e966b83bb2 | |||
| ffa5adb077 | |||
| f2532ec07a | |||
| bc97723e02 | |||
| 65b62a900f | |||
| e61469f8c1 | |||
| 4489832bf3 | |||
| 868843fc89 | |||
| 5cb9474a7d | |||
| 777bc842de | |||
| 04416f8cc3 | |||
| d9ed6f0e5f | |||
| c45354a38c | |||
| 3ac9068e0e | |||
| 4fccfa14e9 | |||
| d22e61a12c | |||
| a595c48526 | |||
| 0ca11bc2f0 | |||
| c346b07b91 | |||
| 8d54de83d3 | |||
| 6d416b34f6 | |||
| aa889ad8d4 | |||
| e08f8498d2 | |||
| f8c6ba224f | |||
| cc3269a50b | |||
| b28ad90d0e | |||
| c81e74b478 | |||
| 574332c3d3 | |||
| e561058051 | |||
| a47f53b8a6 | |||
| 1a2bb68f85 | |||
| fc519143fe | |||
| 5a9ce77ab3 | |||
| 47fed759b6 | |||
| 07565d9016 | |||
| b73ebafa0f | |||
| 3e6a0ab713 | |||
| ec752068a5 | |||
| 54dfe6237c | |||
| c39f32c542 | |||
| 53c27cdd66 | |||
| 3ba633a9e2 | |||
| 6cf98d0f82 | |||
| 9aade7f5df | |||
| 0952a372b6 | |||
| 44948ebc1f | |||
| 1b194088e1 | |||
| f74713da0c | |||
| 575136a82a | |||
| bcece89ad0 | |||
| 02e1199d51 | |||
| 6f653f5993 | |||
| 89379cd373 | |||
| b99f5c3618 | |||
| e434fd0aef | |||
| 7816f5dc46 | |||
| f2ac2e7cad | |||
| 4cd972c3bb | |||
| 9eb82d8894 | |||
| a889336b25 | |||
| 9c29c634b7 | |||
| 6b18b1bb8a | |||
| 0e5a4cacf8 | |||
| 2cee78634c | |||
| 19d7cd1a16 | |||
| d56fbe21fc | |||
| d14b8e4435 | |||
| ef2fbcd2b6 | |||
| 3551a2613d | |||
| 1acaa6dc15 | |||
| f139ffed75 | |||
| 98875d424f | |||
| a995cbef50 | |||
| 5f9205ef8f | |||
| 54f26e61dc | |||
| e42059f34a | |||
| e819ba832e | |||
| d23ac65dd4 | |||
| 938d3db36f | |||
| 4cb827b51e | |||
| 92da094c9f | |||
| 09e943a10c | |||
| a6d8c6d5b0 | |||
| 3ee18bc667 | |||
| 291a90ace4 | |||
| dd02b5ff0a | |||
| 14bed5aee8 | |||
| 0265975178 | |||
| 61a1c05d3a | |||
| bfe9885603 | |||
| e98d36555b | |||
| e81433f46f | |||
| cf0e921f3e | |||
| 0c98019093 | |||
| ba27dce42d | |||
| 7e5ac3f38f | |||
| 5e3f61cc7c | |||
| 80a1c129f1 | |||
| 629d262ed3 | |||
| df12f6d723 | |||
| 21499f1c74 | |||
| 7d40f2b29d | |||
| a701b9bc60 | |||
| a349550924 |
+10
-10
@@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
|
||||
+58
-53
@@ -11,18 +11,21 @@ The following is a set of guidelines for contributing to Marlin, hosted by the [
|
||||
[I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
|
||||
|
||||
[How Can I Contribute?](#how-can-i-contribute)
|
||||
* [Reporting Bugs](#reporting-bugs)
|
||||
* [Suggesting Features or Changes](#suggesting-features-or-changes)
|
||||
* [Your First Code Contribution](#your-first-code-contribution)
|
||||
* [Pull Requests](#pull-requests)
|
||||
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Suggesting Features or Changes](#suggesting-features-or-changes)
|
||||
- [Your First Code Contribution](#your-first-code-contribution)
|
||||
- [Pull Requests](#pull-requests)
|
||||
|
||||
[Styleguides](#styleguides)
|
||||
* [Git Commit Messages](#git-commit-messages)
|
||||
* [C++ Coding Standards](#c++-coding-standards)
|
||||
* [Documentation Styleguide](#documentation)
|
||||
|
||||
- [Git Commit Messages](#git-commit-messages)
|
||||
- [C++ Coding Standards](#c++-coding-standards)
|
||||
- [Documentation Styleguide](#documentation)
|
||||
|
||||
[Additional Notes](#additional-notes)
|
||||
* [Issue and Pull Request Labels](#issue-and-pull-request-labels)
|
||||
|
||||
- [Issue and Pull Request Labels](#issue-and-pull-request-labels)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
@@ -31,6 +34,7 @@ This project and everyone participating in it is governed by the [Marlin Code of
|
||||
## I don't want to read this whole thing I just have a question!!!
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
||||
|
||||
We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions.
|
||||
@@ -43,10 +47,10 @@ We have a Message Board and a Facebook group where our knowledgable user communi
|
||||
|
||||
If chat is more your speed, you can join the MarlinFirmware Discord server:
|
||||
|
||||
* Use the link https://discord.com/servers/marlin-firmware-461605380783472640 to join up as a General User.
|
||||
* Even though our Discord is pretty active, it may take a while for community members to respond — please be patient!
|
||||
* Use the `#general` channel for general questions or discussion about Marlin.
|
||||
* Other channels exist for certain topics or are limited to Patrons. Check the channel list.
|
||||
- Use the link https://discord.com/servers/marlin-firmware-461605380783472640 to join up as a General User.
|
||||
- Even though our Discord is pretty active, it may take a while for community members to respond — please be patient!
|
||||
- Use the `#general` channel for general questions or discussion about Marlin.
|
||||
- Other channels exist for certain topics or are limited to Patrons. Check the channel list.
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
@@ -57,6 +61,7 @@ This section guides you through submitting a Bug Report for Marlin. Following th
|
||||
Before creating a Bug Report, please test the "nightly" development branch, as you might find out that you don't need to create one. When you are creating a Bug Report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE/bug_report.yml), the information it asks for helps us resolve issues faster.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Regressions can happen. If you find a **Closed** issue that seems like your issue, go ahead and open a new issue and include a link to the original issue in the body of your new one. All you need to create a link is the issue number, preceded by #. For example, #8888.
|
||||
|
||||
#### How Do I Submit A (Good) Bug Report?
|
||||
@@ -65,29 +70,29 @@ Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/).
|
||||
|
||||
Explain the problem and include additional details to help maintainers reproduce the problem:
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to identify the problem.
|
||||
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Marlin, e.g. which command exactly you used in the terminal, or how you started Marlin otherwise. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse, or a keyboard shortcut or an Marlin command, and if so which one?
|
||||
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets or log output in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
|
||||
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
|
||||
* **Explain which behavior you expected to see instead and why.**
|
||||
* **Include detailed log output** especially for probing and leveling. See below for usage of `DEBUG_LEVELING_FEATURE`.
|
||||
* **Include screenshots, links to videos, etc.** which clearly demonstrate the problem.
|
||||
* **Include G-code** (if relevant) that reliably causes the problem to show itself.
|
||||
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
|
||||
- **Use a clear and descriptive title** for the issue to identify the problem.
|
||||
- **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Marlin, e.g. which command exactly you used in the terminal, or how you started Marlin otherwise. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse, or a keyboard shortcut or an Marlin command, and if so which one?
|
||||
- **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets or log output in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
|
||||
- **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
|
||||
- **Explain which behavior you expected to see instead and why.**
|
||||
- **Include detailed log output** especially for probing and leveling. See below for usage of `DEBUG_LEVELING_FEATURE`.
|
||||
- **Include screenshots, links to videos, etc.** which clearly demonstrate the problem.
|
||||
- **Include G-code** (if relevant) that reliably causes the problem to show itself.
|
||||
- **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
|
||||
|
||||
Provide more context:
|
||||
|
||||
* **Can you reproduce the problem with a minimum of options enabled?**
|
||||
* **Did the problem start happening recently** (e.g. after updating to a new version of Marlin) or was this always a problem?
|
||||
* If the problem started happening recently, **can you reproduce the problem in an older version of Marlin?** What's the most recent version in which the problem doesn't happen? You can download older versions of Marlin from [the releases page](https://github.com/MarlinFirmware/Marlin/releases).
|
||||
* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.
|
||||
- **Can you reproduce the problem with a minimum of options enabled?**
|
||||
- **Did the problem start happening recently** (e.g. after updating to a new version of Marlin) or was this always a problem?
|
||||
- If the problem started happening recently, **can you reproduce the problem in an older version of Marlin?** What's the most recent version in which the problem doesn't happen? You can download older versions of Marlin from [the releases page](https://github.com/MarlinFirmware/Marlin/releases).
|
||||
- **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.
|
||||
|
||||
Include details about your configuration and environment:
|
||||
|
||||
* **Which version of Marlin are you using?** Marlin's exact version and build date can be seen in the startup message when a host connects to Marlin, or in the LCD Info menu (if enabled).
|
||||
* **What kind of 3D Printer and electronics are you using**?
|
||||
* **What kind of add-ons (probe, filament sensor) do you have**?
|
||||
* **Include your Configuration files.** Make a ZIP file containing `Configuration.h` and `Configuration_adv.h` and drop it on your reply.
|
||||
- **Which version of Marlin are you using?** Marlin's exact version and build date can be seen in the startup message when a host connects to Marlin, or in the LCD Info menu (if enabled).
|
||||
- **What kind of 3D Printer and electronics are you using**?
|
||||
- **What kind of add-ons (probe, filament sensor) do you have**?
|
||||
- **Include your Configuration files.** Make a ZIP file containing `Configuration.h` and `Configuration_adv.h` and drop it on your reply.
|
||||
|
||||
### Suggesting Features or Changes
|
||||
|
||||
@@ -97,52 +102,52 @@ Before creating a suggestion, please check [this list](https://github.com/Marlin
|
||||
|
||||
#### Before Submitting a Feature Request
|
||||
|
||||
* **Check the [Marlin website](https://marlinfw.org/)** for tips — you might discover that the feature is already included. Most importantly, check if you're using [the latest version of Marlin](https://github.com/MarlinFirmware/Marlin/releases) and if you can get the desired behavior by changing [Marlin's config settings](https://marlinfw.org/docs/configuration/configuration.html).
|
||||
* **Perform a [cursory search](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Feature+Request%22)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
- **Check the [Marlin website](https://marlinfw.org/)** for tips — you might discover that the feature is already included. Most importantly, check if you're using [the latest version of Marlin](https://github.com/MarlinFirmware/Marlin/releases) and if you can get the desired behavior by changing [Marlin's config settings](https://marlinfw.org/docs/configuration/configuration.html).
|
||||
- **Perform a [cursory search](https://github.com/MarlinFirmware/Marlin/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Feature+Request%22)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
|
||||
#### How Do I Submit A (Good) Feature Request?
|
||||
|
||||
Feature Requests are tracked as [GitHub issues](https://guides.github.com/features/issues/). Please follow these guidelines in your request:
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to identify the suggestion.
|
||||
* **Provide a step-by-step description of the requested feature** in as much detail as possible.
|
||||
* **Provide specific examples to demonstrate the steps**.
|
||||
* **Describe the current behavior** and **explain which behavior you expected to see instead** and why.
|
||||
* **Include screenshots and links to videos** which demonstrate the feature or point out the part of Marlin to which the request is related.
|
||||
* **Explain why this feature would be useful** to most Marlin users.
|
||||
* **Name other firmwares that have this feature, if any.**
|
||||
- **Use a clear and descriptive title** for the issue to identify the suggestion.
|
||||
- **Provide a step-by-step description of the requested feature** in as much detail as possible.
|
||||
- **Provide specific examples to demonstrate the steps**.
|
||||
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why.
|
||||
- **Include screenshots and links to videos** which demonstrate the feature or point out the part of Marlin to which the request is related.
|
||||
- **Explain why this feature would be useful** to most Marlin users.
|
||||
- **Name other firmwares that have this feature, if any.**
|
||||
|
||||
### Your First Code Contribution
|
||||
|
||||
Unsure where to begin contributing to Marlin? You can start by looking through these `good-first-issue` and `help-wanted` issues:
|
||||
|
||||
* [Beginner issues][good-first-issue] - issues which should only require a few lines of code, and a test or two.
|
||||
* [Help Wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues.
|
||||
- [Beginner issues][good-first-issue] - issues which should only require a few lines of code, and a test or two.
|
||||
- [Help Wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and Github's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation.
|
||||
Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and GitHub's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation.
|
||||
|
||||
* Fill in [the required template](pull_request_template.md).
|
||||
* Don't include issue numbers in the PR title.
|
||||
* Include pictures, diagrams, and links to videos in your Pull Request to demonstrate your changes, if needed.
|
||||
* Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website.
|
||||
* Document new code with clear and concise comments.
|
||||
* End all files with a newline.
|
||||
- Fill in [the required template](pull_request_template.md).
|
||||
- Don't include issue numbers in the PR title.
|
||||
- Include pictures, diagrams, and links to videos in your Pull Request to demonstrate your changes, if needed.
|
||||
- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website.
|
||||
- Document new code with clear and concise comments.
|
||||
- End all files with a newline.
|
||||
|
||||
## Styleguides
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
* Use the present tense ("Add feature" not "Added feature").
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...").
|
||||
* Limit the first line to 72 characters or fewer.
|
||||
* Reference issues and Pull Requests liberally after the first line.
|
||||
- Use the present tense ("Add feature" not "Added feature").
|
||||
- Use the imperative mood ("Move cursor to..." not "Moves cursor to...").
|
||||
- Limit the first line to 72 characters or fewer.
|
||||
- Reference issues and Pull Requests liberally after the first line.
|
||||
|
||||
### C++ Coding Standards
|
||||
|
||||
* Please read and follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website. Failure to follow these guidelines will delay evaluation and acceptance of Pull Requests.
|
||||
- Please read and follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) posted on our website. Failure to follow these guidelines will delay evaluation and acceptance of Pull Requests.
|
||||
|
||||
### Documentation
|
||||
|
||||
* Guidelines for documentation are still under development. In-general, be clear, concise, and to-the-point.
|
||||
- Guidelines for documentation are still under development. In-general, be clear, concise, and to-the-point.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
SCRIPTS_DIR := buildroot/share/scripts
|
||||
MAKESCRIPTS_DIR := buildroot/share/make
|
||||
CONTAINER_RT_BIN := docker
|
||||
CONTAINER_RT_OPTS := --rm -v $(PWD):/code -v platformio-cache:/root/.platformio
|
||||
CONTAINER_IMAGE := marlin-dev
|
||||
@@ -8,9 +9,8 @@ UNIT_TEST_CONFIG ?= default
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows: use `where` – fall back through the three common names
|
||||
PYTHON := $(shell which python 2>nul || which python3 2>nul || which py 2>nul)
|
||||
# Windows: Use cmd tools to find pins files
|
||||
PINS_RAW := $(shell cmd //c "dir /s /b Marlin\src\pins\*.h 2>nul | findstr /r ".*Marlin\\\\src\\\\pins\\\\.*\\\\pins_.*\.h"")
|
||||
PINS := $(subst \,/,$(PINS_RAW))
|
||||
# Windows: Use Python script to find pins files
|
||||
PINS := $(shell $(PYTHON) $(MAKESCRIPTS_DIR)/find.py Marlin/src/pins -mindepth 2 -name 'pins_*.h')
|
||||
else
|
||||
# POSIX: use `command -v` – prefer python3 over python
|
||||
PYTHON := $(shell command -v python3 2>/dev/null || command -v python 2>/dev/null)
|
||||
@@ -36,6 +36,7 @@ help:
|
||||
@echo "make validate-lines -j : Validate line endings, fails on trailing whitespace, etc."
|
||||
@echo "make validate-pins -j : Validate all pins files, fails if any require reformatting"
|
||||
@echo "make validate-boards -j : Validate boards.h and pins.h for standards compliance"
|
||||
@echo "make validate-urls : Validate URLs in source files"
|
||||
@echo "make tests-single-ci : Run a single test from inside the CI"
|
||||
@echo "make tests-single-local : Run a single test locally"
|
||||
@echo "make tests-single-local-docker : Run a single test locally, using docker"
|
||||
@@ -88,7 +89,7 @@ tests-all-local:
|
||||
@$(PYTHON) -c "import yaml" 2>/dev/null || (echo 'pyyaml module is not installed. Install it with "$(PYTHON) -m pip install pyyaml"' && exit 1)
|
||||
export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \
|
||||
&& export VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) \
|
||||
&& for TEST_TARGET in $$($(PYTHON) $(SCRIPTS_DIR)/get_test_targets.py) ; do \
|
||||
&& for TEST_TARGET in $$($(PYTHON) $(MAKESCRIPTS_DIR)/get_test_targets.py) ; do \
|
||||
if [ "$$TEST_TARGET" = "linux_native" ] && [ "$$(uname)" = "Darwin" ]; then \
|
||||
echo "Skipping tests for $$TEST_TARGET on macOS" ; \
|
||||
continue ; \
|
||||
@@ -151,7 +152,7 @@ validate-pins: format-pins
|
||||
@echo "Validating pins files"
|
||||
@git diff --exit-code || (git status && echo "\nError: Pins files are not formatted correctly. Run \"make format-pins\" to fix.\n" && exit 1)
|
||||
|
||||
.PHONY: format-lines validate-lines
|
||||
.PHONY: format-lines validate-lines validate-urls
|
||||
|
||||
format-lines:
|
||||
@echo "Formatting all sources"
|
||||
@@ -160,7 +161,11 @@ format-lines:
|
||||
|
||||
validate-lines:
|
||||
@echo "Validating text formatting"
|
||||
@npx prettier --check . --editorconfig --object-wrap preserve
|
||||
@npx prettier --check . --editorconfig --object-wrap preserve --prose-wrap never
|
||||
|
||||
validate-urls:
|
||||
@echo "Checking URLs in source files"
|
||||
@$(MAKESCRIPTS_DIR)/check-urls.sh
|
||||
|
||||
BOARDS_FILE := Marlin/src/core/boards.h
|
||||
|
||||
@@ -168,4 +173,4 @@ BOARDS_FILE := Marlin/src/core/boards.h
|
||||
|
||||
validate-boards:
|
||||
@echo "Validating boards.h file"
|
||||
@$(PYTHON) $(SCRIPTS_DIR)/validate_boards.py $(BOARDS_FILE) || (echo "\nError: boards.h file is not valid. Please check and correct it.\n" && exit 1)
|
||||
@$(PYTHON) $(MAKESCRIPTS_DIR)/validate_boards.py $(BOARDS_FILE) || (echo "\nError: boards.h file is not valid. Please check and correct it.\n" && exit 1)
|
||||
|
||||
+26
-16
@@ -61,7 +61,7 @@
|
||||
// @section info
|
||||
|
||||
// Author info of this build printed to the host during boot and M115
|
||||
#define STRING_CONFIG_H_AUTHOR "(none, default config)" // Original author or contributor.
|
||||
#define STRING_CONFIG_H_AUTHOR "(MarlinFirmware)" // Original author or contributor.
|
||||
//#define CUSTOM_VERSION_FILE Version.h // Path from the root directory (no quotes)
|
||||
|
||||
// @section machine
|
||||
@@ -468,7 +468,7 @@
|
||||
//===========================================================================
|
||||
//============================= Thermal Settings ============================
|
||||
//===========================================================================
|
||||
// @section temperature
|
||||
// @section temperature sensors
|
||||
|
||||
/**
|
||||
* Temperature Sensors:
|
||||
@@ -500,8 +500,8 @@
|
||||
* 10 : 100kΩ RS PRO 198-961
|
||||
* 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1%
|
||||
* 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed
|
||||
* 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1%
|
||||
* 14 : 100kΩ (R25), 4092K (beta25), 4.7kΩ pull-up, bed thermistor as used in Ender-5 S1
|
||||
* 13 : 100kΩ Hisense up to 300°C - for "Simple ONE" & "All In ONE" hotend - R25 = 100 kOhm, beta25 = 4100 K, 4.7kΩ pull-up
|
||||
* 14 : 100kΩ (R25), 4092K (beta25), 4.7kΩ pull-up, bed thermistor (as used in Ender-5 S1)
|
||||
* 15 : 100kΩ Calibrated for JGAurora A5 hotend
|
||||
* 17 : 100kΩ Dagoma NTC white thermistor
|
||||
* 18 : 200kΩ ATC Semitec 204GT-2 Dagoma.Fr - MKS_Base_DKU001327
|
||||
@@ -652,6 +652,8 @@
|
||||
#define TEMP_SENSOR_REDUNDANT_MAX_DIFF 10 // (°C) Temperature difference that will trigger a print abort.
|
||||
#endif
|
||||
|
||||
// @section temperature
|
||||
|
||||
// Below this temperature the heater will be switched off
|
||||
// because it probably indicates a broken thermistor wire.
|
||||
#define HEATER_0_MINTEMP 5
|
||||
@@ -1661,7 +1663,7 @@
|
||||
* Nozzle-to-Probe offsets { X, Y, Z }
|
||||
*
|
||||
* X and Y offset
|
||||
* Use a caliper or ruler to measure the distance from the tip of
|
||||
* Use a caliper or ruler to measure the distance (in mm) from the tip of
|
||||
* the Nozzle to the center-point of the Probe in the X and Y axes.
|
||||
*
|
||||
* Z offset
|
||||
@@ -1697,7 +1699,7 @@
|
||||
* | [-] |
|
||||
* O-- FRONT --+
|
||||
*/
|
||||
#define NOZZLE_TO_PROBE_OFFSET { 10, 10, 0 }
|
||||
#define NOZZLE_TO_PROBE_OFFSET { 10, 10, 0 } // (mm) X, Y, Z distance from Nozzle tip to Probe trigger-point
|
||||
|
||||
// Enable and set to use a specific tool for probing. Disable to allow any tool.
|
||||
#define PROBING_TOOL 0
|
||||
@@ -1860,15 +1862,12 @@
|
||||
//#define DISABLE_V
|
||||
//#define DISABLE_W
|
||||
|
||||
// Turn off the display blinking that warns about possible accuracy reduction
|
||||
//#define DISABLE_REDUCED_ACCURACY_WARNING
|
||||
|
||||
// @section extruder
|
||||
|
||||
//#define DISABLE_E // Disable the extruder when not stepping
|
||||
#define DISABLE_OTHER_EXTRUDERS // Keep only the active extruder enabled
|
||||
|
||||
// @section motion
|
||||
// @section stepper drivers
|
||||
|
||||
// Invert the stepper direction. Change (or reverse the motor connector) if an axis goes the wrong way.
|
||||
#define INVERT_X_DIR false
|
||||
@@ -1881,8 +1880,6 @@
|
||||
//#define INVERT_V_DIR false
|
||||
//#define INVERT_W_DIR false
|
||||
|
||||
// @section extruder
|
||||
|
||||
// For direct drive extruder v9 set to true, for geared extruder set to false.
|
||||
#define INVERT_E0_DIR false
|
||||
#define INVERT_E1_DIR false
|
||||
@@ -2349,7 +2346,6 @@
|
||||
//#define LCD_BED_TRAMMING
|
||||
|
||||
#if ENABLED(LCD_BED_TRAMMING)
|
||||
#define BED_TRAMMING_INSET_LFRB { 30, 30, 30, 30 } // (mm) Left, Front, Right, Back insets
|
||||
#define BED_TRAMMING_HEIGHT 0.0 // (mm) Z height of nozzle at tramming points
|
||||
#define BED_TRAMMING_Z_HOP 4.0 // (mm) Z raise between tramming points
|
||||
//#define BED_TRAMMING_INCLUDE_CENTER // Move to the center after the last corner
|
||||
@@ -2358,6 +2354,8 @@
|
||||
#define BED_TRAMMING_PROBE_TOLERANCE 0.1 // (mm)
|
||||
#define BED_TRAMMING_VERIFY_RAISED // After adjustment triggers the probe, re-probe to verify
|
||||
//#define BED_TRAMMING_AUDIO_FEEDBACK
|
||||
#else
|
||||
#define BED_TRAMMING_INSET_LFRB { 30, 30, 30, 30 } // (mm) Left, Front, Right, Back insets
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -2527,7 +2525,7 @@
|
||||
//
|
||||
//#define TEMPERATURE_UNITS_SUPPORT
|
||||
|
||||
// @section temperature
|
||||
// @section temperature presets
|
||||
|
||||
//
|
||||
// Preheat Constants - Up to 10 are supported without changes
|
||||
@@ -2757,10 +2755,10 @@
|
||||
*
|
||||
* Select the language to display on the LCD. These languages are available:
|
||||
*
|
||||
* en, an, bg, ca, cz, da, de, el, el_CY, es, eu, fi, fr, gl, hr, hu, it,
|
||||
* en, an, bg, ca, cz, da, de, el, el_CY, es, eu, fi, fr, gl, hg, hr, hu, id, it,
|
||||
* jp_kana, ko_KR, nl, pl, pt, pt_br, ro, ru, sk, sv, tr, uk, vi, zh_CN, zh_TW
|
||||
*
|
||||
* :{ 'en':'English', 'an':'Aragonese', 'bg':'Bulgarian', 'ca':'Catalan', 'cz':'Czech', 'da':'Danish', 'de':'German', 'el':'Greek (Greece)', 'el_CY':'Greek (Cyprus)', 'es':'Spanish', 'eu':'Basque-Euskera', 'fi':'Finnish', 'fr':'French', 'gl':'Galician', 'hr':'Croatian', 'hu':'Hungarian', 'it':'Italian', 'jp_kana':'Japanese', 'ko_KR':'Korean (South Korea)', 'nl':'Dutch', 'pl':'Polish', 'pt':'Portuguese', 'pt_br':'Portuguese (Brazilian)', 'ro':'Romanian', 'ru':'Russian', 'sk':'Slovak', 'sv':'Swedish', 'tr':'Turkish', 'uk':'Ukrainian', 'vi':'Vietnamese', 'zh_CN':'Chinese (Simplified)', 'zh_TW':'Chinese (Traditional)' }
|
||||
* :{ 'en':'English', 'an':'Aragonese', 'bg':'Bulgarian', 'ca':'Catalan', 'cz':'Czech', 'da':'Danish', 'de':'German', 'el':'Greek (Greece)', 'el_CY':'Greek (Cyprus)', 'es':'Spanish', 'eu':'Basque-Euskera', 'fi':'Finnish', 'fr':'French', 'gl':'Galician', 'hg':'Hinglish (Hindi-Latin)', 'hr':'Croatian', 'hu':'Hungarian', 'id':'Indonesian', 'it':'Italian', 'jp_kana':'Japanese', 'ko_KR':'Korean (South Korea)', 'nl':'Dutch', 'pl':'Polish', 'pt':'Portuguese', 'pt_br':'Portuguese (Brazilian)', 'ro':'Romanian', 'ru':'Russian', 'sk':'Slovak', 'sv':'Swedish', 'tr':'Turkish', 'uk':'Ukrainian', 'vi':'Vietnamese', 'zh_CN':'Chinese (Simplified)', 'zh_TW':'Chinese (Traditional)' }
|
||||
*/
|
||||
#define LCD_LANGUAGE en
|
||||
|
||||
@@ -3045,6 +3043,18 @@
|
||||
//
|
||||
//#define FF_INTERFACEBOARD
|
||||
|
||||
//
|
||||
// MightyBoard LCD and Interface
|
||||
//
|
||||
//#define MIGHTYBOARD_LCD
|
||||
#if ENABLED(MIGHTYBOARD_LCD)
|
||||
//#define MIGHTYBOARD_DEBUG // Lightweight debug output for buttons and encoder
|
||||
//#define MIGHTYBOARD_DISABLE_ENC_PULLUP // Enable if the encoder button is unreliable
|
||||
//#define MIGHTYBOARD_BUTTON_PULLUPS // Enable if other buttons are unreliable
|
||||
//#define MIGHTYBOARD_BACK_STATUS_BUTTONS // Use LEFT/RIGHT buttons for Back / Home.
|
||||
// Otherwise they act like encoder down / up.
|
||||
#endif
|
||||
|
||||
//
|
||||
// TFT GLCD Panel with Marlin UI
|
||||
// Panel connected to main board by SPI or I2C interface.
|
||||
|
||||
+124
-30
@@ -1160,9 +1160,26 @@
|
||||
#if ENABLED(FT_MOTION)
|
||||
//#define FTM_IS_DEFAULT_MOTION // Use FT Motion as the factory default?
|
||||
//#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 and M494 parameters
|
||||
//#define FTM_HOME_AND_PROBE // Use FT Motion for homing / probing. Disable if FT Motion breaks these functions.
|
||||
|
||||
#define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED)
|
||||
//#define NO_STANDARD_MOTION // Disable the standard motion system entirely to save Flash and RAM
|
||||
#if DISABLED(NO_STANDARD_MOTION)
|
||||
//#define FTM_HOME_AND_PROBE // Use FT Motion for homing / probing. Disable if FT Motion breaks these functions.
|
||||
#endif
|
||||
|
||||
//#define FTM_DYNAMIC_FREQ // Enable for linear adjustment of XY shaping frequency according to Z or E
|
||||
#if ENABLED(FTM_DYNAMIC_FREQ)
|
||||
#define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED)
|
||||
#endif
|
||||
|
||||
// Disable unused shapers if you need more free space
|
||||
#define FTM_SHAPER_ZV
|
||||
#define FTM_SHAPER_ZVD
|
||||
#define FTM_SHAPER_ZVDD
|
||||
#define FTM_SHAPER_ZVDDD
|
||||
#define FTM_SHAPER_EI
|
||||
#define FTM_SHAPER_2HEI
|
||||
#define FTM_SHAPER_3HEI
|
||||
#define FTM_SHAPER_MZV
|
||||
|
||||
#define FTM_DEFAULT_SHAPER_X ftMotionShaper_NONE // Default shaper mode on X axis (NONE, ZV, ZVD, ZVDD, ZVDDD, EI, 2HEI, 3HEI, MZV)
|
||||
#define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers
|
||||
@@ -1219,9 +1236,27 @@
|
||||
#define FTM_BUFFER_SIZE 128 // Window size for trajectory generation, must be a power of 2 (e.g 64, 128, 256, ...)
|
||||
// The total buffered time in seconds is (FTM_BUFFER_SIZE/FTM_FS)
|
||||
#define FTM_FS 1000 // (Hz) Frequency for trajectory generation.
|
||||
#define FTM_STEPPER_FS 2'000'000 // (Hz) Time resolution of stepper I/O update. Shouldn't affect CPU much (slower board testing needed)
|
||||
#define FTM_MIN_SHAPE_FREQ 20 // (Hz) Minimum shaping frequency, lower consumes more RAM
|
||||
|
||||
/**
|
||||
* TMC2208 / TMC2208_STANDALONE drivers require a brief pause after a DIR change
|
||||
* to prevent a standstill shutdown when using StealthChop (the standalone default).
|
||||
* These options cause FT Motion to delay for > 750µs after a DIR change on a given axis.
|
||||
* Disable only if you are certain that this can never happen with your TMC2208s.
|
||||
*/
|
||||
#if AXIS_DRIVER_TYPE_X(TMC2208) || AXIS_DRIVER_TYPE_X(TMC2208_STANDALONE)
|
||||
#define FTM_DIR_CHANGE_HOLD_X
|
||||
#endif
|
||||
#if AXIS_DRIVER_TYPE_Y(TMC2208) || AXIS_DRIVER_TYPE_Y(TMC2208_STANDALONE)
|
||||
#define FTM_DIR_CHANGE_HOLD_Y
|
||||
#endif
|
||||
#if AXIS_DRIVER_TYPE_Z(TMC2208) || AXIS_DRIVER_TYPE_Z(TMC2208_STANDALONE)
|
||||
#define FTM_DIR_CHANGE_HOLD_Z
|
||||
#endif
|
||||
#if HAS_E_DRIVER(TMC2208) || HAS_E_DRIVER(TMC2208_STANDALONE)
|
||||
#define FTM_DIR_CHANGE_HOLD_E
|
||||
#endif
|
||||
|
||||
#endif // FT_MOTION
|
||||
|
||||
/**
|
||||
@@ -1510,6 +1545,9 @@
|
||||
|
||||
// @section lcd
|
||||
|
||||
// Turn off the display blinking that warns about possible accuracy reduction
|
||||
//#define DISABLE_REDUCED_ACCURACY_WARNING
|
||||
|
||||
#if HAS_MANUAL_MOVE_MENU
|
||||
#define MANUAL_FEEDRATE { 50*60, 50*60, 4*60, 2*60 } // (mm/min) Feedrates for manual moves along X, Y, Z, E from panel
|
||||
#define FINE_MANUAL_MOVE 0.025 // (mm) Smallest manual move (< 0.1mm) applying to Z on most machines
|
||||
@@ -1579,7 +1617,7 @@
|
||||
#define XATC_Z_OFFSETS { 0, 0, 0 } // Z offsets for X axis sample points
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // HAS_BED_PROBE
|
||||
|
||||
// Include a page of printer information in the LCD Main Menu
|
||||
//#define LCD_INFO_MENU
|
||||
@@ -1763,6 +1801,12 @@
|
||||
*/
|
||||
//#define SD_SPI_SPEED SPI_HALF_SPEED
|
||||
|
||||
/**
|
||||
* Reinit the LCD after SD Card insert/remove or when entering the menu.
|
||||
* Required for some LCDs that use shared SPI with an external SD Card reader.
|
||||
*/
|
||||
#define REINIT_NOISY_LCD
|
||||
|
||||
// The standard SD detect circuit reads LOW when media is inserted and HIGH when empty.
|
||||
// Enable this option and set to HIGH if your SD cards are incorrectly detected.
|
||||
//#define SD_DETECT_STATE HIGH
|
||||
@@ -1797,6 +1841,14 @@
|
||||
#define PE_LEDS_COMPLETED_TIME (30*60) // (seconds) Time to keep the LED "done" color before restoring normal illumination
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Priming for the Remaining Time estimate
|
||||
* Long processes at the start of a G-code file can skew the Remaining Time estimate.
|
||||
* Enable these options to start this estimation at a later point in the G-code file.
|
||||
*/
|
||||
//#define REMAINING_TIME_PRIME // Provide G-code 'M75 R' to prime the Remaining Time estimate
|
||||
//#define REMAINING_TIME_AUTOPRIME // Prime the Remaining Time estimate later (e.g., at the end of 'M109')
|
||||
|
||||
/**
|
||||
* Continue after Power-Loss (Creality3D)
|
||||
*
|
||||
@@ -1863,17 +1915,21 @@
|
||||
|
||||
// SD Card Sorting options
|
||||
#if ENABLED(SDCARD_SORT_ALPHA)
|
||||
#define SDSORT_REVERSE false // Default to sorting file names in reverse order.
|
||||
#define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each.
|
||||
#define SDSORT_FOLDERS -1 // -1=above 0=none 1=below
|
||||
#define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1>
|
||||
#define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting.
|
||||
#define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.)
|
||||
#define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option.
|
||||
#define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use!
|
||||
#define SDSORT_CACHE_VFATS 2 // Maximum number of 13-byte VFAT entries to use for sorting.
|
||||
// Note: Only affects SCROLL_LONG_FILENAMES with SDSORT_CACHE_NAMES but not SDSORT_DYNAMIC_RAM.
|
||||
#define SDSORT_QUICK true // Use Quick Sort as a sorting algorithm. Otherwise use Bubble Sort.
|
||||
#define SDSORT_QUICK true // Use Quick Sort as a sorting algorithm. Otherwise use Bubble Sort.
|
||||
#define SDSORT_REVERSE false // Default to sorting file names in reverse order.
|
||||
#define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each.
|
||||
#define SDSORT_FOLDERS -1 // -1=above 0=none 1=below
|
||||
#define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1>
|
||||
#define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.)
|
||||
#define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting.
|
||||
#if ENABLED(SDSORT_USES_RAM)
|
||||
#define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option.
|
||||
#if ENABLED(SDSORT_CACHE_NAMES)
|
||||
#define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use!
|
||||
#define SDSORT_CACHE_VFATS 2 // Maximum number of 13-byte VFAT entries to use for sorting.
|
||||
// Note: Only affects SCROLL_LONG_FILENAMES with SDSORT_CACHE_NAMES but not SDSORT_DYNAMIC_RAM.
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Allow international symbols in long filenames. To display correctly, the
|
||||
@@ -2327,7 +2383,7 @@
|
||||
//#define WATCHDOG_RESET_MANUAL
|
||||
#endif
|
||||
|
||||
// @section lcd
|
||||
// @section baby-stepping
|
||||
|
||||
/**
|
||||
* Babystepping enables movement of the axes by tiny increments without changing
|
||||
@@ -2580,13 +2636,15 @@
|
||||
#endif
|
||||
#endif // PTC_PROBE || PTC_BED || PTC_HOTEND
|
||||
|
||||
// @section extras
|
||||
// @section gcode
|
||||
|
||||
//
|
||||
// G60/G61 Position Save and Return
|
||||
//
|
||||
//#define SAVED_POSITIONS 1 // Each saved position slot costs 12 bytes
|
||||
|
||||
// @section motion
|
||||
|
||||
//
|
||||
// G2/G3 Arc Support
|
||||
//
|
||||
@@ -2618,6 +2676,8 @@
|
||||
*/
|
||||
//#define DIRECT_STEPPING
|
||||
|
||||
// @section calibrate
|
||||
|
||||
/**
|
||||
* G38 Probe Target
|
||||
*
|
||||
@@ -2739,6 +2799,11 @@
|
||||
// Enable this option to collect and display the number
|
||||
// of dropped bytes after a file transfer to SD.
|
||||
//#define SERIAL_STATS_DROPPED_RX
|
||||
|
||||
// Enable this option to collect and display framing errors.
|
||||
// Framing errors occur when invalid start/stop bits or other
|
||||
// serial protocol violations are detected.
|
||||
//#define SERIAL_STATS_RX_FRAMING_ERRORS
|
||||
#endif
|
||||
|
||||
// Monitor RX buffer usage
|
||||
@@ -2766,8 +2831,8 @@
|
||||
*
|
||||
* Adds support for commands:
|
||||
* S000 : Report State and Position while moving.
|
||||
* P000 : Instant Pause / Hold while moving.
|
||||
* R000 : Resume from Pause / Hold.
|
||||
* P000 : Instant Pause / Hold while moving. Enable SOFT_FEED_HOLD for soft deceleration.
|
||||
* R000 : Resume from Pause / Hold. Enable SOFT_FEED_HOLD for soft acceleration.
|
||||
*
|
||||
* - During Hold all Emergency Parser commands are available, as usual.
|
||||
* - Enable NANODLP_Z_SYNC and NANODLP_ALL_AXIS for move command end-state reports.
|
||||
@@ -2824,7 +2889,7 @@
|
||||
*/
|
||||
//#define EXTRA_FAN_SPEED
|
||||
|
||||
// @section gcode
|
||||
// @section firmware retraction
|
||||
|
||||
/**
|
||||
* Firmware-based and LCD-controlled retract
|
||||
@@ -3544,7 +3609,13 @@
|
||||
//#define SPI_ENDSTOPS // TMC2130, TMC2240, and TMC5160
|
||||
//#define IMPROVE_HOMING_RELIABILITY
|
||||
//#define SENSORLESS_STALLGUARD_DELAY 0 // (ms) Delay to allow drivers to settle
|
||||
#endif
|
||||
|
||||
#if HAS_MARLINUI_MENU
|
||||
// Convenient homing menu items next to Sensorless Homing edit items
|
||||
//#define SENSORLESS_HOMING_TEST_MENU_ITEMS
|
||||
#endif
|
||||
|
||||
#endif // SENSORLESS_HOMING || SENSORLESS_PROBING
|
||||
|
||||
// @section tmc/config
|
||||
|
||||
@@ -3641,7 +3712,7 @@
|
||||
//#define PHOTO_RETRACT_MM 6.5 // (mm) E retract/recover for the photo move (M240 R S)
|
||||
|
||||
// Canon RC-1 or homebrew digital camera trigger
|
||||
// Data from: https://www.doc-diy.net/photo/rc-1_hacked/
|
||||
// Data from: https://web.archive.org/web/20250327153953/www.doc-diy.net/photo/rc-1_hacked/
|
||||
//#define PHOTOGRAPH_PIN 23
|
||||
|
||||
// Canon Hack Development Kit
|
||||
@@ -4212,7 +4283,7 @@
|
||||
#define BUTTON1_WHEN_PRINTING false // Button allowed to trigger during printing?
|
||||
#define BUTTON1_GCODE "G28"
|
||||
#define BUTTON1_DESC "Homing" // Optional string to set the LCD status
|
||||
//#define BUTTON1_IMMEDIATE // Skip the queue and run the G-code immediately. Rarely needed.
|
||||
//#define BUTTON1_IMMEDIATE // Skip the queue and execute immediately. Rarely needed.
|
||||
#endif
|
||||
|
||||
//#define BUTTON2_PIN -1
|
||||
@@ -4278,7 +4349,7 @@
|
||||
* Developed by Chris Barr at Aus3D.
|
||||
*
|
||||
* Wiki: https://wiki.aus3d.com.au/Magnetic_Encoder
|
||||
* Github: https://github.com/Aus3D/MagneticEncoder
|
||||
* GitHub: https://github.com/Aus3D/MagneticEncoder
|
||||
*
|
||||
* Supplier: https://aus3d.com.au/products/magnetic-encoder-module
|
||||
* Alternative Supplier: https://reliabuild3d.com/
|
||||
@@ -4397,15 +4468,38 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Instant freeze / unfreeze functionality
|
||||
* Potentially useful for rapid stop that allows being resumed. Halts stepper movement.
|
||||
* Note this does NOT pause spindles, lasers, fans, heaters or any other auxiliary device.
|
||||
* @section interface
|
||||
* Freeze / Unfreeze
|
||||
*
|
||||
* Pause / Hold that keeps power available and does not stop the spindle can be initiated by
|
||||
* the FREEZE_PIN. Halts instantly (default) or performs a soft feed hold that decelerates and
|
||||
* halts movement at FREEZE_JERK (requires SOFT_FEED_HOLD).
|
||||
* Motion can be resumed by using the FREEZE_PIN.
|
||||
*
|
||||
* NOTE: Controls Laser PWM but does NOT pause Spindle, Fans, Heaters or other devices.
|
||||
* @section freeze
|
||||
*/
|
||||
//#define FREEZE_FEATURE
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
//#define FREEZE_PIN 41 // Override the default (KILL) pin here
|
||||
#define FREEZE_STATE LOW // State of pin indicating freeze
|
||||
//#define FREEZE_PIN -1 // Override the default (KILL) pin here
|
||||
#define FREEZE_STATE LOW // State of pin indicating freeze
|
||||
#endif
|
||||
|
||||
#if ANY(FREEZE_FEATURE, REALTIME_REPORTING_COMMANDS)
|
||||
/**
|
||||
* Command P000 (REALTIME_REPORTING_COMMANDS and EMERGENCY_PARSER) or
|
||||
* FREEZE_PIN (FREEZE_FEATURE) initiates a soft feed hold that keeps
|
||||
* power available and does not stop the spindle.
|
||||
*
|
||||
* The soft feed hold decelerates and halts movement at FREEZE_JERK.
|
||||
* Motion can be resumed with command R000 (requires REALTIME_REPORTING_COMMANDS) or
|
||||
* by using the FREEZE_PIN (requires FREEZE_FEATURE).
|
||||
*
|
||||
* NOTE: Affects Laser PWM but DOES NOT pause Spindle, Fans, Heaters or other devices.
|
||||
*/
|
||||
//#define SOFT_FEED_HOLD
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
#define FREEZE_JERK 2 // (mm/s) Completely halt when motion has decelerated below this value
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -41,7 +41,7 @@
|
||||
* here we define this default string as the date where the latest release
|
||||
* version was tagged.
|
||||
*/
|
||||
//#define STRING_DISTRIBUTION_DATE "2025-12-02"
|
||||
//#define STRING_DISTRIBUTION_DATE "2026-03-19"
|
||||
|
||||
/**
|
||||
* The protocol for communication to the host. Protocol indicates communication
|
||||
@@ -58,7 +58,7 @@
|
||||
/**
|
||||
* The SOURCE_CODE_URL is the location where users will find the Marlin Source
|
||||
* Code which is installed on the device. In most cases —unless the manufacturer
|
||||
* has a distinct Github fork— the Source Code URL should just be the main
|
||||
* has a distinct GitHub fork— the Source Code URL should just be the main
|
||||
* Marlin repository.
|
||||
*/
|
||||
//#define SOURCE_CODE_URL "github.com/MarlinFirmware/Marlin"
|
||||
|
||||
@@ -96,7 +96,7 @@ void MarlinHAL::init() {
|
||||
// Might disable other peripherals using the pin; to circumvent that please undefine one of the above things!
|
||||
// The true culprit is the AVR ArduinoCore that enables peripherals redundantly.
|
||||
// (USART1 on the GeeeTech GT2560)
|
||||
// https://www.youtube.com/watch?v=jMgCvRXkexk
|
||||
// https://youtube.be/jMgCvRXkexk
|
||||
_ATmega_savePinAlternate(BEEPER_PIN);
|
||||
|
||||
OUT_WRITE(BEEPER_PIN, LOW);
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS
|
||||
|
||||
#if MB(BQ_ZUM_MEGA_3D, MIGHTYBOARD_REVE, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
|
||||
#if MB(BQ_ZUM_MEGA_3D, MIGHTYBOARD_REVE, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14, MIGHTYBOARD_REVG)
|
||||
#define AVR_ATmega2560_FAMILY_PLUS_70 1
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* Structures for 2560 family boards that use more than 70 pins
|
||||
*/
|
||||
|
||||
#if MB(BQ_ZUM_MEGA_3D, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
|
||||
#if MB(BQ_ZUM_MEGA_3D, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14, MIGHTYBOARD_REVG)
|
||||
#undef NUM_DIGITAL_PINS
|
||||
#define NUM_DIGITAL_PINS 85
|
||||
#elif MB(MIGHTYBOARD_REVE)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
// ------------------------
|
||||
|
||||
typedef uint16_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFU
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX)
|
||||
|
||||
// ------------------------
|
||||
// Defines
|
||||
@@ -50,10 +50,9 @@ typedef uint16_t hal_timer_t;
|
||||
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
|
||||
#define STEPPER_TIMER_PRESCALE 8
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
/**
|
||||
* Description: Tone function for Arduino Due and compatible (SAM3X8E)
|
||||
* Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
|
||||
* Derived from https://forum.arduino.cc/t/arduino-due-and-tone/133302/13
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_SAM
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define HAL_TIMER_PRESCALER 2
|
||||
#define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals
|
||||
@@ -59,7 +59,6 @@ typedef uint32_t hal_timer_t;
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# editorconfig.org
|
||||
|
||||
[{*.c,*.cpp,*.h}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
@@ -271,7 +271,8 @@ void MarlinHAL::adc_start(const pin_t pin) {
|
||||
uint32_t mv;
|
||||
esp_adc_cal_get_voltage((adc_channel_t)chan, &characteristics[attenuations[chan]], &mv);
|
||||
|
||||
adc_result = mv * isr_float_t(1023) / isr_float_t(ADC_REFERENCE_VOLTAGE) / isr_float_t(1000);
|
||||
static constexpr uint32_t adc_divisor = uint32_t((ADC_REFERENCE_VOLTAGE) * 1000UL);
|
||||
adc_result = (mv * 1023UL) / adc_divisor;
|
||||
|
||||
// Change the attenuation level based on the new reading
|
||||
adc_atten_t atten;
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
// Types
|
||||
// ------------------------
|
||||
|
||||
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
|
||||
typedef int16_t pin_t;
|
||||
|
||||
typedef struct pwm_pin {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
/**
|
||||
* Description: Tone function for ESP32
|
||||
* Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
|
||||
* Derived from https://forum.arduino.cc/t/arduino-due-and-tone/133302/13
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
@@ -156,38 +156,43 @@ void stepperTask(void *parameter) {
|
||||
|
||||
while (dma.rw_pos < DMA_SAMPLE_COUNT) {
|
||||
|
||||
#if ENABLED(FT_MOTION)
|
||||
if (using_ftMotion) {
|
||||
|
||||
if (using_ftMotion) {
|
||||
#if ENABLED(FT_MOTION)
|
||||
if (!nextMainISR) stepper.ftMotion_stepper();
|
||||
nextMainISR = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
||||
if (!using_ftMotion) {
|
||||
if (!nextMainISR) {
|
||||
stepper.pulse_phase_isr();
|
||||
nextMainISR = stepper.block_phase_isr();
|
||||
}
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
else if (!nextAdvanceISR) {
|
||||
stepper.advance_isr();
|
||||
nextAdvanceISR = stepper.la_interval;
|
||||
#if HAS_STANDARD_MOTION
|
||||
|
||||
if (!nextMainISR) {
|
||||
stepper.pulse_phase_isr();
|
||||
nextMainISR = stepper.block_phase_isr();
|
||||
}
|
||||
#endif
|
||||
else
|
||||
i2s_push_sample();
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
else if (!nextAdvanceISR) {
|
||||
stepper.advance_isr();
|
||||
nextAdvanceISR = stepper.la_interval;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
i2s_push_sample();
|
||||
|
||||
nextMainISR--;
|
||||
nextMainISR--;
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
if (nextAdvanceISR == stepper.LA_ADV_NEVER)
|
||||
nextAdvanceISR = stepper.la_interval;
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
if (nextAdvanceISR == stepper.LA_ADV_NEVER)
|
||||
nextAdvanceISR = stepper.la_interval;
|
||||
|
||||
if (nextAdvanceISR && nextAdvanceISR != stepper.LA_ADV_NEVER)
|
||||
nextAdvanceISR--;
|
||||
#endif
|
||||
|
||||
#endif // HAS_STANDARD_MOTION
|
||||
|
||||
if (nextAdvanceISR && nextAdvanceISR != stepper.LA_ADV_NEVER)
|
||||
nextAdvanceISR--;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
#endif
|
||||
|
||||
#if ALL(I2S_STEPPER_STREAM, LIN_ADVANCE) && DISABLED(EXPERIMENTAL_I2S_LA)
|
||||
#error "I2S stream is currently incompatible with LIN_ADVANCE."
|
||||
#error "I2S stream is currently incompatible with LIN_ADVANCE. Enable EXPERIMENTAL_I2S_LA to proceed anyway."
|
||||
#endif
|
||||
|
||||
#if ALL(I2S_STEPPER_STREAM, PRINTCOUNTER) && PRINTCOUNTER_SAVE_INTERVAL > 0 && DISABLED(PRINTCOUNTER_SYNC)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint64_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFF'FFFF'FFFF'FFFFULL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT64_MAX)
|
||||
|
||||
#ifndef MF_TIMER_STEP
|
||||
#define MF_TIMER_STEP 0 // Timer Index for Stepper
|
||||
@@ -66,7 +66,6 @@ typedef uint64_t hal_timer_t;
|
||||
#define STEP_TIMER_MIN_INTERVAL 8 // minimum time in µs between stepper interrupts
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define TONE_TIMER_PRESCALE 1000 // Arbitrary value, no idea what i'm doing here
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
#define __bss_end __bss_end__
|
||||
|
||||
// Types
|
||||
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
|
||||
typedef uint8_t pin_t; // Parity with mfl platform
|
||||
|
||||
// Servo
|
||||
|
||||
@@ -69,10 +69,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAL_TIMER_RATE
|
||||
#define HAL_TIMER_RATE GetStepperTimerClkFreq()
|
||||
#endif
|
||||
|
||||
#ifndef STEP_TIMER
|
||||
#define STEP_TIMER MF_TIMER_STEP
|
||||
#endif
|
||||
@@ -121,9 +117,10 @@ void HAL_timer_start(const uint8_t timer_number, const uint32_t frequency) {
|
||||
|
||||
if (is_step) {
|
||||
timer.setPrescaler(STEPPER_TIMER_PRESCALE);
|
||||
timer.setRolloverValue(_MIN(static_cast<hal_timer_t>(HAL_TIMER_TYPE_MAX),
|
||||
(HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE)),
|
||||
TimerFormat::TICK);
|
||||
timer.setRolloverValue(
|
||||
_MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE))),
|
||||
TimerFormat::TICK
|
||||
);
|
||||
is_step_timer_initialized = true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -34,21 +34,24 @@
|
||||
#define MF_TIMER_TEMP 1
|
||||
#define MF_TIMER_PULSE MF_TIMER_STEP
|
||||
|
||||
#define hal_timer_t uint32_t
|
||||
#define HAL_TIMER_TYPE_MAX UINT16_MAX
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX)
|
||||
|
||||
extern uint32_t GetStepperTimerClkFreq();
|
||||
#ifndef HAL_TIMER_RATE
|
||||
extern uint32_t GetStepperTimerClkFreq();
|
||||
#define HAL_TIMER_RATE GetStepperTimerClkFreq()
|
||||
#endif
|
||||
|
||||
// Timer configuration constants
|
||||
#define STEPPER_TIMER_RATE 2000000
|
||||
#define TEMP_TIMER_FREQUENCY 1000
|
||||
|
||||
// Timer prescaler calculations
|
||||
#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE ((HAL_TIMER_RATE) / (STEPPER_TIMER_RATE)) // Prescaler = 30
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
// Pulse Timer (counter) calculations
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
// Timer interrupt priorities
|
||||
|
||||
@@ -30,17 +30,17 @@
|
||||
* it would not make sense to parse G-Code from TMC responses
|
||||
*/
|
||||
constexpr bool serial_handles_emergency(int port) {
|
||||
return false
|
||||
return (false
|
||||
#ifdef SERIAL_PORT
|
||||
|| (SERIAL_PORT) == port
|
||||
|| (SERIAL_PORT) == port
|
||||
#endif
|
||||
#ifdef SERIAL_PORT_2
|
||||
|| (SERIAL_PORT_2) == port
|
||||
|| (SERIAL_PORT_2) == port
|
||||
#endif
|
||||
#ifdef LCD_SERIAL_PORT
|
||||
|| (LCD_SERIAL_PORT) == port
|
||||
|| (LCD_SERIAL_PORT) == port
|
||||
#endif
|
||||
;
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -48,7 +48,7 @@ constexpr bool serial_handles_emergency(int port) {
|
||||
//
|
||||
|
||||
// serial port where RX and TX use IRQs
|
||||
#define DEFINE_IRQ_SERIAL_MARLIN(name, n) \
|
||||
#define DEFINE_IRQ_SERIAL_MARLIN(name, n) \
|
||||
MSerialT name(serial_handles_emergency(n), \
|
||||
&USART##n##_config, \
|
||||
BOARD_USART##n##_TX_PIN, \
|
||||
@@ -57,7 +57,7 @@ constexpr bool serial_handles_emergency(int port) {
|
||||
// serial port where RX uses DMA and TX uses IRQs
|
||||
// all serial ports use DMA1
|
||||
// since there are 4 USARTs and 4 DMA channels, we can use the USART number as the DMA channel
|
||||
#define DEFINE_DMA_SERIAL_MARLIN(name, n) \
|
||||
#define DEFINE_DMA_SERIAL_MARLIN(name, n) \
|
||||
MSerialT name(serial_handles_emergency(n), \
|
||||
&USART##n##_config, \
|
||||
BOARD_USART##n##_TX_PIN, \
|
||||
@@ -67,12 +67,17 @@ constexpr bool serial_handles_emergency(int port) {
|
||||
|
||||
#define DEFINE_SERIAL_MARLIN(name, n) TERN(SERIAL_DMA, DEFINE_DMA_SERIAL_MARLIN(name, n), DEFINE_IRQ_SERIAL_MARLIN(name, n))
|
||||
|
||||
DEFINE_SERIAL_MARLIN(MSerial1, 1);
|
||||
DEFINE_SERIAL_MARLIN(MSerial2, 2);
|
||||
|
||||
// TODO: remove this warning when SERIAL_DMA has been tested some more
|
||||
#if ENABLED(SERIAL_DMA)
|
||||
#warning "SERIAL_DMA may be unstable on HC32F460."
|
||||
#if PINS_EXIST(BOARD_USART1_RX, BOARD_USART1_TX)
|
||||
DEFINE_SERIAL_MARLIN(MSerial1, 1);
|
||||
#endif
|
||||
#if PINS_EXIST(BOARD_USART2_RX, BOARD_USART2_TX)
|
||||
DEFINE_SERIAL_MARLIN(MSerial2, 2);
|
||||
#endif
|
||||
#if PINS_EXIST(BOARD_USART3_RX, BOARD_USART3_TX)
|
||||
DEFINE_SERIAL_MARLIN(MSerial3, 3);
|
||||
#endif
|
||||
#if PINS_EXIST(BOARD_USART4_RX, BOARD_USART4_TX)
|
||||
DEFINE_SERIAL_MARLIN(MSerial4, 4);
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
@@ -92,3 +92,5 @@ typedef Serial1Class<MarlinSerial> MSerialT;
|
||||
|
||||
extern MSerialT MSerial1;
|
||||
extern MSerialT MSerial2;
|
||||
extern MSerialT MSerial3;
|
||||
extern MSerialT MSerial4;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
// Shared by both panic and PostMortem debugging
|
||||
//
|
||||
static void minserial_begin() {
|
||||
#if !WITHIN(SERIAL_PORT, 1, 3)
|
||||
#if !WITHIN(SERIAL_PORT, 1, 4)
|
||||
#warning "MinSerial requires a physical UART port for output."
|
||||
#warning "Disabling MinSerial because the used serial port is not a HW port."
|
||||
#else
|
||||
|
||||
@@ -6,7 +6,7 @@ This document provides notes on the HAL for the HC32F460 MCU.
|
||||
|
||||
The HC32F460 HAL is designed to be generic enough for any HC32F460-based board. Adding support for a new HC32F460-based board will require the following steps:
|
||||
|
||||
1. Follow [the usual instructions](https://marlinfw.org/docs/development/boards.html#adding-a-new-board) to add a new board to Marlin. (i.e., Add a pins file, edit `boards.h` and `pins.h`, etc.)
|
||||
1. Follow [the usual instructions](//marlinfw.org/docs/development/boards.html#adding-a-new-board) to add a new board to Marlin. (i.e., Add a pins file, edit `boards.h` and `pins.h`, etc.)
|
||||
2. Determine the flash size your board uses:
|
||||
- Examine the board's main processor. (Refer the naming key in `hc32.ini`.)
|
||||
- Extend the `HC32F460C_common` base env for 256K, or `HC32F460E_common` for 512K.
|
||||
@@ -50,10 +50,12 @@ SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
|
||||
Just searching for `SCB->VTOR` should yield some results. From there, you just need to look at the value that's assigned to it. The example uses `APP_START_ADDRESS`.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Some vendors publish incomplete source code. But they sometimes leave version control related files in the repo, which can contain previous version of files that were removed. Find these by including folders like `.git` or `.svn` in your search.
|
||||
|
||||
> [!NOTE]
|
||||
> The example is based on the [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2/blob/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo.
|
||||
>
|
||||
> The example is based on the [Voxelab-64/Aquila_X2](//github.com/Voxelab-64/Aquila_X2/blob/main/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo.
|
||||
|
||||
2. Using a linker script
|
||||
|
||||
@@ -72,7 +74,8 @@ MEMORY
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> This example is based on [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2/blob/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/main/hdsc32core/hc32f46x_flash.ld#L55)
|
||||
>
|
||||
> This example is based on [Voxelab-64/Aquila_X2](//github.com/Voxelab-64/Aquila_X2/blob/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/main/hdsc32core/hc32f46x_flash.ld#L55)
|
||||
|
||||
## Documentation on the HC32F460
|
||||
|
||||
@@ -96,15 +99,15 @@ Contact me on Discord (@shadow578) if you need it.
|
||||
|
||||
This HAL depends on the following projects:
|
||||
|
||||
- [shadow578/platform-hc32f46x](https://github.com/shadow578/platform-hc32f46x) (PlatformIO platform for HC32F46x)
|
||||
- [shadow578/framework-arduino-hc32f46x](https://github.com/shadow578/framework-arduino-hc32f46x) (Arduino framework for HC32F46x)
|
||||
- [shadow578/framework-hc32f46x-ddl](https://github.com/shadow578/framework-hc32f46x-ddl) (HC32F46x DDL framework)
|
||||
- [shadow578/platform-hc32f46x](//github.com/shadow578/platform-hc32f46x) (PlatformIO platform for HC32F46x)
|
||||
- [shadow578/framework-arduino-hc32f46x](//github.com/shadow578/framework-arduino-hc32f46x) (Arduino framework for HC32F46x)
|
||||
- [shadow578/framework-hc32f46x-ddl](//github.com/shadow578/framework-hc32f46x-ddl) (HC32F46x DDL framework)
|
||||
|
||||
## Credits
|
||||
|
||||
This HAL wouldn't be possible without the following projects:
|
||||
|
||||
- [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2) (original implementation)
|
||||
- [alexqzd/Marlin-H32](https://github.com/alexqzd/Marlin-H32) (misc. fixes to the original implementation)
|
||||
- [kgoveas/Arduino-Core-Template](https://github.com/kgoveas/Arduino-Core-Template) (template for Arduino headers)
|
||||
- [stm32duino/Arduino_Core_STM32](https://github.com/stm32duino/Arduino_Core_STM32) (misc. Arduino functions)
|
||||
- [Voxelab-64/Aquila_X2](//github.com/Voxelab-64/Aquila_X2) (original implementation)
|
||||
- [alexqzd/Marlin-H32](//github.com/alexqzd/Marlin-H32) (misc. fixes to the original implementation)
|
||||
- [kgoveas/Arduino-Core-Template](//github.com/kgoveas/Arduino-Core-Template) (template for Arduino headers)
|
||||
- [stm32duino/Arduino_Core_STM32](//github.com/stm32duino/Arduino_Core_STM32) (misc. Arduino functions)
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
#define USART_RX_DMA_SUPPORT 1
|
||||
#endif
|
||||
|
||||
// SoftwareSerial uses STM32duino API compatibility mode
|
||||
#define SOFTWARE_SERIAL_STM32_API_COMPATIBILITY 1
|
||||
|
||||
//
|
||||
// Misc.
|
||||
//
|
||||
|
||||
@@ -43,8 +43,11 @@
|
||||
#error "FAST_PWM_FAN is not yet implemented for this platform."
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SW_SERIAL) && HAS_TMC_SW_SERIAL
|
||||
#error "Missing SoftwareSerial implementation."
|
||||
// SoftwareSerial introduced in arduino core version 1.3.1
|
||||
#if ARDUINO_CORE_VERSION_INT < GET_VERSION_INT(1, 3, 1)
|
||||
#if !defined(HAVE_SW_SERIAL) && HAS_TMC_SW_SERIAL
|
||||
#error "Missing SoftwareSerial implementation."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA
|
||||
|
||||
@@ -109,7 +109,7 @@ bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) {
|
||||
WITH_RETRY(SDIO_READ_RETRIES, {
|
||||
en_result_t rc = SDCARD_ReadBlocks(handle, block, 1, dst, SDIO_READ_TIMEOUT);
|
||||
if (rc == Ok) return true;
|
||||
printf("SDIO_ReadBlock error (rc=%u; ErrorCode=%lu)\n", rc, handle->u32ErrorCode);
|
||||
printf("SDIO_ReadBlock error (rc=%u; ErrorCode=%" PRIu32 ")\n", rc, handle->u32ErrorCode);
|
||||
})
|
||||
|
||||
return false;
|
||||
@@ -122,7 +122,7 @@ bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) {
|
||||
WITH_RETRY(SDIO_WRITE_RETRIES, {
|
||||
en_result_t rc = SDCARD_WriteBlocks(handle, block, 1, (uint8_t *)src, SDIO_WRITE_TIMEOUT);
|
||||
if (rc == Ok) return true;
|
||||
printf("SDIO_WriteBlock error (rc=%u; ErrorCode=%lu)\n", rc, handle->u32ErrorCode);
|
||||
printf("SDIO_WriteBlock error (rc=%u; ErrorCode=%" PRIu32 ")\n", rc, handle->u32ErrorCode);
|
||||
})
|
||||
|
||||
return false;
|
||||
|
||||
@@ -204,7 +204,7 @@ void core_hook_sysclock_init() {
|
||||
power_mode_update_post(F_SYSTEM_CLOCK);
|
||||
|
||||
// Verify clocks match expected values (at runtime)
|
||||
#if ENABLED(MARLIN_DEV_MODE) || ENABLED(ALWAYS_VALIDATE_CLOCKS)
|
||||
#if ANY(MARLIN_DEV_MODE, ALWAYS_VALIDATE_CLOCKS)
|
||||
validate_system_clocks();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
//
|
||||
typedef Timer0 *timer_channel_t;
|
||||
typedef uint16_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFU
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX)
|
||||
|
||||
//
|
||||
// Timer instances
|
||||
@@ -69,9 +69,9 @@ extern Timer0 step_timer;
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // Integer 3
|
||||
|
||||
// Pulse timer (== stepper timer)
|
||||
#define MF_TIMER_PULSE MF_TIMER_STEP
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define MF_TIMER_PULSE MF_TIMER_STEP
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
//
|
||||
// HAL functions
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE ((SystemCoreClock) / 4) // frequency of timers peripherals
|
||||
|
||||
@@ -56,7 +56,6 @@ typedef uint32_t hal_timer_t;
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -40,10 +40,6 @@
|
||||
* SPI sharing pins. The SCK, MOSI & MISO pins can NOT be set/cleared with
|
||||
* WRITE nor digitalWrite when the hardware SPI module within the LPC17xx is
|
||||
* active. If any of these pins are shared then the software SPI must be used.
|
||||
*
|
||||
* A more sophisticated hardware SPI can be found at the following link.
|
||||
* This implementation has not been fully debugged.
|
||||
* https://github.com/MarlinFirmware/Marlin/tree/071c7a78f27078fd4aee9a3ef365fcf5e143531e
|
||||
*/
|
||||
|
||||
#ifdef TARGET_LPC1768
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/**
|
||||
* digipot_mcp4451_I2C_routines.c
|
||||
* Adapted from https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
* Adapted from https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
*/
|
||||
|
||||
#ifdef TARGET_LPC1768
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* digipot_mcp4451_I2C_routines.h
|
||||
* Adapted from https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
* Adapted from https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
#define _HAL_TIMER_ISR(T) __HAL_TIMER_ISR(T)
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE ((F_CPU) / 4) // (Hz) Frequency of timers peripherals
|
||||
|
||||
@@ -77,12 +77,11 @@ typedef uint32_t hal_timer_t;
|
||||
#define TEMP_TIMER_RATE 1000000 // 1MHz
|
||||
#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR frequency
|
||||
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
// adapted from I2C/master/master.c example
|
||||
// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
// https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
|
||||
#ifdef TARGET_LPC1768
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ if pioutil.is_pio_build():
|
||||
from ctypes import windll
|
||||
from pathlib import PureWindowsPath
|
||||
|
||||
# getting list of drives
|
||||
# https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python
|
||||
# Getting a list of drives
|
||||
# https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-windows-drives
|
||||
drives = []
|
||||
bitmask = windll.kernel32.GetLogicalDrives()
|
||||
for letter in string.ascii_uppercase:
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint64_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFF'FFFF'FFFF'FFFFULL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT64_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE ((SystemCoreClock) / 4) // frequency of timers peripherals
|
||||
|
||||
@@ -55,12 +55,11 @@ typedef uint64_t hal_timer_t;
|
||||
#define TEMP_TIMER_RATE 1'000'000 // (Hz) Temperature Timer count rate
|
||||
#define TEMP_TIMER_FREQUENCY 1000 // (Hz) Temperature ISR call frequency
|
||||
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1'000'000) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // (Hz) Frequency of Stepper Timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1'000'000) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
// adapted from I2C/master/master.c example
|
||||
// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
// https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
|
||||
#ifdef __PLAT_NATIVE_SIM__
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
#include "../shared/Delay.h"
|
||||
#include "../../module/temperature.h" // For OVERSAMPLENR
|
||||
|
||||
extern "C" {
|
||||
#include "pico/bootrom.h"
|
||||
@@ -41,50 +42,38 @@ extern "C" {
|
||||
#include "msc_sd.h"
|
||||
#endif
|
||||
|
||||
// Core 1 watchdog configuration
|
||||
#define CORE1_MAX_RESETS 5 // Maximum number of Core 1 resets before halting system
|
||||
|
||||
// ------------------------
|
||||
// Public Variables
|
||||
// ------------------------
|
||||
|
||||
volatile uint32_t adc_accumulators[5] = {0}; // Accumulators for oversampling (sum of readings)
|
||||
volatile uint8_t adc_counts[5] = {0}; // Count of readings accumulated per channel
|
||||
volatile uint16_t adc_values[5] = {512, 512, 512, 512, 512}; // Final oversampled ADC values (averages) - initialized to mid-range
|
||||
volatile uint16_t adc_values[5] = {4095, 4095, 4095, 4095, 4095}; // Averaged ADC values (single reading equivalent) - initialized to max (open circuit)
|
||||
|
||||
// Core 1 watchdog monitoring
|
||||
// Core monitoring for watchdog
|
||||
volatile uint32_t core0_last_heartbeat = 0; // Timestamp of Core 0's last activity
|
||||
volatile uint32_t core1_last_heartbeat = 0; // Timestamp of Core 1's last activity
|
||||
volatile bool core1_watchdog_triggered = false; // Flag to indicate Core 1 reset
|
||||
volatile uint8_t core1_reset_count = 0; // Count of Core 1 resets - halt system if >= CORE1_MAX_RESETS
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
volatile bool core1_freeze_test = false; // Flag to freeze Core 1 for watchdog testing
|
||||
#endif
|
||||
volatile uint8_t current_pin;
|
||||
volatile bool MarlinHAL::adc_has_result;
|
||||
volatile uint8_t adc_channels_enabled[5] = {false}; // Track which ADC channels are enabled
|
||||
|
||||
// Helper function for LED blinking patterns
|
||||
void blink_led_pattern(uint8_t blink_count, uint32_t blink_duration_us = 100000) {
|
||||
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
|
||||
for (uint8_t i = 0; i < blink_count; i++) {
|
||||
WRITE(LED_PIN, HIGH);
|
||||
busy_wait_us(blink_duration_us);
|
||||
WRITE(LED_PIN, LOW);
|
||||
if (i < blink_count - 1) { // Don't delay after the last blink
|
||||
busy_wait_us(blink_duration_us);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Core 1 ADC reading task - dynamically reads all enabled channels with oversampling
|
||||
void core1_adc_task() {
|
||||
static uint32_t last_led_toggle = 0;
|
||||
const uint8_t OVERSAMPLENR = 16; // Standard Marlin oversampling count
|
||||
|
||||
// Signal successful Core 1 startup/restart
|
||||
SERIAL_ECHO_MSG("Core 1 ADC task started");
|
||||
static uint32_t last_temp_update = 0;
|
||||
|
||||
while (true) {
|
||||
// Update heartbeat timestamp at start of each scan cycle
|
||||
core1_last_heartbeat = time_us_32();
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
// Check if we should freeze for watchdog test
|
||||
if (core1_freeze_test) {
|
||||
// Stop updating heartbeat and spin forever
|
||||
while (core1_freeze_test) {
|
||||
busy_wait_us(100000); // 100ms delay
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Scan all enabled ADC channels
|
||||
for (uint8_t channel = 0; channel < 5; channel++) {
|
||||
@@ -114,11 +103,9 @@ void core1_adc_task() {
|
||||
adc_accumulators[channel] += reading;
|
||||
adc_counts[channel]++;
|
||||
|
||||
// Update the averaged value with current accumulation (provides immediate valid data)
|
||||
adc_values[channel] = adc_accumulators[channel] / adc_counts[channel];
|
||||
|
||||
// When we reach the full oversampling count, reset accumulator for next cycle
|
||||
// When we reach the full oversampling count, calculate averaged value (Marlin ISR does its own oversampling)
|
||||
if (adc_counts[channel] >= OVERSAMPLENR) {
|
||||
adc_values[channel] = adc_accumulators[channel] / OVERSAMPLENR; // Return single-reading equivalent
|
||||
adc_accumulators[channel] = 0;
|
||||
adc_counts[channel] = 0;
|
||||
}
|
||||
@@ -129,17 +116,19 @@ void core1_adc_task() {
|
||||
}
|
||||
}
|
||||
|
||||
// Core 1 LED indicator: Double blink every 2 seconds to show Core 1 is active
|
||||
// Core 1 just provides ADC readings - don't trigger temperature updates from here
|
||||
// Let Marlin's main temperature ISR on Core 0 handle the timing and updates
|
||||
uint32_t now = time_us_32();
|
||||
if (now - last_led_toggle >= 2000000) { // 2 seconds
|
||||
last_led_toggle = now;
|
||||
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
|
||||
// Triple blink pattern if watchdog was triggered (shows Core 1 was reset)
|
||||
if (core1_watchdog_triggered) {
|
||||
core1_watchdog_triggered = false; // Clear flag
|
||||
blink_led_pattern(3); // Triple blink for watchdog reset
|
||||
} else {
|
||||
blink_led_pattern(2); // Normal double blink
|
||||
if (now - last_temp_update >= 100000) { // 100ms = 100000 microseconds
|
||||
last_temp_update = now;
|
||||
#if ENABLED(USE_WATCHDOG)
|
||||
// Refresh watchdog here like AVR ISR does indirectly via temperature updates
|
||||
// Use 2 second delay to allow watchdog_init to be called during boot
|
||||
static uint32_t core1_start_time = 0;
|
||||
if (core1_start_time == 0) core1_start_time = time_us_32();
|
||||
|
||||
if (time_us_32() - core1_start_time > 2000000) {
|
||||
hal.watchdog_refresh(1); // Refresh from Core 1
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -219,37 +208,42 @@ void MarlinHAL::reboot() { watchdog_reboot(0, 0, 1); }
|
||||
void MarlinHAL::watchdog_init() {
|
||||
#if DISABLED(DISABLE_WATCHDOG_INIT)
|
||||
static_assert(WDT_TIMEOUT_US > 1000, "WDT Timeout is too small, aborting");
|
||||
// Initialize Core 0 heartbeat
|
||||
core0_last_heartbeat = time_us_32();
|
||||
watchdog_enable(WDT_TIMEOUT_US/1000, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MarlinHAL::watchdog_refresh() {
|
||||
// If Core 1 has reset CORE1_MAX_RESETS+ times, stop updating watchdog to halt system
|
||||
if (core1_reset_count >= CORE1_MAX_RESETS) {
|
||||
SERIAL_ECHO_MSG("Core 1 reset limit exceeded (", core1_reset_count, " resets) - halting system for safety");
|
||||
return; // Don't update watchdog - system will halt
|
||||
void MarlinHAL::watchdog_refresh(const uint8_t core/*=0*/) {
|
||||
if (core == 0) {
|
||||
// Update Core 0 heartbeat
|
||||
core0_last_heartbeat = time_us_32();
|
||||
|
||||
// Check if Core 1 is alive (2 second timeout)
|
||||
if (time_us_32() - core1_last_heartbeat < 2000000) {
|
||||
watchdog_update(); // Only refresh if Core 1 is responding
|
||||
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
|
||||
TOGGLE(LED_PIN); // Heartbeat indicator
|
||||
#endif
|
||||
}
|
||||
// If Core 1 is stuck, don't refresh - let watchdog reset the system
|
||||
}
|
||||
else {
|
||||
// Update Core 1 heartbeat
|
||||
core1_last_heartbeat = time_us_32();
|
||||
|
||||
watchdog_update();
|
||||
|
||||
// Check Core 1 watchdog (15 second timeout)
|
||||
uint32_t now = time_us_32();
|
||||
if (now - core1_last_heartbeat > 15000000) { // 15 seconds
|
||||
// Core 1 appears stuck - reset it
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_adc_task);
|
||||
core1_watchdog_triggered = true; // Signal for LED indicator
|
||||
core1_reset_count++; // Increment reset counter
|
||||
SERIAL_ECHO_MSG("Core 1 ADC watchdog triggered - resetting Core 1 (attempt ", core1_reset_count, ")");
|
||||
// Check if Core 0 is alive (2 second timeout)
|
||||
if (time_us_32() - core0_last_heartbeat < 2000000) {
|
||||
watchdog_update(); // Only refresh if Core 0 is responding
|
||||
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
|
||||
TOGGLE(LED_PIN); // Heartbeat indicator
|
||||
#endif
|
||||
}
|
||||
// If Core 0 is stuck, don't refresh - let watchdog reset the system
|
||||
}
|
||||
|
||||
#if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
|
||||
// Core 0 LED indicator: Single toggle every watchdog refresh (shows Core 0 activity)
|
||||
TOGGLE(LED_PIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // USE_WATCHDOG
|
||||
|
||||
// ------------------------
|
||||
// ADC
|
||||
@@ -290,13 +284,15 @@ void flashFirmware(const int16_t) { hal.reboot(); }
|
||||
|
||||
extern "C" {
|
||||
void * _sbrk(int incr);
|
||||
extern unsigned int __bss_end__; // end of bss section
|
||||
extern unsigned int __StackLimit; // Lowest address the stack can grow to
|
||||
}
|
||||
|
||||
// Return free memory between end of heap (or end bss) and whatever is current
|
||||
// Return free memory between end of heap and start of stack
|
||||
int freeMemory() {
|
||||
int free_memory, heap_end = (int)_sbrk(0);
|
||||
return (int)&free_memory - (heap_end ?: (int)&__bss_end__);
|
||||
void* heap_end = _sbrk(0);
|
||||
// Use the linker-provided stack limit instead of a local variable
|
||||
// __StackLimit is the lowest address the stack can grow to
|
||||
return (char*)&__StackLimit - (char*)heap_end;
|
||||
}
|
||||
|
||||
#endif // __PLAT_RP2040__
|
||||
|
||||
@@ -51,6 +51,28 @@
|
||||
|
||||
#include "MarlinSerial.h"
|
||||
|
||||
#if !WITHIN(SERIAL_PORT, -1, 1)
|
||||
#error "SERIAL_PORT must be from -1 to 1."
|
||||
#endif
|
||||
|
||||
#ifdef SERIAL_PORT_2
|
||||
#if !WITHIN(SERIAL_PORT_2, -1, 1)
|
||||
#error "SERIAL_PORT_2 must be from -1 to 1."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SERIAL_PORT_3
|
||||
#if !WITHIN(SERIAL_PORT_3, -1, 1)
|
||||
#error "SERIAL_PORT_3 must be from -1 to 1."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LCD_SERIAL_PORT
|
||||
#if !WITHIN(LCD_SERIAL_PORT, -1, 1)
|
||||
#error "LCD_SERIAL_PORT must be from -1 to 1."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ------------------------
|
||||
// Defines
|
||||
// ------------------------
|
||||
@@ -131,7 +153,7 @@ public:
|
||||
|
||||
// Watchdog
|
||||
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
|
||||
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});
|
||||
static void watchdog_refresh(const uint8_t=0) IF_DISABLED(USE_WATCHDOG, {});
|
||||
|
||||
static void init(); // Called early in setup()
|
||||
static void init_board() {} // Called less early in setup()
|
||||
|
||||
@@ -44,15 +44,15 @@ static void TXBegin() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void TX(char b){
|
||||
#if SERIAL_PORT == -1
|
||||
USBSerial
|
||||
#elif SERIAL_PORT == 0
|
||||
USBSerial
|
||||
#elif SERIAL_PORT == 1
|
||||
Serial1
|
||||
#endif
|
||||
.write(b);
|
||||
static void TX(char b) {
|
||||
#if SERIAL_PORT == -1
|
||||
USBSerial
|
||||
#elif SERIAL_PORT == 0
|
||||
USBSerial
|
||||
#elif SERIAL_PORT == 1
|
||||
Serial1
|
||||
#endif
|
||||
.write(b);
|
||||
}
|
||||
|
||||
// A SW memory barrier, to ensure GCC does not overoptimize loops
|
||||
|
||||
@@ -30,10 +30,40 @@
|
||||
#include "../../feature/e_parser.h"
|
||||
#endif
|
||||
|
||||
#define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X)
|
||||
#define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X)
|
||||
#if WITHIN(SERIAL_PORT, 0, 3)
|
||||
IMPLEMENT_SERIAL(SERIAL_PORT);
|
||||
#include <HardwareSerial.h>
|
||||
|
||||
// Marlin uses: -1=USB, 0=UART0, 1=UART1
|
||||
// Arduino uses: Serial=USB, Serial1=UART0, Serial2=UART1
|
||||
//
|
||||
// To remap Arduino's numbering to Marlin's convention, we create MarlinSerial0/MarlinSerial1
|
||||
// as new UART instances with custom pins.
|
||||
//
|
||||
// We use distinct names (MarlinSerial0/MarlinSerial1) to avoid symbol conflicts with
|
||||
// the Arduino framework's pre-defined Serial1/Serial2 objects, which use the same
|
||||
// underlying hardware (_UART0_ and _UART1_).
|
||||
|
||||
// Create Serial0 as UART0 with custom or default pins
|
||||
arduino::UART MarlinSerial0(
|
||||
#if PINS_EXIST(SERIAL0_TX, SERIAL0_RX)
|
||||
SERIAL0_TX_PIN, SERIAL0_RX_PIN // Custom pins for UART0 (Marlin Serial0)
|
||||
#else
|
||||
0, 1 // Default UART0 pins (GP0/GP1)
|
||||
#endif
|
||||
);
|
||||
|
||||
// Not using PINS_EXIST(SERIAL1_TX, SERIAL1_RX) because SERIAL1_TX and SERIAL1_RX
|
||||
// are defined in framework-arduino-mbed/variants/RASPBERRY_PI_PICO/pins_arduino.h
|
||||
|
||||
// Create Serial1 as UART1 with custom or default pins
|
||||
#if defined(SERIAL1_TX_PIN) && defined(SERIAL1_RX_PIN)
|
||||
arduino::UART MarlinSerial1(SERIAL1_TX_PIN, SERIAL1_RX_PIN); // Custom pins for UART1 (Marlin Serial1)
|
||||
#endif
|
||||
|
||||
// Wrap the serial ports for Marlin
|
||||
DefaultSerial0 MSerial0(false, MarlinSerial0); // Marlin Serial0 = UART0
|
||||
#if defined(SERIAL1_TX_PIN) && defined(SERIAL1_RX_PIN)
|
||||
DefaultSerial1 MSerial1(false, MarlinSerial1); // Marlin Serial1 = UART1
|
||||
#endif
|
||||
DefaultSerial2 MSerial2(false, Serial); // Marlin Serial2 = USB (-1)
|
||||
|
||||
#endif // __PLAT_RP2040__
|
||||
|
||||
@@ -29,20 +29,50 @@
|
||||
|
||||
#include "../../core/serial_hook.h"
|
||||
|
||||
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
|
||||
extern DefaultSerial1 MSerial0;
|
||||
/**
|
||||
* Serial Port Configuration for RP2040 (Raspberry Pi Pico)
|
||||
*
|
||||
* Arduino-Pico Core Serial Objects:
|
||||
* - Serial: USB Serial (CDC ACM)
|
||||
* - Serial1: Hardware UART0
|
||||
* - Serial2: Hardware UART1
|
||||
* - SerialUSB: Alias for Serial (USB)
|
||||
*
|
||||
* Marlin Serial Wrappers:
|
||||
* - MSerial0: Wrapper for MarlinSerial0 (UART0), used as Serial0
|
||||
* - MSerial1: Wrapper for MarlinSerial1 (UART1), declared dynamically if used
|
||||
* - MSerial2: Wrapper for Serial (USB)
|
||||
* - USBSerial: Wrapper for SerialUSB (USB)
|
||||
*
|
||||
* How it all joins together:
|
||||
* - Configuration defines SERIAL_PORT, SERIAL_PORT_2, etc. (-1 to 1 range)
|
||||
* - shared/serial_ports.h maps these to MYSERIAL1, MYSERIAL2, etc.
|
||||
* - MYSERIAL1 uses MSerialX based on the port index
|
||||
* - USB ports (-1) use USB_SERIAL_PORT (MSerial2)
|
||||
*/
|
||||
|
||||
// Forward declare our custom Serial objects (defined in MarlinSerial.cpp)
|
||||
namespace arduino { class UART; }
|
||||
extern arduino::UART MarlinSerial0; // Always declared
|
||||
extern arduino::UART MarlinSerial1; // Custom Marlin Serial1 to avoid conflict
|
||||
|
||||
typedef ForwardSerial1Class< decltype(MarlinSerial0) > DefaultSerial0;
|
||||
extern DefaultSerial0 MSerial0;
|
||||
typedef ForwardSerial1Class< decltype(MarlinSerial1) > DefaultSerial1;
|
||||
extern DefaultSerial1 MSerial1;
|
||||
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial2;
|
||||
extern DefaultSerial2 MSerial2;
|
||||
typedef ForwardSerial1Class<decltype(SerialUSB)> USBSerialType;
|
||||
extern USBSerialType USBSerial;
|
||||
|
||||
#define Serial0 Serial
|
||||
#define _DECLARE_SERIAL(X) \
|
||||
typedef ForwardSerial1Class<decltype(Serial##X)> DefaultSerial##X; \
|
||||
typedef ForwardSerial1Class<decltype(MarlinSerial##X)> DefaultSerial##X; \
|
||||
extern DefaultSerial##X MSerial##X
|
||||
#define DECLARE_SERIAL(X) _DECLARE_SERIAL(X)
|
||||
|
||||
#define SERIAL_INDEX_MIN 0
|
||||
#define SERIAL_INDEX_MAX 6
|
||||
#define USB_SERIAL_PORT(...) MSerial0
|
||||
#define SERIAL_INDEX_MAX 1
|
||||
#define USB_SERIAL_PORT(...) MSerial2
|
||||
#include "../shared/serial_ports.h"
|
||||
|
||||
#if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI)
|
||||
|
||||
@@ -137,7 +137,7 @@ int8_t digital_pin_to_analog_pin(pin_t pin) {
|
||||
}
|
||||
|
||||
bool isAnalogPin(const pin_t pin) {
|
||||
return digital_pin_to_analog_pin(pin) != -1;
|
||||
return digital_pin_to_analog_pin(pin) >= 0;
|
||||
}
|
||||
|
||||
#define digitalRead_mod(A) extDigitalRead(A) // must use Arduino pin numbers when doing reads
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#define _HAL_TIMER_ISR(T) __HAL_TIMER_ISR(T)
|
||||
|
||||
typedef uint64_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFF'FFFF'FFFF'FFFFULL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT64_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE (1'000'000ULL) // fixed value as we use a microsecond timesource
|
||||
#ifndef MF_TIMER_STEP
|
||||
@@ -65,7 +65,6 @@ typedef uint64_t hal_timer_t;
|
||||
#define STEPPER_TIMER_PRESCALE (10)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
@@ -129,16 +128,16 @@ FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, hal_time
|
||||
|
||||
switch (timer_num) {
|
||||
case 0:
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_0, compare, HAL_timer_alarm_pool_0_callback, 0, false);
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_0, compare, HAL_timer_alarm_pool_0_callback, 0, true);
|
||||
break;
|
||||
case 1:
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_1, compare, HAL_timer_alarm_pool_1_callback, 0, false);
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_1, compare, HAL_timer_alarm_pool_1_callback, 0, true);
|
||||
break;
|
||||
case 2:
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_2, compare, HAL_timer_alarm_pool_2_callback, 0, false);
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_2, compare, HAL_timer_alarm_pool_2_callback, 0, true);
|
||||
break;
|
||||
case 3:
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_3, compare, HAL_timer_alarm_pool_3_callback, 0, false);
|
||||
alarm_pool_add_alarm_in_us(HAL_timer_pool_3, compare, HAL_timer_alarm_pool_3_callback, 0, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
* On SAMD21, all pins support external interrupt capability.
|
||||
* Any pin can be used for external interrupts, but there are some restrictions.
|
||||
* At most 16 different external interrupts can be used at one time.
|
||||
* Further, you can’t just pick any 16 pins to use. This is because every pin on the SAMD21
|
||||
* Further, you can't just pick any 16 pins to use. This is because every pin on the SAMD21
|
||||
* connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external
|
||||
* interrupts at a time
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#define getPinByIndex(x) pin_array[x].pin
|
||||
#define getPinIsDigitalByIndex(x) pin_array[x].is_digital
|
||||
#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL))
|
||||
#define isAnalogPin(P) (digitalPinToAnalogIndex(P) != -1)
|
||||
#define isAnalogPin(P) (digitalPinToAnalogIndex(P) >= 0)
|
||||
#define pwm_status(P) digitalPinHasPWM(P)
|
||||
#define MULTI_NAME_PAD 27 // space needed to be pretty if not first name assigned to a pin
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals
|
||||
|
||||
@@ -56,7 +56,6 @@ typedef uint32_t hal_timer_t;
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
@@ -143,9 +142,8 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
|
||||
Rtc * const rtc = timer_config[timer_num].pRtc;
|
||||
// Clear interrupt flag
|
||||
rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0| RTC_MODE0_INTFLAG_OVF;
|
||||
|
||||
}
|
||||
else if (timer_config[timer_num].type == TimerType::tcc){
|
||||
else if (timer_config[timer_num].type == TimerType::tcc) {
|
||||
Tcc * const tc = timer_config[timer_num].pTcc;
|
||||
// Clear interrupt flag
|
||||
tc->INTFLAG.reg = TCC_INTFLAG_OVF;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician)
|
||||
*/
|
||||
// adapted from I2C/master/master.c example
|
||||
// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
// https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html
|
||||
|
||||
#ifdef __SAMD21__
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* On SAMD51, all pins support external interrupt capability.
|
||||
* Any pin can be used for external interrupts, but there are some restrictions.
|
||||
* At most 16 different external interrupts can be used at one time.
|
||||
* Further, you can’t just pick any 16 pins to use. This is because every pin on the SAMD51
|
||||
* Further, you can't just pick any 16 pins to use. This is because every pin on the SAMD51
|
||||
* connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external
|
||||
* interrupts at a time
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#define getPinByIndex(x) pin_array[x].pin
|
||||
#define getPinIsDigitalByIndex(x) pin_array[x].is_digital
|
||||
#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL))
|
||||
#define isAnalogPin(P) (digitalPinToAnalogIndex(P) != -1)
|
||||
#define isAnalogPin(P) (digitalPinToAnalogIndex(P) >= 0)
|
||||
#define pwm_status(P) digitalPinHasPWM(P)
|
||||
#define MULTI_NAME_PAD 27 // space needed to be pretty if not first name assigned to a pin
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals
|
||||
|
||||
@@ -55,7 +55,6 @@ typedef uint32_t hal_timer_t;
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -63,8 +63,6 @@
|
||||
// Types
|
||||
// ------------------------
|
||||
|
||||
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
|
||||
|
||||
typedef int32_t pin_t; // Parity with platform/ststm32
|
||||
|
||||
class libServo;
|
||||
|
||||
@@ -39,12 +39,16 @@ static void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb, u
|
||||
|
||||
void MarlinSPI::setClockDivider(uint8_t _div) {
|
||||
_speed = spi_getClkFreq(&_spi);// / _div;
|
||||
_clockDivider = _div;
|
||||
if (_clockDivider != _div) {
|
||||
_clockDivider = _div;
|
||||
_mustInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MarlinSPI::begin(void) {
|
||||
//TODO: only call spi_init if any parameter changed!!
|
||||
if (!_mustInit) return;
|
||||
spi_init(&_spi, _speed, _dataMode, _bitOrder, _dataSize);
|
||||
_mustInit = false;
|
||||
}
|
||||
|
||||
void MarlinSPI::setupDma(SPI_HandleTypeDef &_spiHandle, DMA_HandleTypeDef &_dmaHandle, uint32_t direction, bool minc) {
|
||||
|
||||
@@ -76,15 +76,23 @@ public:
|
||||
/* These methods are deprecated and kept for compatibility.
|
||||
* Use SPISettings with SPI.beginTransaction() to configure SPI parameters.
|
||||
*/
|
||||
void setBitOrder(BitOrder _order) { _bitOrder = _order; }
|
||||
void setBitOrder(BitOrder order) {
|
||||
if (_bitOrder == order) return;
|
||||
_bitOrder = order;
|
||||
_mustInit = true;
|
||||
}
|
||||
|
||||
void setDataMode(uint8_t _mode) {
|
||||
switch (_mode) {
|
||||
void setDataMode(uint8_t mode) {
|
||||
auto previous_mode = _dataMode;
|
||||
switch (mode) {
|
||||
case SPI_MODE0: _dataMode = SPI_MODE_0; break;
|
||||
case SPI_MODE1: _dataMode = SPI_MODE_1; break;
|
||||
case SPI_MODE2: _dataMode = SPI_MODE_2; break;
|
||||
case SPI_MODE3: _dataMode = SPI_MODE_3; break;
|
||||
default: return;
|
||||
}
|
||||
if (previous_mode != _dataMode)
|
||||
_mustInit = true;
|
||||
}
|
||||
|
||||
void setClockDivider(uint8_t _div);
|
||||
@@ -104,4 +112,5 @@ private:
|
||||
pin_t _misoPin;
|
||||
pin_t _sckPin;
|
||||
pin_t _ssPin;
|
||||
bool _mustInit = true;
|
||||
};
|
||||
|
||||
@@ -88,9 +88,9 @@ void USBHost::setUsbTaskState(uint8_t state) {
|
||||
capacity = info.capacity.block_nbr / 2000;
|
||||
block_size = info.capacity.block_size;
|
||||
block_count = info.capacity.block_nbr;
|
||||
//SERIAL_ECHOLNPGM("info.capacity.block_nbr : %ld\n", info.capacity.block_nbr);
|
||||
//SERIAL_ECHOLNPGM("info.capacity.block_size: %d\n", info.capacity.block_size);
|
||||
//SERIAL_ECHOLNPGM("capacity : %d MB\n", capacity);
|
||||
//SERIAL_ECHOLNPGM("info.capacity.block_nbr : ", info.capacity.block_nbr);
|
||||
//SERIAL_ECHOLNPGM("info.capacity.block_size: ", info.capacity.block_size);
|
||||
//SERIAL_ECHOLNPGM("capacity : ", capacity, "MB");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -81,10 +81,6 @@
|
||||
#define MCU_TEMP_TIMER 14 // TIM7 is consumed by Software Serial if used.
|
||||
#endif
|
||||
|
||||
#ifndef HAL_TIMER_RATE
|
||||
#define HAL_TIMER_RATE GetStepperTimerClkFreq()
|
||||
#endif
|
||||
|
||||
#ifndef STEP_TIMER
|
||||
#define STEP_TIMER MCU_STEP_TIMER
|
||||
#endif
|
||||
@@ -141,7 +137,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
||||
*/
|
||||
|
||||
timer_instance[timer_num]->setPrescaleFactor(STEPPER_TIMER_PRESCALE); //the -1 is done internally
|
||||
timer_instance[timer_num]->setOverflow(_MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE) /* /frequency */), TICK_FORMAT);
|
||||
timer_instance[timer_num]->setOverflow(_MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE) /* / frequency */)), TICK_FORMAT);
|
||||
break;
|
||||
case MF_TIMER_TEMP: // TEMP TIMER - any available 16bit timer
|
||||
timer_instance[timer_num] = new HardwareTimer(TEMP_TIMER_DEV);
|
||||
|
||||
@@ -48,16 +48,21 @@
|
||||
#define TIMER_INDEX_(T) TIMER##T##_INDEX // TIMER#_INDEX enums (timer_index_t) depend on TIM#_BASE defines.
|
||||
#define TIMER_INDEX(T) TIMER_INDEX_(T) // Convert Timer ID to HardwareTimer_Handle index.
|
||||
|
||||
#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() is expected to be called at around 1kHz
|
||||
#ifndef HAL_TIMER_RATE
|
||||
extern uint32_t GetStepperTimerClkFreq();
|
||||
#define HAL_TIMER_RATE GetStepperTimerClkFreq()
|
||||
#endif
|
||||
|
||||
// TODO: get rid of manual rate/prescale/ticks/cycles taken for procedures in stepper.cpp
|
||||
#define STEPPER_TIMER_RATE 2000000 // 2 Mhz
|
||||
extern uint32_t GetStepperTimerClkFreq();
|
||||
#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / (STEPPER_TIMER_RATE))
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
// Timer configuration constants
|
||||
#define STEPPER_TIMER_RATE 2000000
|
||||
#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() should run at ~1kHz
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
// Timer prescaler calculations
|
||||
#define STEPPER_TIMER_PRESCALE ((HAL_TIMER_RATE) / (STEPPER_TIMER_RATE))
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (ticks/μs) Stepper Timer ticks per µs
|
||||
|
||||
// Pulse Timer (counter) calculations
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* On STM32F, all pins support external interrupt capability.
|
||||
* Any pin can be used for external interrupts, but there are some restrictions.
|
||||
* At most 16 different external interrupts can be used at one time.
|
||||
* Further, you can’t just pick any 16 pins to use. This is because every pin on the STM32
|
||||
* Further, you can't just pick any 16 pins to use. This is because every pin on the STM32
|
||||
* connects to what is called an EXTI line, and only one pin per EXTI line can be used for external interrupts at a time
|
||||
* Check the Reference Manual of the MCU to confirm which line is used by each pin
|
||||
*/
|
||||
|
||||
@@ -84,7 +84,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
||||
timer_set_prescaler(STEP_TIMER_DEV, (uint16_t)(STEPPER_TIMER_PRESCALE - 1));
|
||||
timer_set_reload(STEP_TIMER_DEV, 0xFFFF);
|
||||
timer_oc_set_mode(STEP_TIMER_DEV, STEP_TIMER_CHAN, TIMER_OC_MODE_FROZEN, TIMER_OC_NO_PRELOAD); // no output pin change
|
||||
timer_set_compare(STEP_TIMER_DEV, STEP_TIMER_CHAN, _MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (STEPPER_TIMER_RATE) / frequency));
|
||||
timer_set_compare(STEP_TIMER_DEV, STEP_TIMER_CHAN, _MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((STEPPER_TIMER_RATE) / frequency)));
|
||||
timer_no_ARR_preload_ARPE(STEP_TIMER_DEV); // Need to be sure no preload on ARR register
|
||||
timer_attach_interrupt(STEP_TIMER_DEV, STEP_TIMER_CHAN, stepTC_Handler);
|
||||
HAL_timer_set_interrupt_priority(MF_TIMER_STEP, STEP_TIMER_IRQ_PRIO);
|
||||
@@ -97,7 +97,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
||||
timer_set_count(TEMP_TIMER_DEV, 0);
|
||||
timer_set_prescaler(TEMP_TIMER_DEV, (uint16_t)(TEMP_TIMER_PRESCALE - 1));
|
||||
timer_set_reload(TEMP_TIMER_DEV, 0xFFFF);
|
||||
timer_set_compare(TEMP_TIMER_DEV, TEMP_TIMER_CHAN, _MIN(hal_timer_t(HAL_TIMER_TYPE_MAX), (F_CPU) / (TEMP_TIMER_PRESCALE) / frequency));
|
||||
timer_set_compare(TEMP_TIMER_DEV, TEMP_TIMER_CHAN, _MIN(HAL_TIMER_TYPE_MAX, hal_timer_t((F_CPU) / (TEMP_TIMER_PRESCALE) / frequency)));
|
||||
timer_attach_interrupt(TEMP_TIMER_DEV, TEMP_TIMER_CHAN, tempTC_Handler);
|
||||
HAL_timer_set_interrupt_priority(MF_TIMER_TEMP, TEMP_TIMER_IRQ_PRIO);
|
||||
timer_generate_update(TEMP_TIMER_DEV);
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
*/
|
||||
|
||||
typedef uint16_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFU
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX)
|
||||
|
||||
#define HAL_TIMER_RATE uint32_t(F_CPU) // frequency of timers peripherals
|
||||
|
||||
@@ -103,7 +103,6 @@ typedef uint16_t hal_timer_t;
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
timer_dev* HAL_get_timer_dev(int number);
|
||||
|
||||
@@ -31,7 +31,5 @@ class libServo : public Servo {
|
||||
void move(const int value);
|
||||
private:
|
||||
typedef Servo super;
|
||||
uint16_t min_ticks;
|
||||
uint16_t max_ticks;
|
||||
uint8_t servoIndex; // index into the channel data for this servo
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define FTM0_TIMER_PRESCALE 8
|
||||
#define FTM1_TIMER_PRESCALE 4
|
||||
@@ -59,11 +59,10 @@ typedef uint32_t hal_timer_t;
|
||||
#define TEMP_TIMER_FREQUENCY 1000
|
||||
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -35,7 +35,5 @@ class libServo : public Servo {
|
||||
void move(const int value);
|
||||
private:
|
||||
typedef Servo super;
|
||||
uint16_t min_ticks;
|
||||
uint16_t max_ticks;
|
||||
uint8_t servoIndex; // Index into the channel data for this servo
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFFUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX)
|
||||
|
||||
#define FTM0_TIMER_PRESCALE 8
|
||||
#define FTM1_TIMER_PRESCALE 4
|
||||
@@ -59,11 +59,10 @@ typedef uint32_t hal_timer_t;
|
||||
#define TEMP_TIMER_FREQUENCY 1000
|
||||
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL)
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs
|
||||
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -37,7 +37,5 @@ class libServo : public PWMServo {
|
||||
private:
|
||||
typedef PWMServo super;
|
||||
uint8_t servoPin;
|
||||
uint16_t min_ticks;
|
||||
uint16_t max_ticks;
|
||||
uint8_t servoIndex; // Index into the channel data for this servo
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 4.0/4.1."
|
||||
#endif
|
||||
|
||||
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) || ENABLED(SERIAL_STATS_DROPPED_RX) || ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) || ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
|
||||
#if ANY(SERIAL_STATS_MAX_RX_QUEUED, SERIAL_STATS_DROPPED_RX, SERIAL_STATS_RX_FRAMING_ERRORS, SERIAL_STATS_RX_BUFFER_OVERRUNS)
|
||||
#error "SERIAL_STATS_* features not supported on Teensy 4.0/4.1."
|
||||
#endif
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef uint32_t hal_timer_t;
|
||||
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFEUL
|
||||
#define HAL_TIMER_TYPE_MAX hal_timer_t(UINT32_MAX-1UL)
|
||||
|
||||
#define GPT_TIMER_RATE (F_CPU / 4) // 150MHz (Can't use F_BUS_ACTUAL because it's extern volatile)
|
||||
|
||||
@@ -57,13 +57,12 @@ typedef uint32_t hal_timer_t;
|
||||
#define TEMP_TIMER_RATE 1000000
|
||||
#define TEMP_TIMER_FREQUENCY 1000
|
||||
|
||||
#define HAL_TIMER_RATE GPT1_TIMER_RATE
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL)
|
||||
#define STEPPER_TIMER_PRESCALE (GPT_TIMER_RATE / STEPPER_TIMER_RATE)
|
||||
#define HAL_TIMER_RATE GPT1_TIMER_RATE
|
||||
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
|
||||
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL)
|
||||
#define STEPPER_TIMER_PRESCALE (GPT_TIMER_RATE / STEPPER_TIMER_RATE)
|
||||
|
||||
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer
|
||||
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
|
||||
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
}
|
||||
else {
|
||||
// Enable DWT counter
|
||||
// From https://stackoverflow.com/a/41188674/1469714
|
||||
// From https://stackoverflow.com/questions/36378280/stm32-how-to-enable-dwt-cycle-counter/41188674#41188674
|
||||
HW_REG(_DEM_CR) = HW_REG(_DEM_CR) | 0x01000000; // Enable trace
|
||||
#if __CORTEX_M == 7
|
||||
HW_REG(_LAR) = 0xC5ACCE55; // Unlock access to DWT registers, see https://developer.arm.com/documentation/ihi0029/e/ section B2.3.10
|
||||
|
||||
@@ -66,7 +66,7 @@ void * hook_get_usagefault_vector_address(unsigned vtor) { return (void*)(vtor +
|
||||
void * hook_get_reserved_vector_address(unsigned vtor) { return (void*)(vtor + 0x07); }
|
||||
|
||||
// Common exception frame for ARM, should work for all ARM CPU
|
||||
// Described here (modified for convenience): https://interrupt.memfault.com/blog/cortex-m-fault-debug
|
||||
// Described here (modified for convenience): https://interrupt.memfault.com/blog/cortex-m-hardfault-debug
|
||||
struct __attribute__((packed)) ContextStateFrame {
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
|
||||
+51
-41
@@ -74,11 +74,11 @@
|
||||
#endif
|
||||
|
||||
#if HAS_DWIN_E3V2
|
||||
#include "lcd/e3v2/common/encoder.h"
|
||||
#include "lcd/dwin/common/encoder.h"
|
||||
#if ENABLED(DWIN_CREALITY_LCD)
|
||||
#include "lcd/e3v2/creality/dwin.h"
|
||||
#include "lcd/dwin/creality/dwin.h"
|
||||
#elif ENABLED(DWIN_CREALITY_LCD_JYERSUI)
|
||||
#include "lcd/e3v2/jyersui/dwin.h"
|
||||
#include "lcd/dwin/jyersui/dwin.h"
|
||||
#elif ENABLED(SOVOL_SV06_RTS)
|
||||
#include "lcd/sovol_rts/sovol_rts.h"
|
||||
#endif
|
||||
@@ -260,6 +260,10 @@
|
||||
#include "feature/rs485.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
#include "feature/e_parser.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Spin in place here while keeping temperature processing alive
|
||||
*/
|
||||
@@ -282,7 +286,7 @@ Marlin marlin;
|
||||
#endif
|
||||
|
||||
// Global state of the firmware
|
||||
MarlinState Marlin::state = MarlinState::MF_INITIALIZING;
|
||||
MarlinState Marlin::state = MF_INITIALIZING;
|
||||
|
||||
// For M109 and M190, this flag may be cleared (by M108) to exit the wait loop
|
||||
bool Marlin::wait_for_heatup = false;
|
||||
@@ -370,7 +374,7 @@ void Marlin::startOrResumeJob() {
|
||||
if (!printingIsPaused()) {
|
||||
TERN_(GCODE_REPEAT_MARKERS, repeat.reset());
|
||||
TERN_(CANCEL_OBJECTS, cancelable.reset());
|
||||
TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator = 0);
|
||||
TERN_(LCD_SHOW_E_TOTAL, motion.e_move_accumulator = 0);
|
||||
TERN_(SET_REMAINING_TIME, ui.reset_remaining_time());
|
||||
TERN_(HAS_PRUSA_MMU3, MMU3::operation_statistics.reset_per_print_stats());
|
||||
}
|
||||
@@ -384,7 +388,7 @@ void Marlin::startOrResumeJob() {
|
||||
card.abortFilePrintNow(TERN_(SD_RESORT, true));
|
||||
|
||||
queue.clear();
|
||||
quickstop_stepper();
|
||||
motion.quickstop_stepper();
|
||||
|
||||
print_job_timer.abort();
|
||||
|
||||
@@ -404,8 +408,8 @@ void Marlin::startOrResumeJob() {
|
||||
}
|
||||
|
||||
inline void finishSDPrinting() {
|
||||
if (queue.enqueue_one(F("M1001"))) { // Keep trying until it gets queued
|
||||
marlin.setState(MarlinState::MF_RUNNING); // Signal to stop trying
|
||||
if (queue.enqueue_one(F("M1001"))) { // Keep trying until it gets queued
|
||||
marlin.setState(MF_RUNNING); // Signal to stop trying
|
||||
TERN_(PASSWORD_AFTER_SD_PRINT_END, password.lock_machine());
|
||||
TERN_(DGUS_LCD_UI_MKS, screen.sdPrintingFinished());
|
||||
}
|
||||
@@ -514,8 +518,14 @@ void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
stepper.frozen = READ(FREEZE_PIN) == FREEZE_STATE;
|
||||
// Handle the FREEZE button
|
||||
#if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD)
|
||||
stepper.set_frozen_triggered(
|
||||
TERN0(FREEZE_FEATURE, READ(FREEZE_PIN) == FREEZE_STATE)
|
||||
#if ALL(SOFT_FEED_HOLD, REALTIME_REPORTING_COMMANDS)
|
||||
|| realtime_ramping_pause_flag
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
#if HAS_HOME
|
||||
@@ -699,19 +709,19 @@ void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) {
|
||||
#endif
|
||||
|
||||
#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
|
||||
if (thermalManager.degHotend(active_extruder) > (EXTRUDER_RUNOUT_MINTEMP)
|
||||
if (thermalManager.degHotend(motion.extruder) > (EXTRUDER_RUNOUT_MINTEMP)
|
||||
&& ELAPSED(ms, gcode.previous_move_ms, SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS))
|
||||
&& !planner.has_blocks_queued()
|
||||
) {
|
||||
const int8_t e_stepper = TERN(HAS_SWITCHING_EXTRUDER, active_extruder >> 1, active_extruder);
|
||||
const int8_t e_stepper = TERN(HAS_SWITCHING_EXTRUDER, motion.extruder / 2, motion.extruder);
|
||||
const bool e_off = !stepper.AXIS_IS_ENABLED(E_AXIS, e_stepper);
|
||||
if (e_off) stepper.ENABLE_EXTRUDER(e_stepper);
|
||||
|
||||
const float olde = current_position.e;
|
||||
current_position.e += EXTRUDER_RUNOUT_EXTRUDE;
|
||||
line_to_current_position(MMM_TO_MMS(EXTRUDER_RUNOUT_SPEED));
|
||||
current_position.e = olde;
|
||||
planner.set_e_position_mm(olde);
|
||||
const float olde = motion.position.e;
|
||||
motion.position.e += EXTRUDER_RUNOUT_EXTRUDE;
|
||||
motion.goto_current_position(MMM_TO_MMS(EXTRUDER_RUNOUT_SPEED));
|
||||
motion.position.e = olde;
|
||||
motion.sync_plan_position_e();
|
||||
planner.synchronize();
|
||||
|
||||
if (e_off) stepper.DISABLE_EXTRUDER(e_stepper);
|
||||
@@ -722,11 +732,11 @@ void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) {
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
// handle delayed move timeout
|
||||
if (delayed_move_time && ELAPSED(ms, delayed_move_time) && isRunning()) {
|
||||
if (motion.delayed_move_time && ELAPSED(ms, motion.delayed_move_time) && isRunning()) {
|
||||
// travel moves have been received so enact them
|
||||
delayed_move_time = 0xFFFFFFFFUL; // force moves to be done
|
||||
destination = current_position;
|
||||
prepare_line_to_destination();
|
||||
motion.delayed_move_time = UINT32_MAX; // force moves to be done
|
||||
motion.destination = motion.position;
|
||||
motion.prepare_line_to_destination();
|
||||
planner.synchronize();
|
||||
}
|
||||
#endif
|
||||
@@ -803,10 +813,10 @@ void Marlin::idle(const bool no_stepper_sleep/*=false*/) {
|
||||
TERN_(MAX7219_DEBUG, max7219.idle_tasks());
|
||||
|
||||
// Return if setup() isn't completed
|
||||
if (state == MarlinState::MF_INITIALIZING) goto IDLE_DONE;
|
||||
if (is(MF_INITIALIZING)) goto IDLE_DONE;
|
||||
|
||||
// TODO: Still causing errors
|
||||
TERN_(TOOL_SENSOR, (void)check_tool_sensor_stats(active_extruder, true));
|
||||
TERN_(TOOL_SENSOR, (void)check_tool_sensor_stats(motion.extruder, true));
|
||||
|
||||
// Handle filament runout sensors
|
||||
#if HAS_FILAMENT_SENSOR
|
||||
@@ -843,6 +853,17 @@ void Marlin::idle(const bool no_stepper_sleep/*=false*/) {
|
||||
// Update the Beeper queue
|
||||
TERN_(HAS_BEEPER, buzzer.tick());
|
||||
|
||||
// Async Babystepping via the Emergency Parser
|
||||
#if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER)
|
||||
babystep.do_ep_steps();
|
||||
#endif
|
||||
|
||||
// Direct Stepping
|
||||
TERN_(DIRECT_STEPPING, page_manager.write_responses());
|
||||
|
||||
// Manage Fixed-time Motion Control
|
||||
TERN_(FT_MOTION, ftMotion.loop());
|
||||
|
||||
// Handle UI input / draw events
|
||||
#if ENABLED(SOVOL_SV06_RTS)
|
||||
RTS_Update();
|
||||
@@ -870,7 +891,7 @@ void Marlin::idle(const bool no_stepper_sleep/*=false*/) {
|
||||
TERN_(AUTO_REPORT_TEMPERATURES, thermalManager.auto_reporter.tick());
|
||||
TERN_(AUTO_REPORT_FANS, fan_check.auto_reporter.tick());
|
||||
TERN_(AUTO_REPORT_SD_STATUS, card.auto_reporter.tick());
|
||||
TERN_(AUTO_REPORT_POSITION, position_auto_reporter.tick());
|
||||
TERN_(AUTO_REPORT_POSITION, motion.position_auto_reporter.tick());
|
||||
TERN_(BUFFER_MONITORING, queue.auto_report_buffer_statistics());
|
||||
}
|
||||
#endif
|
||||
@@ -885,20 +906,9 @@ void Marlin::idle(const bool no_stepper_sleep/*=false*/) {
|
||||
// Handle Joystick jogging
|
||||
TERN_(POLL_JOG, joystick.inject_jog_moves());
|
||||
|
||||
// Async Babystepping via the Emergency Parser
|
||||
#if ALL(EP_BABYSTEPPING, EMERGENCY_PARSER)
|
||||
babystep.do_ep_steps();
|
||||
#endif
|
||||
|
||||
// Direct Stepping
|
||||
TERN_(DIRECT_STEPPING, page_manager.write_responses());
|
||||
|
||||
// Update the LVGL interface
|
||||
TERN_(HAS_TFT_LVGL_UI, LV_TASK_HANDLER());
|
||||
|
||||
// Manage Fixed-time Motion Control
|
||||
TERN_(FT_MOTION, ftMotion.loop());
|
||||
|
||||
IDLE_DONE:
|
||||
TERN_(MARLIN_DEV_MODE, idle_depth--);
|
||||
|
||||
@@ -996,7 +1006,7 @@ void Marlin::stop() {
|
||||
SERIAL_ERROR_MSG(STR_ERR_STOPPED);
|
||||
LCD_MESSAGE(MSG_STOPPED);
|
||||
safe_delay(350); // Allow enough time for messages to get out before stopping
|
||||
state = MarlinState::MF_STOPPED;
|
||||
setState(MF_STOPPED);
|
||||
}
|
||||
} // Marlin::stop()
|
||||
|
||||
@@ -1221,7 +1231,7 @@ void setup() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
#if ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN)
|
||||
SETUP_LOG("FREEZE_PIN");
|
||||
#if FREEZE_STATE
|
||||
SET_INPUT_PULLDOWN(FREEZE_PIN);
|
||||
@@ -1401,9 +1411,9 @@ void setup() {
|
||||
SETUP_RUN(touchBt.init());
|
||||
#endif
|
||||
|
||||
TERN_(HAS_HOME_OFFSET, current_position += home_offset); // Init current position based on home_offset
|
||||
TERN_(HAS_HOME_OFFSET, motion.position += motion.home_offset); // Init current position based on home_offset
|
||||
|
||||
sync_plan_position(); // Vital to init stepper/planner equivalent for current_position
|
||||
motion.sync_plan_position(); // Vital to init stepper/planner equivalent for motion.position
|
||||
|
||||
SETUP_RUN(thermalManager.init()); // Initialize temperature loop
|
||||
|
||||
@@ -1709,7 +1719,7 @@ void setup() {
|
||||
SETUP_RUN(ftMotion.init());
|
||||
#endif
|
||||
|
||||
marlin.setState(MarlinState::MF_RUNNING);
|
||||
marlin.setState(MF_RUNNING);
|
||||
|
||||
#ifdef STARTUP_TUNE
|
||||
// Play a short startup tune before continuing.
|
||||
@@ -1741,7 +1751,7 @@ void loop() {
|
||||
|
||||
#if HAS_MEDIA
|
||||
if (card.flag.abort_sd_printing) abortSDPrinting();
|
||||
if (marlin.is(MarlinState::MF_SD_COMPLETE)) finishSDPrinting();
|
||||
if (marlin.is(MF_SD_COMPLETE)) finishSDPrinting();
|
||||
#endif
|
||||
|
||||
queue.advance();
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
// Global State of the firmware
|
||||
enum class MarlinState : uint8_t {
|
||||
enum MarlinState : uint8_t {
|
||||
MF_INITIALIZING = 0,
|
||||
MF_STOPPED,
|
||||
MF_KILLED,
|
||||
@@ -54,8 +54,8 @@ public:
|
||||
static MarlinState state;
|
||||
static void setState(const MarlinState s) { state = s; }
|
||||
static bool is(const MarlinState s) { return state == s; }
|
||||
static bool isStopped() { return is(MarlinState::MF_STOPPED); }
|
||||
static bool isRunning() { return state >= MarlinState::MF_RUNNING; }
|
||||
static bool isStopped() { return is(MF_STOPPED); }
|
||||
static bool isRunning() { return state >= MF_RUNNING; }
|
||||
|
||||
static bool printingIsActive();
|
||||
static bool printJobOngoing();
|
||||
|
||||
+13
-10
@@ -187,6 +187,7 @@
|
||||
#define BOARD_MALYAN_M180 1333 // Malyan M180 Mainboard Version 2 (no display function, direct G-code only)
|
||||
#define BOARD_PROTONEER_CNC_SHIELD_V3 1334 // Mega controller & Protoneer CNC Shield V3.00
|
||||
#define BOARD_WEEDO_62A 1335 // WEEDO 62A board (TINA2, Monoprice Cadet, etc.)
|
||||
#define BOARD_MIGHTYBOARD_REVG 1336 // Makerbot Mightyboard Revision G and H
|
||||
|
||||
//
|
||||
// ATmega1281, ATmega2561
|
||||
@@ -419,6 +420,7 @@
|
||||
#define BOARD_MD_D301 5068 // Mingda D2 DZ301 V1.0 (STM32F103ZE)
|
||||
#define BOARD_VOXELAB_AQUILA 5069 // Voxelab Aquila V1.0.0/V1.0.1 (GD32F103RC / N32G455RE / STM32F103RE)
|
||||
#define BOARD_SPRINGER_CONTROLLER 5070 // ORCA 3D SPRINGER Modular Controller (STM32F103VC)
|
||||
#define BOARD_ATOMSTACK_FB5_V2 5071 // Atomstack FB5 V2.0 (STM32F103RCT6)
|
||||
|
||||
//
|
||||
// ARM Cortex-M4F
|
||||
@@ -483,16 +485,17 @@
|
||||
#define BOARD_BLACKPILL_CUSTOM 5249 // Custom board based on STM32F401CDU6.
|
||||
#define BOARD_I3DBEEZ9_V1 5250 // I3DBEEZ9 V1 (STM32F407ZG)
|
||||
#define BOARD_MELLOW_FLY_E3_V2 5251 // Mellow Fly E3 V2 (STM32F407VG)
|
||||
#define BOARD_BLACKBEEZMINI_V1 5252 // BlackBeezMini V1 (STM32F401CCU6)
|
||||
#define BOARD_XTLW_CLIMBER_8TH 5253 // XTLW Climber-8th (STM32F407VGT6)
|
||||
#define BOARD_FLY_RRF_E3_V1 5254 // Fly RRF E3 V1.0 (STM32F407VG)
|
||||
#define BOARD_FLY_SUPER8 5255 // Fly SUPER8 (STM32F407ZGT6)
|
||||
#define BOARD_FLY_D8 5256 // FLY D8 (STM32F407VG)
|
||||
#define BOARD_FLY_CDY_V3 5257 // FLY CDY V3 (STM32F407VGT6)
|
||||
#define BOARD_ZNP_ROBIN_NANO 5258 // Elegoo Neptune 2 v1.2 board
|
||||
#define BOARD_ZNP_ROBIN_NANO_V1_3 5259 // Elegoo Neptune 2 v1.3 board
|
||||
#define BOARD_MKS_NEPTUNE_X 5260 // Elegoo Neptune X
|
||||
#define BOARD_MKS_NEPTUNE_3 5261 // Elegoo Neptune 3
|
||||
#define BOARD_MELLOW_FLY_E3_PRO_V3 5252 // Mellow Fly E3 Pro V3 (STM32F407VG)
|
||||
#define BOARD_BLACKBEEZMINI_V1 5253 // BlackBeezMini V1 (STM32F401CCU6)
|
||||
#define BOARD_XTLW_CLIMBER_8TH 5254 // XTLW Climber-8th (STM32F407VGT6)
|
||||
#define BOARD_FLY_RRF_E3_V1 5255 // Fly RRF E3 V1.0 (STM32F407VG)
|
||||
#define BOARD_FLY_SUPER8 5256 // Fly SUPER8 (STM32F407ZGT6)
|
||||
#define BOARD_FLY_D8 5257 // FLY D8 (STM32F407VG)
|
||||
#define BOARD_FLY_CDY_V3 5258 // FLY CDY V3 (STM32F407VGT6)
|
||||
#define BOARD_ZNP_ROBIN_NANO 5259 // Elegoo Neptune 2 v1.2 board
|
||||
#define BOARD_ZNP_ROBIN_NANO_V1_3 5260 // Elegoo Neptune 2 v1.3 board
|
||||
#define BOARD_MKS_NEPTUNE_X 5261 // Elegoo Neptune X
|
||||
#define BOARD_MKS_NEPTUNE_3 5262 // Elegoo Neptune 3
|
||||
|
||||
//
|
||||
// Other ARM Cortex-M4
|
||||
|
||||
@@ -41,6 +41,6 @@ private:
|
||||
SERIAL_ECHO(fpre);
|
||||
if (the_msg) SERIAL_ECHO(C(' '), the_msg);
|
||||
SERIAL_CHAR(' ');
|
||||
print_xyz(xyz_pos_t(current_position));
|
||||
print_xyz(xyz_pos_t(motion.position));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,8 +57,10 @@
|
||||
// fr French
|
||||
// fr_na French without accents (DWIN T5UID1 touchscreen)
|
||||
// gl Galician
|
||||
// hg Hinglish (Hindi in Latin script)
|
||||
// hr Croatian
|
||||
// hu Hungarian
|
||||
// id Indonesian (Bahasa)
|
||||
// it Italian
|
||||
// jp_kana Japanese
|
||||
// ko_KR Korean (South Korea)
|
||||
@@ -366,17 +368,17 @@
|
||||
#define STR_Z2 STR_C "2"
|
||||
#define STR_Z3 STR_C "3"
|
||||
#define STR_Z4 STR_C "4"
|
||||
#if CORE_IS_XY || CORE_IS_XZ
|
||||
#if ANY(HAS_REAL_X, IS_SCARA, DELTA)
|
||||
#define STEPPER_A_NAME 'A'
|
||||
#else
|
||||
#define STEPPER_A_NAME 'X'
|
||||
#endif
|
||||
#if CORE_IS_XY || CORE_IS_YZ
|
||||
#if ANY(HAS_REAL_Y, IS_SCARA, DELTA, POLAR)
|
||||
#define STEPPER_B_NAME 'B'
|
||||
#else
|
||||
#define STEPPER_B_NAME 'Y'
|
||||
#endif
|
||||
#if CORE_IS_XZ || CORE_IS_YZ
|
||||
#if ANY(HAS_REAL_Z, DELTA)
|
||||
#define STEPPER_C_NAME 'C'
|
||||
#else
|
||||
#define STEPPER_C_NAME 'Z'
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
// Array shorthand
|
||||
#define COUNT(a) (sizeof(a)/sizeof(*a))
|
||||
#define ZERO(a) memset((void*)a,0,sizeof(a))
|
||||
#define OBJZERO(a) memset(&a,0,sizeof(a))
|
||||
#define COPY(a,b) do{ \
|
||||
static_assert(sizeof(a[0]) == sizeof(b[0]), "COPY: '" STRINGIFY(a) "' and '" STRINGIFY(b) "' types (sizes) don't match!"); \
|
||||
memcpy(&a[0],&b[0],_MIN(sizeof(a),sizeof(b))); \
|
||||
|
||||
@@ -158,16 +158,16 @@ public:
|
||||
MString& append_P(PGM_P const s) { int sz = length(); if (sz < SIZE) strlcpy_P(str + sz, s, SIZE - sz + 1); debug(F("pstring")); return *this; }
|
||||
MString& append(FSTR_P const f) { return append_P(FTOP(f)); }
|
||||
MString& append(const bool &b) { return append(b ? F("true") : F("false")); }
|
||||
MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } return *this; }
|
||||
MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } debug(F("char")); return *this; }
|
||||
#if ENABLED(FASTER_APPEND)
|
||||
MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; }
|
||||
MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; }
|
||||
MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; }
|
||||
MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); return *this; }
|
||||
MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; }
|
||||
MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; }
|
||||
MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; }
|
||||
MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); return *this; }
|
||||
MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("int8_t")); return *this; }
|
||||
MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("short")); return *this; }
|
||||
MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("int")); return *this; }
|
||||
MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); debug(F("long")); return *this; }
|
||||
MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("uchar")); return *this; }
|
||||
MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("ushort")); return *this; }
|
||||
MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("uint")); return *this; }
|
||||
MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); debug(F("ulong")); return *this; }
|
||||
#else
|
||||
MString& append(const int8_t &i) { char buf[ 5]; sprintf(buf, "%d", i); return append(buf); }
|
||||
MString& append(const short &i) { char buf[12]; sprintf(buf, "%d", i); return append(buf); }
|
||||
|
||||
+162
-84
@@ -52,6 +52,11 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
|
||||
#define MAIN_AXIS_NAMES_LC NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)
|
||||
#define NUM_AXIS_CALL(G) do { NUM_AXIS_CODE(G(X_AXIS), G(Y_AXIS), G(Z_AXIS), G(I_AXIS), G(J_AXIS), G(K_AXIS), G(U_AXIS), G(V_AXIS), G(W_AXIS)); } while(0)
|
||||
#define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
|
||||
#define NUM_AXIS_ANY(x, y, z, i, j, k, u, v, w) (false \
|
||||
NUM_AXIS_GANG(|| (x), || (y), || (z), || (i), || (j), || (k), || (u), || (v), || (w)))
|
||||
#define NUM_AXIS_ALL(x, y, z, i, j, k, u, v, w) ((NUM_AXES > 0) \
|
||||
NUM_AXIS_GANG(&& (x), && (y), && (z), && (i), && (j), && (k), && (u), && (v), && (w)))
|
||||
#define NUM_AXIS_NONE(V...) !NUM_AXIS_ANY(V)
|
||||
|
||||
#define LOGICAL_AXIS_GANG(N,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(N)
|
||||
#define LOGICAL_AXIS_CODE(N,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(N)
|
||||
@@ -71,6 +76,11 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
|
||||
#define LOGICAL_AXIS_MAP_LC(F) MAP(F, LOGICAL_AXIS_NAMES_LC)
|
||||
#define LOGICAL_AXIS_CALL(G) do { LOGICAL_AXIS_CODE(G(E_AXIS), G(X_AXIS), G(Y_AXIS), G(Z_AXIS), G(I_AXIS), G(J_AXIS), G(K_AXIS), G(U_AXIS), G(V_AXIS), G(W_AXIS)); } while(0)
|
||||
#define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
|
||||
#define LOGICAL_AXIS_ANY(e, x, y, z, i, j, k, u, v, w) (false \
|
||||
LOGICAL_AXIS_GANG(|| (e), || (x), || (y), || (z), || (i), || (j), || (k), || (u), || (v), || (w)))
|
||||
#define LOGICAL_AXIS_ALL(e, x, y, z, i, j, k, u, v, w) ((LOGICAL_AXES > 0) \
|
||||
LOGICAL_AXIS_GANG(&& (e), && (x), && (y), && (z), && (i), && (j), && (k), && (u), && (v), && (w)))
|
||||
#define LOGICAL_AXIS_NONE(V...) !LOGICAL_AXIS_ANY(V)
|
||||
|
||||
#define NUM_AXIS_PAIRED_LIST(V...) LIST_N(DOUBLE(NUM_AXES), V)
|
||||
#define LOGICAL_AXIS_PAIRED_LIST(EA,EB,V...) NUM_AXIS_PAIRED_LIST(V) LIST_ITEM_E(EA) LIST_ITEM_E(EB)
|
||||
@@ -145,10 +155,14 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
|
||||
#define XY_ARRAY(V...) ARRAY_N(XY_COUNT, V)
|
||||
#define XY_CODE(V...) CODE_N(XY_COUNT, V)
|
||||
#define XY_GANG(V...) GANG_N(XY_COUNT, V)
|
||||
#define XY_ANY(x,y) (false XY_GANG(|| (x), || (y)))
|
||||
#define XY_ALL(x,y) ((NUM_AXES > 0) XY_GANG(&& (x), && (y)))
|
||||
#define XYZ_LIST(V...) LIST_N(XYZ_COUNT, V)
|
||||
#define XYZ_ARRAY(V...) ARRAY_N(XYZ_COUNT, V)
|
||||
#define XYZ_CODE(V...) CODE_N(XYZ_COUNT, V)
|
||||
#define XYZ_GANG(V...) GANG_N(XYZ_COUNT, V)
|
||||
#define XYZ_ANY(x,y,z) (false XYZ_GANG(|| (x), || (y), || (z)))
|
||||
#define XYZ_ALL(x,y,z) ((NUM_AXES > 0) XYZ_GANG(&& (x), && (y), && (z)))
|
||||
|
||||
#if HAS_ROTATIONAL_AXES
|
||||
#define ROTATIONAL_AXIS_GANG(V...) GANG_N(ROTATIONAL_AXES, V)
|
||||
@@ -177,6 +191,7 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
|
||||
#define CARTES_CODE(x,y,z,e) XYZ_CODE(x,y,z) CODE_ITEM_E(e)
|
||||
#define CARTES_GANG(x,y,z,e) XYZ_GANG(x,y,z) GANG_ITEM_E(e)
|
||||
#define CARTES_AXIS_NAMES CARTES_LIST(X,Y,Z,E)
|
||||
#define CARTES_AXIS_NAMES_LC CARTES_LIST(x,y,z,e)
|
||||
#define CARTES_MAP(F) MAP(F, CARTES_AXIS_NAMES)
|
||||
#if CARTES_COUNT
|
||||
#define CARTES_COMMA ,
|
||||
@@ -335,9 +350,9 @@ typedef struct {
|
||||
//
|
||||
// Enumerated axis indices
|
||||
//
|
||||
// - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space
|
||||
// - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians
|
||||
// - X_HEAD, Y_HEAD, and Z_HEAD should be used for axes on Core kinematics
|
||||
// - X_REAL, Y_REAL, and Z_REAL should be used for axes in Cartesian space
|
||||
// - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers
|
||||
// - X_AXIS, Y_AXIS, and Z_AXIS are now more generic interchangeble indexes
|
||||
//
|
||||
enum AxisEnum : uint8_t {
|
||||
|
||||
@@ -349,8 +364,14 @@ enum AxisEnum : uint8_t {
|
||||
#undef _EN_ITEM
|
||||
|
||||
// Core also keeps toolhead directions
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
X_HEAD, Y_HEAD, Z_HEAD,
|
||||
#if HAS_REAL_X
|
||||
X_REAL,
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
Y_REAL,
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
Z_REAL,
|
||||
#endif
|
||||
|
||||
// Distinct axes, including all E and Core
|
||||
@@ -359,6 +380,10 @@ enum AxisEnum : uint8_t {
|
||||
// Most of the time we refer only to the single E_AXIS
|
||||
#if HAS_EXTRUDERS
|
||||
E_AXIS = E0_AXIS,
|
||||
E_REAL = E_AXIS,
|
||||
#define _EN_REAL(N) E##N##_REAL = E##N##_AXIS,
|
||||
REPEAT(EXTRUDERS, _EN_REAL)
|
||||
#undef _EN_REAL
|
||||
#endif
|
||||
|
||||
// A, B, and C are for DELTA, SCARA, etc.
|
||||
@@ -372,6 +397,35 @@ enum AxisEnum : uint8_t {
|
||||
C_AXIS = Z_AXIS,
|
||||
#endif
|
||||
|
||||
// Aliases to distinguish tool axes from stepper indexes
|
||||
#if HAS_X_AXIS && !HAS_REAL_X
|
||||
X_REAL = X_AXIS,
|
||||
#endif
|
||||
#if HAS_Y_AXIS && !HAS_REAL_Y
|
||||
Y_REAL = Y_AXIS,
|
||||
#endif
|
||||
#if HAS_Z_AXIS && !HAS_REAL_Z
|
||||
Z_REAL = Z_AXIS,
|
||||
#endif
|
||||
#if HAS_I_AXIS
|
||||
I_REAL = I_AXIS,
|
||||
#endif
|
||||
#if HAS_J_AXIS
|
||||
J_REAL = J_AXIS,
|
||||
#endif
|
||||
#if HAS_K_AXIS
|
||||
K_REAL = K_AXIS,
|
||||
#endif
|
||||
#if HAS_U_AXIS
|
||||
U_REAL = U_AXIS,
|
||||
#endif
|
||||
#if HAS_V_AXIS
|
||||
V_REAL = V_AXIS,
|
||||
#endif
|
||||
#if HAS_W_AXIS
|
||||
W_REAL = W_AXIS,
|
||||
#endif
|
||||
|
||||
// To refer to all or none
|
||||
ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
|
||||
};
|
||||
@@ -556,7 +610,7 @@ struct XYval {
|
||||
#endif
|
||||
|
||||
// Length reduced to one dimension
|
||||
FI constexpr T magnitude() const { return (T)sqrtf(x*x + y*y); }
|
||||
FI constexpr T magnitude() const { return (T)SQRT(x*x + y*y); }
|
||||
// Pointer to the data as a simple array
|
||||
explicit FI operator T* () { return pos; }
|
||||
// If any element is true then it's true
|
||||
@@ -578,7 +632,7 @@ struct XYval {
|
||||
FI constexpr XYval<uint32_t> asUInt32() const { return { uint32_t(x), uint32_t(y) }; }
|
||||
FI constexpr XYval<int64_t> asInt64() const { return { int64_t(x), int64_t(y) }; }
|
||||
FI constexpr XYval<uint64_t> asUInt64() const { return { uint64_t(x), uint64_t(y) }; }
|
||||
FI constexpr XYval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y) }; }
|
||||
FI constexpr XYval<float> asFloat() const { return { float(x), float(y) }; }
|
||||
|
||||
// Marlin workspace shifting is done with G92 and M206
|
||||
FI XYval<float> asLogical() const { XYval<float> o = asFloat(); toLogical(o); return o; }
|
||||
@@ -645,8 +699,8 @@ struct XYval {
|
||||
|
||||
// Exact comparisons. For floats a "NEAR" operation may be better.
|
||||
FI bool operator==(const XYval<T> &rs) const { return x == rs.x && y == rs.y; }
|
||||
FI bool operator==(const XYZval<T> &rs) const { return ENABLED(HAS_X_AXIS) XY_GANG(&& x == rs.x, && y == rs.y); }
|
||||
FI bool operator==(const XYZEval<T> &rs) const { return ENABLED(HAS_X_AXIS) XY_GANG(&& x == rs.x, && y == rs.y); }
|
||||
FI bool operator==(const XYZval<T> &rs) const { return XY_ALL(x == rs.x, y == rs.y); }
|
||||
FI bool operator==(const XYZEval<T> &rs) const { return XY_ALL(x == rs.x, y == rs.y); }
|
||||
FI bool operator!=(const XYval<T> &rs) const { return !operator==(rs); }
|
||||
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
|
||||
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
|
||||
@@ -660,15 +714,15 @@ struct XYval {
|
||||
FI bool operator> (const XYval<T> &rs) const { return x > rs.x && y > rs.y; }
|
||||
FI bool operator>=(const XYval<T> &rs) const { return x >= rs.x && y >= rs.y; }
|
||||
|
||||
FI bool operator< (const XYZval<T> &rs) const { return true XY_GANG(&& x < rs.x, && y < rs.y); }
|
||||
FI bool operator<=(const XYZval<T> &rs) const { return true XY_GANG(&& x <= rs.x, && y <= rs.y); }
|
||||
FI bool operator> (const XYZval<T> &rs) const { return true XY_GANG(&& x > rs.x, && y > rs.y); }
|
||||
FI bool operator>=(const XYZval<T> &rs) const { return true XY_GANG(&& x >= rs.x, && y >= rs.y); }
|
||||
FI bool operator< (const XYZval<T> &rs) const { return XY_ALL(x < rs.x, y < rs.y); }
|
||||
FI bool operator<=(const XYZval<T> &rs) const { return XY_ALL(x <= rs.x, y <= rs.y); }
|
||||
FI bool operator> (const XYZval<T> &rs) const { return XY_ALL(x > rs.x, y > rs.y); }
|
||||
FI bool operator>=(const XYZval<T> &rs) const { return XY_ALL(x >= rs.x, y >= rs.y); }
|
||||
|
||||
FI bool operator< (const XYZEval<T> &rs) const { return true XY_GANG(&& x < rs.x, && y < rs.y); }
|
||||
FI bool operator<=(const XYZEval<T> &rs) const { return true XY_GANG(&& x <= rs.x, && y <= rs.y); }
|
||||
FI bool operator> (const XYZEval<T> &rs) const { return true XY_GANG(&& x > rs.x, && y > rs.y); }
|
||||
FI bool operator>=(const XYZEval<T> &rs) const { return true XY_GANG(&& x >= rs.x, && y >= rs.y); }
|
||||
FI bool operator< (const XYZEval<T> &rs) const { return XY_ALL(x < rs.x, y < rs.y); }
|
||||
FI bool operator<=(const XYZEval<T> &rs) const { return XY_ALL(x <= rs.x, y <= rs.y); }
|
||||
FI bool operator> (const XYZEval<T> &rs) const { return XY_ALL(x > rs.x, y > rs.y); }
|
||||
FI bool operator>=(const XYZEval<T> &rs) const { return XY_ALL(x >= rs.x, y >= rs.y); }
|
||||
|
||||
};
|
||||
|
||||
@@ -708,36 +762,36 @@ struct XYZval {
|
||||
|
||||
// Setters with fewer elements leave the rest untouched
|
||||
#if HAS_Y_AXIS
|
||||
FI void set(const T px) { x = px; }
|
||||
FI void set(const T px) { x = px; }
|
||||
#endif
|
||||
#if HAS_Z_AXIS
|
||||
FI void set(const T px, const T py) { x = px; y = py; }
|
||||
FI void set(const T px, const T py) { set(px); y = py; }
|
||||
#endif
|
||||
#if HAS_I_AXIS
|
||||
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
|
||||
FI void set(const T px, const T py, const T pz) { set(px, py); z = pz; }
|
||||
#endif
|
||||
#if HAS_J_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi) { set(px, py, pz); i = pi; }
|
||||
#endif
|
||||
#if HAS_K_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj) { set(px, py, pz, pi); j = pj; }
|
||||
#endif
|
||||
#if HAS_U_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { set(px, py, pz, pi, pj); k = pk; }
|
||||
#endif
|
||||
#if HAS_V_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { set(px, py, pz, pi, pj, pk); u = pu; }
|
||||
#endif
|
||||
#if HAS_W_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { set(px, py, pz, pi, pj, pk, pu); v = pv; }
|
||||
#endif
|
||||
|
||||
// Length reduced to one dimension
|
||||
FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); }
|
||||
FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, SQRT(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); }
|
||||
// Pointer to the data as a simple array
|
||||
explicit FI operator T* () { return pos; }
|
||||
// If any element is true then it's true
|
||||
FI constexpr operator bool() const { return 0 NUM_AXIS_GANG(|| x, || y, || z, || i, || j, || k, || u, || v, || w); }
|
||||
FI constexpr operator bool() const { return NUM_AXIS_ANY(x, y, z, i, j, k, u, v, w); }
|
||||
// Smallest element
|
||||
FI constexpr T small() const { return TERN0(HAS_X_AXIS, _MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w))); }
|
||||
// Largest element
|
||||
@@ -755,13 +809,13 @@ struct XYZval {
|
||||
FI constexpr XYZval<uint32_t> asUInt32() const { return NUM_AXIS_ARRAY(uint32_t(x), uint32_t(y), uint32_t(z), uint32_t(i), uint32_t(j), uint32_t(k), uint32_t(u), uint32_t(v), uint32_t(w)); }
|
||||
FI constexpr XYZval<int64_t> asInt64() const { return NUM_AXIS_ARRAY(int64_t(x), int64_t(y), int64_t(z), int64_t(i), int64_t(j), int64_t(k), int64_t(u), int64_t(v), int64_t(w)); }
|
||||
FI constexpr XYZval<uint64_t> asUInt64() const { return NUM_AXIS_ARRAY(uint64_t(x), uint64_t(y), uint64_t(z), uint64_t(i), uint64_t(j), uint64_t(k), uint64_t(u), uint64_t(v), uint64_t(w)); }
|
||||
FI constexpr XYZval<float> asFloat() const { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
|
||||
FI constexpr XYZval<float> asFloat() const { return NUM_AXIS_ARRAY(float(x), float(y), float(z), float(i), float(j), float(k), float(u), float(v), float(w)); }
|
||||
|
||||
// Marlin workspace shifting is done with G92 and M206
|
||||
FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
|
||||
FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
|
||||
|
||||
// In-place cast to types having fewer fields
|
||||
// In-place reinterpret-cast to types having fewer fields
|
||||
FI operator XYval<T>&() { return *(XYval<T>*)this; }
|
||||
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
|
||||
|
||||
@@ -816,29 +870,29 @@ struct XYZval {
|
||||
FI XYZval<T>& operator-=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; }
|
||||
FI XYZval<T>& operator*=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; }
|
||||
FI XYZval<T>& operator/=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; }
|
||||
FI XYZval<T>& operator*=(const float p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; }
|
||||
FI XYZval<T>& operator*=(const float &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; }
|
||||
FI XYZval<T>& operator*=(const int &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; }
|
||||
FI XYZval<T>& operator/=(const float p) { NUM_AXIS_CODE(x /= p, y /= p, z /= p, i /= p, j /= p, k /= p, u /= p, v /= p, w /= p); return *this; }
|
||||
FI XYZval<T>& operator/=(const float &p) { NUM_AXIS_CODE(x /= p, y /= p, z /= p, i /= p, j /= p, k /= p, u /= p, v /= p, w /= p); return *this; }
|
||||
FI XYZval<T>& operator>>=(const int &p) { NUM_AXIS_CODE(_RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; }
|
||||
FI XYZval<T>& operator<<=(const int &p) { NUM_AXIS_CODE(_LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; }
|
||||
|
||||
// Exact comparisons. For floats a "NEAR" operation may be better.
|
||||
FI bool operator==(const XYZEval<T> &rs) const { return ENABLED(HAS_X_AXIS) NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
|
||||
FI bool operator==(const XYZEval<T> &rs) const { return NUM_AXIS_ALL(x == rs.x, y == rs.y, z == rs.z, i == rs.i, j == rs.j, k == rs.k, u == rs.u, v == rs.v, w == rs.w); }
|
||||
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
|
||||
|
||||
// Exact comparison to a single value
|
||||
FI bool operator==(const T &p) const { return ENABLED(HAS_X_AXIS) NUM_AXIS_GANG(&& x == p, && y == p, && z == p, && i == p, && j == p, && k == p, && u == p, && v == p, && w == p); }
|
||||
FI bool operator==(const T &p) const { return NUM_AXIS_ALL(x == p, y == p, z == p, i == p, j == p, k == p, u == p, v == p, w == p); }
|
||||
FI bool operator!=(const T &p) const { return !operator==(p); }
|
||||
|
||||
FI bool operator< (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
|
||||
FI bool operator<=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
|
||||
FI bool operator> (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
|
||||
FI bool operator>=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
|
||||
FI bool operator< (const XYZval<T> &rs) const { return NUM_AXIS_ALL(x < rs.x, y < rs.y, z < rs.z, i < rs.i, j < rs.j, k < rs.k, u < rs.u, v < rs.v, w < rs.w); }
|
||||
FI bool operator<=(const XYZval<T> &rs) const { return NUM_AXIS_ALL(x <= rs.x, y <= rs.y, z <= rs.z, i <= rs.i, j <= rs.j, k <= rs.k, u <= rs.u, v <= rs.v, w <= rs.w); }
|
||||
FI bool operator> (const XYZval<T> &rs) const { return NUM_AXIS_ALL(x > rs.x, y > rs.y, z > rs.z, i > rs.i, j > rs.j, k > rs.k, u > rs.u, v > rs.v, w > rs.w); }
|
||||
FI bool operator>=(const XYZval<T> &rs) const { return NUM_AXIS_ALL(x >= rs.x, y >= rs.y, z >= rs.z, i >= rs.i, j >= rs.j, k >= rs.k, u >= rs.u, v >= rs.v, w >= rs.w); }
|
||||
|
||||
FI bool operator< (const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
|
||||
FI bool operator<=(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
|
||||
FI bool operator> (const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
|
||||
FI bool operator>=(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
|
||||
FI bool operator< (const XYZEval<T> &rs) const { return NUM_AXIS_ALL(x < rs.x, y < rs.y, z < rs.z, i < rs.i, j < rs.j, k < rs.k, u < rs.u, v < rs.v, w < rs.w); }
|
||||
FI bool operator<=(const XYZEval<T> &rs) const { return NUM_AXIS_ALL(x <= rs.x, y <= rs.y, z <= rs.z, i <= rs.i, j <= rs.j, k <= rs.k, u <= rs.u, v <= rs.v, w <= rs.w); }
|
||||
FI bool operator> (const XYZEval<T> &rs) const { return NUM_AXIS_ALL(x > rs.x, y > rs.y, z > rs.z, i > rs.i, j > rs.j, k > rs.k, u > rs.u, v > rs.v, w > rs.w); }
|
||||
FI bool operator>=(const XYZEval<T> &rs) const { return NUM_AXIS_ALL(x >= rs.x, y >= rs.y, z >= rs.z, i >= rs.i, j >= rs.j, k >= rs.k, u >= rs.u, v >= rs.v, w >= rs.w); }
|
||||
|
||||
};
|
||||
|
||||
@@ -857,7 +911,7 @@ struct XYZEval {
|
||||
T pos[LOGICAL_AXES];
|
||||
};
|
||||
// Reset all to 0
|
||||
FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
|
||||
FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
|
||||
|
||||
// Setters taking struct types and arrays
|
||||
FI void set(const XYval<T> &pxy) { XY_CODE(x = pxy.x, y = pxy.y); }
|
||||
@@ -882,33 +936,33 @@ struct XYZEval {
|
||||
FI void set(const T px) { x = px; }
|
||||
#endif
|
||||
#if HAS_Z_AXIS
|
||||
FI void set(const T px, const T py) { x = px; y = py; }
|
||||
FI void set(const T px, const T py) { set(px); y = py; }
|
||||
#endif
|
||||
#if HAS_I_AXIS
|
||||
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
|
||||
FI void set(const T px, const T py, const T pz) { set(px, py); z = pz; }
|
||||
#endif
|
||||
#if HAS_J_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi) { set(px, py, pz); i = pi; }
|
||||
#endif
|
||||
#if HAS_K_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj) { set(px, py, pz, pi); j = pj; }
|
||||
#endif
|
||||
#if HAS_U_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { set(px, py, pz, pi, pj); k = pk; }
|
||||
#endif
|
||||
#if HAS_V_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { set(px, py, pz, pi, pj, pk); u = pu; }
|
||||
#endif
|
||||
#if HAS_W_AXIS
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; }
|
||||
FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { set(px, py, pz, pi, pj, pk, pu); v = pv; }
|
||||
#endif
|
||||
|
||||
// Length reduced to one dimension
|
||||
FI constexpr T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); }
|
||||
FI constexpr T magnitude() const { return (T)SQRT(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); }
|
||||
// Pointer to the data as a simple array
|
||||
explicit FI operator T* () { return pos; }
|
||||
// If any element is true then it's true
|
||||
FI constexpr operator bool() const { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); }
|
||||
FI constexpr operator bool() const { return LOGICAL_AXIS_ANY(e, x, y, z, i, j, k, u, v, w); }
|
||||
// Smallest element
|
||||
FI constexpr T small() const { return _MIN(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); }
|
||||
// Largest element
|
||||
@@ -926,13 +980,13 @@ struct XYZEval {
|
||||
FI constexpr XYZEval<uint32_t> asUInt32() const { return LOGICAL_AXIS_ARRAY(uint32_t(e), uint32_t(x), uint32_t(y), uint32_t(z), uint32_t(i), uint32_t(j), uint32_t(k), uint32_t(u), uint32_t(v), uint32_t(w)); }
|
||||
FI constexpr XYZEval<int64_t> asInt64() const { return LOGICAL_AXIS_ARRAY(int64_t(e), int64_t(x), int64_t(y), int64_t(z), int64_t(i), int64_t(j), int64_t(k), int64_t(u), int64_t(v), int64_t(w)); }
|
||||
FI constexpr XYZEval<uint64_t> asUInt64() const { return LOGICAL_AXIS_ARRAY(uint64_t(e), uint64_t(x), uint64_t(y), uint64_t(z), uint64_t(i), uint64_t(j), uint64_t(k), uint64_t(u), uint64_t(v), uint64_t(w)); }
|
||||
FI constexpr XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
|
||||
FI constexpr XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(float(e), float(x), float(y), float(z), float(i), float(j), float(k), float(u), float(v), float(w)); }
|
||||
|
||||
// Marlin workspace shifting is done with G92 and M206
|
||||
FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
|
||||
FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
|
||||
|
||||
// In-place cast to types having fewer fields
|
||||
// In-place reinterpret-cast to types having fewer fields
|
||||
FI operator XYval<T>&() { return *(XYval<T>*)this; }
|
||||
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
|
||||
FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
|
||||
@@ -997,24 +1051,24 @@ struct XYZEval {
|
||||
FI XYZEval<T>& operator<<=(const int &p) { LOGICAL_AXIS_CODE(_LSE(e), _LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; }
|
||||
|
||||
// Exact comparisons. For floats a "NEAR" operation may be better.
|
||||
FI bool operator==(const XYZval<T> &rs) const { return ENABLED(HAS_X_AXIS) NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
|
||||
FI bool operator==(const XYZEval<T> &rs) const { return ANY(HAS_X_AXIS, HAS_EXTRUDERS) LOGICAL_AXIS_GANG(&& e == rs.e, && x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
|
||||
FI bool operator==(const XYZval<T> &rs) const { return NUM_AXIS_ALL(x == rs.x, y == rs.y, z == rs.z, i == rs.i, j == rs.j, k == rs.k, u == rs.u, v == rs.v, w == rs.w); }
|
||||
FI bool operator==(const XYZEval<T> &rs) const { return LOGICAL_AXIS_ALL(e == rs.e, x == rs.x, y == rs.y, z == rs.z, i == rs.i, j == rs.j, k == rs.k, u == rs.u, v == rs.v, w == rs.w); }
|
||||
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
|
||||
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
|
||||
|
||||
// Exact comparison to a single value
|
||||
FI bool operator==(const T &p) const { return ENABLED(HAS_X_AXIS) LOGICAL_AXIS_GANG(&& e == p, && x == p, && y == p, && z == p, && i == p, && j == p, && k == p, && u == p, && v == p, && w == p); }
|
||||
FI bool operator==(const T &p) const { return LOGICAL_AXIS_ALL(e == p, x == p, y == p, z == p, i == p, j == p, k == p, u == p, v == p, w == p); }
|
||||
FI bool operator!=(const T &p) const { return !operator==(p); }
|
||||
|
||||
FI bool operator< (const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e < rs.e, && x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
|
||||
FI bool operator<=(const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e <= rs.e, && x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
|
||||
FI bool operator> (const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e > rs.e, && x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
|
||||
FI bool operator>=(const XYZEval<T> &rs) const { return true LOGICAL_AXIS_GANG(&& e >= rs.e, && x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
|
||||
FI bool operator< (const XYZEval<T> &rs) const { return LOGICAL_AXIS_ALL(e < rs.e, x < rs.x, y < rs.y, z < rs.z, i < rs.i, j < rs.j, k < rs.k, u < rs.u, v < rs.v, w < rs.w); }
|
||||
FI bool operator<=(const XYZEval<T> &rs) const { return LOGICAL_AXIS_ALL(e <= rs.e, x <= rs.x, y <= rs.y, z <= rs.z, i <= rs.i, j <= rs.j, k <= rs.k, u <= rs.u, v <= rs.v, w <= rs.w); }
|
||||
FI bool operator> (const XYZEval<T> &rs) const { return LOGICAL_AXIS_ALL(e > rs.e, x > rs.x, y > rs.y, z > rs.z, i > rs.i, j > rs.j, k > rs.k, u > rs.u, v > rs.v, w > rs.w); }
|
||||
FI bool operator>=(const XYZEval<T> &rs) const { return LOGICAL_AXIS_ALL(e >= rs.e, x >= rs.x, y >= rs.y, z >= rs.z, i >= rs.i, j >= rs.j, k >= rs.k, u >= rs.u, v >= rs.v, w >= rs.w); }
|
||||
|
||||
FI bool operator< (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x < rs.x, && y < rs.y, && z < rs.z, && i < rs.i, && j < rs.j, && k < rs.k, && u < rs.u, && v < rs.v, && w < rs.w); }
|
||||
FI bool operator<=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x <= rs.x, && y <= rs.y, && z <= rs.z, && i <= rs.i, && j <= rs.j, && k <= rs.k, && u <= rs.u, && v <= rs.v, && w <= rs.w); }
|
||||
FI bool operator> (const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x > rs.x, && y > rs.y, && z > rs.z, && i > rs.i, && j > rs.j, && k > rs.k, && u > rs.u, && v > rs.v, && w > rs.w); }
|
||||
FI bool operator>=(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x >= rs.x, && y >= rs.y, && z >= rs.z, && i >= rs.i, && j >= rs.j, && k >= rs.k, && u >= rs.u, && v >= rs.v, && w >= rs.w); }
|
||||
FI bool operator< (const XYZval<T> &rs) const { return NUM_AXIS_ALL(x < rs.x, y < rs.y, z < rs.z, i < rs.i, j < rs.j, k < rs.k, u < rs.u, v < rs.v, w < rs.w); }
|
||||
FI bool operator<=(const XYZval<T> &rs) const { return NUM_AXIS_ALL(x <= rs.x, y <= rs.y, z <= rs.z, i <= rs.i, j <= rs.j, k <= rs.k, u <= rs.u, v <= rs.v, w <= rs.w); }
|
||||
FI bool operator> (const XYZval<T> &rs) const { return NUM_AXIS_ALL(x > rs.x, y > rs.y, z > rs.z, i > rs.i, j > rs.j, k > rs.k, u > rs.u, v > rs.v, w > rs.w); }
|
||||
FI bool operator>=(const XYZval<T> &rs) const { return NUM_AXIS_ALL(x >= rs.x, y >= rs.y, z >= rs.z, i >= rs.i, j >= rs.j, k >= rs.k, u >= rs.u, v >= rs.v, w >= rs.w); }
|
||||
|
||||
};
|
||||
|
||||
@@ -1044,28 +1098,28 @@ struct XYZarray {
|
||||
|
||||
// Setters with fewer elements leave the rest untouched
|
||||
#if HAS_Y_AXIS
|
||||
FI void set(const int n, const T px) { x[n] = px; }
|
||||
FI void set(const int n, const T px) { x[n] = px; }
|
||||
#endif
|
||||
#if HAS_Z_AXIS
|
||||
FI void set(const int n, const T px, const T py) { x[n] = px; y[n] = py; }
|
||||
FI void set(const int n, const T px, const T py) { set(n, px); y[n] = py; }
|
||||
#endif
|
||||
#if HAS_I_AXIS
|
||||
FI void set(const int n, const T px, const T py, const T pz) { x[n] = px; y[n] = py; z[n] = pz; }
|
||||
FI void set(const int n, const T px, const T py, const T pz) { set(n, px, py); z[n] = pz; }
|
||||
#endif
|
||||
#if HAS_J_AXIS
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; }
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi) { set(n, px, py, pz); i[n] = pi; }
|
||||
#endif
|
||||
#if HAS_K_AXIS
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; }
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj) { set(n, px, py, pz, pi); j[n] = pj; }
|
||||
#endif
|
||||
#if HAS_U_AXIS
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; }
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk) { set(n, px, py, pz, pi, pj); k[n] = pk; }
|
||||
#endif
|
||||
#if HAS_V_AXIS
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; }
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { set(n, px, py, pz, pi, pj, pk); u[n] = pu; }
|
||||
#endif
|
||||
#if HAS_W_AXIS
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; v[n] = pv; }
|
||||
FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { set(n, px, py, pz, pi, pj, pk, pu); v[n] = pv; }
|
||||
#endif
|
||||
|
||||
FI XYZval<T> operator[](const int n) const { return XYZval<T>(NUM_AXIS_ARRAY(x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); }
|
||||
@@ -1130,7 +1184,7 @@ public:
|
||||
typedef bits_t(NUM_AXIS_HEADS) el;
|
||||
union {
|
||||
el bits;
|
||||
// Axes x, y, z ... e0, e1, e2 ... hx, hy, hz
|
||||
// Axes x, y, z ... e0, e1, e2 ... rx, ry, rz
|
||||
struct {
|
||||
#if NUM_AXES
|
||||
bool NUM_AXIS_LIST(x:1, y:1, z:1, i:1, j:1, k:1, u:1, v:1, w:1);
|
||||
@@ -1138,11 +1192,17 @@ public:
|
||||
#define _EN_ITEM(N) bool e##N:1;
|
||||
REPEAT(EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool hx:1, hy:1, hz:1;
|
||||
#if HAS_REAL_X
|
||||
bool rx:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool ry:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool rz:1;
|
||||
#endif
|
||||
};
|
||||
// Axes X, Y, Z ... E0, E1, E2 ... HX, HY, HZ
|
||||
// Axes X, Y, Z ... E0, E1, E2 ... RX, RY, RZ
|
||||
struct {
|
||||
#if NUM_AXES
|
||||
bool NUM_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, W:1);
|
||||
@@ -1150,11 +1210,17 @@ public:
|
||||
#define _EN_ITEM(N) bool E##N:1;
|
||||
REPEAT(EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool HX:1, HY:1, HZ:1;
|
||||
#if HAS_REAL_X
|
||||
bool RX:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool RY:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool RZ:1;
|
||||
#endif
|
||||
};
|
||||
// a, b, c, e ... ha, hb, hc
|
||||
// a, b, c, e ... ra, rb, rc
|
||||
struct {
|
||||
bool LOGICAL_AXIS_LIST(e:1, a:1, b:1, c:1, ii:1, jj:1, kk:1, uu:1, vv:1, ww:1);
|
||||
#if EXTRUDERS > 1
|
||||
@@ -1162,11 +1228,17 @@ public:
|
||||
REPEAT_S(1,EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#endif
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool ha:1, hb:1, hc:1;
|
||||
#if HAS_REAL_X
|
||||
bool ra:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool rb:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool rc:1;
|
||||
#endif
|
||||
};
|
||||
// A, B, C, E ... HA, HB, HC
|
||||
// A, B, C, E ... RA, RB, RC
|
||||
struct {
|
||||
bool LOGICAL_AXIS_LIST(E:1, A:1, B:1, C:1, II:1, JJ:1, KK:1, UU:1, VV:1, WW:1);
|
||||
#if EXTRUDERS > 1
|
||||
@@ -1174,8 +1246,14 @@ public:
|
||||
REPEAT_S(1,EXTRUDERS,_EN_ITEM)
|
||||
#undef _EN_ITEM
|
||||
#endif
|
||||
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
|
||||
bool HA:1, HB:1, HC:1;
|
||||
#if HAS_REAL_X
|
||||
bool RA:1;
|
||||
#endif
|
||||
#if HAS_REAL_Y
|
||||
bool RB:1;
|
||||
#endif
|
||||
#if HAS_REAL_Z
|
||||
bool RC:1;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
SERIAL_ECHOPGM("ABL Adjustment");
|
||||
LOOP_NUM_AXES(a) {
|
||||
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]));
|
||||
serial_offset(planner.get_axis_position_mm((AxisEnum)a) - current_position[a]);
|
||||
serial_offset(planner.get_axis_position_mm((AxisEnum)a) - motion.position[a]);
|
||||
}
|
||||
#else
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
@@ -141,11 +141,11 @@
|
||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
SERIAL_ECHOPGM("ABL Adjustment Z");
|
||||
#endif
|
||||
const float rz = bedlevel.get_z_correction(current_position);
|
||||
const float rz = bedlevel.get_z_correction(motion.position);
|
||||
SERIAL_ECHO(ftostr43sign(rz, '+'));
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
if (planner.z_fade_height)
|
||||
SERIAL_ECHO(F(" ("), ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+'), C(')'));
|
||||
SERIAL_ECHO(F(" ("), ftostr43sign(rz * planner.fade_scaling_factor_for_z(motion.position.z), '+'), C(')'));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -160,11 +160,11 @@
|
||||
if (planner.leveling_active) {
|
||||
SERIAL_ECHOLNPGM(" (enabled)");
|
||||
const float z_offset = bedlevel.get_z_offset(),
|
||||
z_correction = bedlevel.get_z_correction(current_position);
|
||||
z_correction = bedlevel.get_z_correction(motion.position);
|
||||
SERIAL_ECHOPGM("MBL Adjustment Z", ftostr43sign(z_offset + z_correction, '+'));
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
if (planner.z_fade_height) {
|
||||
SERIAL_ECHO(F(" ("), ftostr43sign(z_offset + z_correction * planner.fade_scaling_factor_for_z(current_position.z), '+'), C(')'));
|
||||
SERIAL_ECHO(F(" ("), ftostr43sign(z_offset + z_correction * planner.fade_scaling_factor_for_z(motion.position.z), '+'), C(')'));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ void Babystep::add_mm(const AxisEnum axis, const float mm) {
|
||||
|
||||
#if ENABLED(BD_SENSOR)
|
||||
void Babystep::set_mm(const AxisEnum axis, const float mm) {
|
||||
//if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axis_should_home(axis)) return;
|
||||
//if (DISABLED(BABYSTEP_WITHOUT_HOMING) && motion.axis_should_home(axis)) return;
|
||||
const int16_t distance = mm * planner.settings.axis_steps_per_mm[axis];
|
||||
accum = distance; // Count up babysteps for the UI
|
||||
steps[BS_AXIS_IND(axis)] = distance;
|
||||
@@ -70,7 +70,7 @@ void Babystep::add_mm(const AxisEnum axis, const float mm) {
|
||||
#endif
|
||||
|
||||
bool Babystep::can_babystep(const AxisEnum axis) {
|
||||
return (ENABLED(BABYSTEP_WITHOUT_HOMING) || !axis_should_home(axis));
|
||||
return (ENABLED(BABYSTEP_WITHOUT_HOMING) || !motion.axis_should_home(axis));
|
||||
}
|
||||
|
||||
void Babystep::add_steps(const AxisEnum axis, const int16_t distance) {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "../module/motion.h"
|
||||
#include "../module/planner.h"
|
||||
|
||||
AxisBits Backlash::last_direction_bits;
|
||||
AxisBits Backlash::last_direction;
|
||||
xyz_long_t Backlash::residual_error{0};
|
||||
|
||||
#ifdef BACKLASH_DISTANCE_MM
|
||||
@@ -64,7 +64,7 @@ Backlash backlash;
|
||||
*/
|
||||
|
||||
void Backlash::add_correction_steps(const xyze_long_t &dist, const AxisBits dm, block_t * const block) {
|
||||
AxisBits changed_dir = last_direction_bits ^ dm;
|
||||
AxisBits changed_dir = last_direction ^ dm;
|
||||
// Ignore direction change unless steps are taken in that direction
|
||||
#if DISABLED(CORE_BACKLASH) || ANY(MARKFORGED_XY, MARKFORGED_YX)
|
||||
if (!dist.a) changed_dir.x = false;
|
||||
@@ -83,7 +83,7 @@ void Backlash::add_correction_steps(const xyze_long_t &dist, const AxisBits dm,
|
||||
if (!(dist.b - dist.c)) changed_dir.z = false;
|
||||
if (!dist.a) changed_dir.x = false;
|
||||
#endif
|
||||
last_direction_bits ^= changed_dir;
|
||||
last_direction ^= changed_dir;
|
||||
|
||||
if (!correction && !residual_error) return;
|
||||
|
||||
@@ -167,7 +167,7 @@ void Backlash::add_correction_steps(const xyze_long_t &dist, const AxisBits dm,
|
||||
int32_t Backlash::get_applied_steps(const AxisEnum axis) {
|
||||
if (axis >= NUM_AXES) return 0;
|
||||
|
||||
const bool forward = last_direction_bits[axis];
|
||||
const bool forward = last_direction[axis];
|
||||
|
||||
const int32_t residual_error_axis = residual_error[axis];
|
||||
|
||||
@@ -224,12 +224,12 @@ class Backlash::StepAdjuster {
|
||||
void Backlash::measure_with_probe() {
|
||||
if (measured_count.z == 255) return;
|
||||
|
||||
const float start_height = current_position.z;
|
||||
while (current_position.z < (start_height + BACKLASH_MEASUREMENT_LIMIT) && PROBE_TRIGGERED())
|
||||
do_blocking_move_to_z(current_position.z + BACKLASH_MEASUREMENT_RESOLUTION, MMM_TO_MMS(BACKLASH_MEASUREMENT_FEEDRATE));
|
||||
const float start_height = motion.position.z;
|
||||
while (motion.position.z < (start_height + BACKLASH_MEASUREMENT_LIMIT) && PROBE_TRIGGERED())
|
||||
motion.blocking_move_z(motion.position.z + BACKLASH_MEASUREMENT_RESOLUTION, MMM_TO_MMS(BACKLASH_MEASUREMENT_FEEDRATE));
|
||||
|
||||
// The backlash from all probe points is averaged, so count the number of measurements
|
||||
measured_mm.z += current_position.z - start_height;
|
||||
measured_mm.z += motion.position.z - start_height;
|
||||
measured_count.z++;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
static constexpr uint8_t all_on = 0xFF, all_off = 0x00;
|
||||
|
||||
private:
|
||||
static AxisBits last_direction_bits;
|
||||
static AxisBits last_direction;
|
||||
static xyz_long_t residual_error;
|
||||
|
||||
#if ENABLED(BACKLASH_GCODE)
|
||||
|
||||
@@ -37,12 +37,12 @@
|
||||
|
||||
LevelingBilinear bedlevel;
|
||||
|
||||
xy_pos_t LevelingBilinear::grid_spacing,
|
||||
LevelingBilinear::grid_start;
|
||||
xy_float_t LevelingBilinear::grid_factor;
|
||||
xy_pos_t LevelingBilinear::grid_spacing,
|
||||
LevelingBilinear::grid_start,
|
||||
LevelingBilinear::cached_rel;
|
||||
xy_int8_t LevelingBilinear::cached_g;
|
||||
bed_mesh_t LevelingBilinear::z_values;
|
||||
xy_pos_t LevelingBilinear::cached_rel;
|
||||
xy_int8_t LevelingBilinear::cached_g;
|
||||
|
||||
/**
|
||||
* Extrapolate a single point from its neighbors
|
||||
@@ -106,9 +106,17 @@ void LevelingBilinear::reset() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set grid spacing and start position
|
||||
*/
|
||||
void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) {
|
||||
grid_spacing = _grid_spacing;
|
||||
grid_start = _grid_start;
|
||||
#if HAS_PROUI_MESH_EDIT
|
||||
grid_spacing.set(MESH_X_DIST, MESH_Y_DIST);
|
||||
grid_start = mesh_min;
|
||||
#else
|
||||
grid_spacing = _grid_spacing;
|
||||
grid_start = _grid_start;
|
||||
#endif
|
||||
grid_factor = grid_spacing.reciprocal();
|
||||
}
|
||||
|
||||
@@ -371,8 +379,8 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) {
|
||||
*/
|
||||
void LevelingBilinear::line_to_destination(const feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) {
|
||||
// Get current and destination cells for this line
|
||||
xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) },
|
||||
c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) };
|
||||
xy_int_t c1 { CELL_INDEX(x, motion.position.x), CELL_INDEX(y, motion.position.y) },
|
||||
c2 { CELL_INDEX(x, motion.destination.x), CELL_INDEX(y, motion.destination.y) };
|
||||
LIMIT(c1.x, 0, ABL_BG_POINTS_X - 2);
|
||||
LIMIT(c1.y, 0, ABL_BG_POINTS_Y - 2);
|
||||
LIMIT(c2.x, 0, ABL_BG_POINTS_X - 2);
|
||||
@@ -380,12 +388,12 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) {
|
||||
|
||||
// Start and end in the same cell? No split needed.
|
||||
if (c1 == c2) {
|
||||
current_position = destination;
|
||||
line_to_current_position(scaled_fr_mm_s);
|
||||
motion.position = motion.destination;
|
||||
motion.goto_current_position(scaled_fr_mm_s);
|
||||
return;
|
||||
}
|
||||
|
||||
#define LINE_SEGMENT_END(A) (current_position.A + (destination.A - current_position.A) * normalized_dist)
|
||||
#define LINE_SEGMENT_END(A) (motion.position.A + (motion.destination.A - motion.position.A) * normalized_dist)
|
||||
|
||||
float normalized_dist;
|
||||
xyze_pos_t end;
|
||||
@@ -396,36 +404,36 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) {
|
||||
if (c2.x != c1.x && TEST(x_splits, gc.x)) {
|
||||
// Split on the X grid line
|
||||
CBI(x_splits, gc.x);
|
||||
end = destination;
|
||||
destination.x = grid_start.x + ABL_BG_SPACING(x) * gc.x;
|
||||
normalized_dist = (destination.x - current_position.x) / (end.x - current_position.x);
|
||||
destination.y = LINE_SEGMENT_END(y);
|
||||
end = motion.destination;
|
||||
motion.destination.x = grid_start.x + ABL_BG_SPACING(x) * gc.x;
|
||||
normalized_dist = (motion.destination.x - motion.position.x) / (end.x - motion.position.x);
|
||||
motion.destination.y = LINE_SEGMENT_END(y);
|
||||
}
|
||||
// Crosses on the Y and not already split on this Y?
|
||||
else if (c2.y != c1.y && TEST(y_splits, gc.y)) {
|
||||
// Split on the Y grid line
|
||||
CBI(y_splits, gc.y);
|
||||
end = destination;
|
||||
destination.y = grid_start.y + ABL_BG_SPACING(y) * gc.y;
|
||||
normalized_dist = (destination.y - current_position.y) / (end.y - current_position.y);
|
||||
destination.x = LINE_SEGMENT_END(x);
|
||||
end = motion.destination;
|
||||
motion.destination.y = grid_start.y + ABL_BG_SPACING(y) * gc.y;
|
||||
normalized_dist = (motion.destination.y - motion.position.y) / (end.y - motion.position.y);
|
||||
motion.destination.x = LINE_SEGMENT_END(x);
|
||||
}
|
||||
else {
|
||||
// Must already have been split on these border(s)
|
||||
// This should be a rare case.
|
||||
current_position = destination;
|
||||
line_to_current_position(scaled_fr_mm_s);
|
||||
motion.position = motion.destination;
|
||||
motion.goto_current_position(scaled_fr_mm_s);
|
||||
return;
|
||||
}
|
||||
|
||||
destination.z = LINE_SEGMENT_END(z);
|
||||
destination.e = LINE_SEGMENT_END(e);
|
||||
motion.destination.z = LINE_SEGMENT_END(z);
|
||||
motion.destination.e = LINE_SEGMENT_END(e);
|
||||
|
||||
// Do the split and look for more borders
|
||||
line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
|
||||
|
||||
// Restore destination from stack
|
||||
destination = end;
|
||||
motion.destination = end;
|
||||
line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,8 +72,8 @@ void BDS_Leveling::init(uint8_t _sda, uint8_t _scl, uint16_t delay_s) {
|
||||
config_state = BDS_IDLE;
|
||||
const int ret = BD_I2C_SENSOR.i2c_init(_sda, _scl, BD_SENSOR_I2C_ADDR, delay_s);
|
||||
if (ret != 1) SERIAL_ECHOLNPGM("BD Sensor Init Fail (", ret, ")");
|
||||
sync_plan_position();
|
||||
pos_zero_offset = planner.get_axis_position_mm(Z_AXIS) - current_position.z;
|
||||
motion.sync_plan_position();
|
||||
pos_zero_offset = planner.get_axis_position_mm(Z_AXIS) - motion.position.z;
|
||||
SERIAL_ECHOLNPGM("BD Sensor Zero Offset:", pos_zero_offset);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ void BDS_Leveling::process() {
|
||||
|
||||
uint16_t tmp = 0;
|
||||
const float cur_z = planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset;
|
||||
static float old_cur_z = cur_z, old_buf_z = current_position.z;
|
||||
static float old_cur_z = cur_z, old_buf_z = motion.position.z;
|
||||
tmp = BD_I2C_SENSOR.BD_i2c_read();
|
||||
if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && good_data(tmp)) {
|
||||
const float z_sensor = interpret(tmp);
|
||||
@@ -127,11 +127,11 @@ void BDS_Leveling::process() {
|
||||
if (config_state > 0) {
|
||||
if (cur_z < config_state * 0.1f
|
||||
&& old_cur_z == cur_z
|
||||
&& old_buf_z == current_position.z
|
||||
&& old_buf_z == motion.position.z
|
||||
&& z_sensor < (MAX_BD_HEIGHT) - 0.1f
|
||||
) {
|
||||
babystep.set_mm(Z_AXIS, cur_z - z_sensor);
|
||||
DEBUG_ECHOLNPGM("BD:", z_sensor, ", Z:", cur_z, "|", current_position.z);
|
||||
DEBUG_ECHOLNPGM("BD:", z_sensor, ", Z:", cur_z, "|", motion.position.z);
|
||||
}
|
||||
else
|
||||
babystep.set_mm(Z_AXIS, 0);
|
||||
@@ -139,7 +139,7 @@ void BDS_Leveling::process() {
|
||||
#endif
|
||||
|
||||
old_cur_z = cur_z;
|
||||
old_buf_z = current_position.z;
|
||||
old_buf_z = motion.position.z;
|
||||
endstops.bdp_state_update(z_sensor <= BD_SENSOR_HOME_Z_POSITION);
|
||||
|
||||
#if HAS_STATUS_MESSAGE
|
||||
@@ -158,7 +158,7 @@ void BDS_Leveling::process() {
|
||||
marlin.kill(F("BDsensor connect Err!"));
|
||||
}
|
||||
|
||||
DEBUG_ECHOLNPGM("BD:", tmp & 0x3FF, " Z:", cur_z, "|", current_position.z);
|
||||
DEBUG_ECHOLNPGM("BD:", tmp & 0x3FF, " Z:", cur_z, "|", motion.position.z);
|
||||
if (TERN0(DEBUG_OUT_BD, BD_I2C_SENSOR.BD_Check_OddEven(tmp) == 0)) DEBUG_ECHOLNPGM("CRC error");
|
||||
|
||||
if (!good_data(tmp)) {
|
||||
@@ -204,15 +204,15 @@ void BDS_Leveling::process() {
|
||||
SERIAL_ECHOLNPGM("c_z0:", planner.get_axis_position_mm(Z_AXIS), "-", pos_zero_offset);
|
||||
|
||||
// Move the z axis instead of enabling the Z axis with M17
|
||||
// TODO: Use do_blocking_move_to_z for synchronized move.
|
||||
current_position.z = 0;
|
||||
sync_plan_position();
|
||||
// TODO: Use motion.blocking_move_z for synchronized move.
|
||||
motion.position.z = 0;
|
||||
motion.sync_plan_position();
|
||||
gcode.process_subcommands_now(F("G1Z0.05"));
|
||||
safe_delay(300);
|
||||
gcode.process_subcommands_now(F("G1Z0.00"));
|
||||
safe_delay(300);
|
||||
current_position.z = 0;
|
||||
sync_plan_position();
|
||||
motion.position.z = 0;
|
||||
motion.sync_plan_position();
|
||||
//safe_delay(1000);
|
||||
|
||||
while ((planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset) > 0.00001f) {
|
||||
@@ -235,10 +235,10 @@ void BDS_Leveling::process() {
|
||||
}
|
||||
else {
|
||||
char tmp_1[32];
|
||||
// TODO: Use prepare_internal_move_to_destination to guarantee machine space
|
||||
// TODO: Use motion.prepare_internal_move_to_destination to guarantee machine space
|
||||
sprintf_P(tmp_1, PSTR("G1Z%d.%d"), int(zpos), int(zpos * 10) % 10);
|
||||
gcode.process_subcommands_now(tmp_1);
|
||||
SERIAL_ECHO(tmp_1); SERIAL_ECHOLNPGM(", Z:", current_position.z);
|
||||
SERIAL_ECHO(tmp_1); SERIAL_ECHOLNPGM(", Z:", motion.position.z);
|
||||
uint16_t failcount = 300;
|
||||
for (float tmp_k = 0; abs(zpos - tmp_k) > 0.006f && failcount--;) {
|
||||
tmp_k = planner.get_axis_position_mm(Z_AXIS) - pos_zero_offset;
|
||||
|
||||
@@ -46,8 +46,18 @@
|
||||
#include "../../lcd/extui/ui_api.h"
|
||||
#endif
|
||||
|
||||
#if ALL(HAS_MESH, DWIN_LCD_PROUI)
|
||||
#include "../../lcd/dwin/proui/bedlevel_tools.h"
|
||||
#endif
|
||||
|
||||
bool leveling_is_valid() {
|
||||
return TERN1(HAS_MESH, bedlevel.mesh_is_valid());
|
||||
return (
|
||||
#if ALL(HAS_MESH, DWIN_LCD_PROUI)
|
||||
bedLevelTools.meshValidate()
|
||||
#else
|
||||
TERN1(HAS_MESH, bedlevel.mesh_is_valid())
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,9 +76,9 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
|
||||
auto _report_leveling = []{
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
if (planner.leveling_active)
|
||||
DEBUG_POS("Leveling ON", current_position);
|
||||
DEBUG_POS("Leveling ON", motion.position);
|
||||
else
|
||||
DEBUG_POS("Leveling OFF", current_position);
|
||||
DEBUG_POS("Leveling OFF", motion.position);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,11 +86,11 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
|
||||
planner.synchronize();
|
||||
|
||||
// Get the corrected leveled / unleveled position
|
||||
planner.apply_modifiers(current_position, true); // Physical position with all modifiers
|
||||
FLIP(planner.leveling_active); // Toggle leveling between apply and unapply
|
||||
planner.unapply_modifiers(current_position, true); // Logical position with modifiers removed
|
||||
planner.apply_modifiers(motion.position, true); // Physical position with all modifiers
|
||||
FLIP(planner.leveling_active); // Toggle leveling between apply and unapply
|
||||
planner.unapply_modifiers(motion.position, true); // Logical position with modifiers removed
|
||||
|
||||
sync_plan_position();
|
||||
motion.sync_plan_position();
|
||||
_report_leveling();
|
||||
}
|
||||
}
|
||||
@@ -101,10 +111,10 @@ TemporaryBedLevelingState::TemporaryBedLevelingState(const bool enable) : saved(
|
||||
planner.set_z_fade_height(zfh);
|
||||
|
||||
if (leveling_was_active) {
|
||||
const xyz_pos_t oldpos = current_position;
|
||||
const xyz_pos_t oldpos = motion.position;
|
||||
set_bed_leveling_enabled(true);
|
||||
if (do_report && oldpos != current_position)
|
||||
report_current_position();
|
||||
if (do_report && oldpos != motion.position)
|
||||
motion.report_position();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,16 +208,16 @@ void reset_bed_level() {
|
||||
#else
|
||||
#warning "It's recommended to set some MANUAL_PROBE_START_Z value for manual leveling."
|
||||
#endif
|
||||
#if Z_CLEARANCE_BETWEEN_MANUAL_PROBES > 0 // A probe/obstacle clearance exists so there is a raise:
|
||||
#if Z_CLEARANCE_BETWEEN_MANUAL_PROBES > 0 // A probe/obstacle clearance exists so there is a raise:
|
||||
#ifndef MANUAL_PROBE_START_Z
|
||||
const float finalz = current_position.z; // - Use the current Z for starting-Z if no MANUAL_PROBE_START_Z was provided
|
||||
const float finalz = motion.position.z; // - Use the current Z for starting-Z if no MANUAL_PROBE_START_Z was provided
|
||||
#endif
|
||||
do_blocking_move_to_xy_z(pos, Z_CLEARANCE_BETWEEN_MANUAL_PROBES); // - Raise Z, then move to the new XY
|
||||
do_blocking_move_to_z(finalz); // - Lower down to the starting Z height, ready for adjustment!
|
||||
#elif defined(MANUAL_PROBE_START_Z) // A starting-Z was provided, but there's no raise:
|
||||
do_blocking_move_to_xy_z(pos, finalz); // - Move in XY then down to the starting Z height, ready for adjustment!
|
||||
#else // Zero raise and no starting Z height either:
|
||||
do_blocking_move_to_xy(pos); // - Move over with no raise, ready for adjustment!
|
||||
motion.blocking_move_xy_z(pos, Z_CLEARANCE_BETWEEN_MANUAL_PROBES); // - Raise Z, then move to the new XY
|
||||
motion.blocking_move_z(finalz); // - Lower down to the starting Z height, ready for adjustment!
|
||||
#elif defined(MANUAL_PROBE_START_Z) // A starting-Z was provided, but there's no raise:
|
||||
motion.blocking_move_xy_z(pos, finalz); // - Move in XY then down to the starting Z height, ready for adjustment!
|
||||
#else // Zero raise and no starting Z height either:
|
||||
motion.blocking_move_xy(pos); // - Move over with no raise, ready for adjustment!
|
||||
#endif
|
||||
|
||||
TERN_(LCD_BED_LEVELING, ui.wait_for_move = false);
|
||||
|
||||
@@ -102,8 +102,8 @@ bool hilbert_curve::search_from(uint8_t x, uint8_t y, hilbert_curve::callback_pt
|
||||
*/
|
||||
bool hilbert_curve::search_from_closest(const xy_pos_t &pos, hilbert_curve::callback_ptr func, void *data) {
|
||||
// Find closest grid intersection
|
||||
const uint8_t grid_x = LROUND(constrain(float(pos.x - (MESH_MIN_X)) / (MESH_X_DIST), 0, (GRID_MAX_POINTS_X) - 1));
|
||||
const uint8_t grid_y = LROUND(constrain(float(pos.y - (MESH_MIN_Y)) / (MESH_Y_DIST), 0, (GRID_MAX_POINTS_Y) - 1));
|
||||
const uint8_t grid_x = LROUND(constrain((pos.x - mesh_min.x) / (MESH_X_DIST), 0, (GRID_MAX_POINTS_X) - 1));
|
||||
const uint8_t grid_y = LROUND(constrain((pos.y - mesh_min.y) / (MESH_Y_DIST), 0, (GRID_MAX_POINTS_Y) - 1));
|
||||
return search_from(grid_x, grid_y, func, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,14 +39,21 @@
|
||||
mesh_bed_leveling::index_to_xpos[GRID_MAX_POINTS_X],
|
||||
mesh_bed_leveling::index_to_ypos[GRID_MAX_POINTS_Y];
|
||||
|
||||
mesh_bed_leveling::mesh_bed_leveling() {
|
||||
mesh_bed_leveling::mesh_bed_leveling() { initialize(); }
|
||||
|
||||
void mesh_bed_leveling::initialize() {
|
||||
for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i)
|
||||
index_to_xpos[i] = MESH_MIN_X + i * (MESH_X_DIST);
|
||||
index_to_xpos[i] = mesh_min.x + i * (MESH_X_DIST);
|
||||
for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; ++i)
|
||||
index_to_ypos[i] = MESH_MIN_Y + i * (MESH_Y_DIST);
|
||||
index_to_ypos[i] = mesh_min.y + i * (MESH_Y_DIST);
|
||||
reset();
|
||||
}
|
||||
|
||||
void mesh_bed_leveling::report_mesh() {
|
||||
SERIAL_ECHOLN(F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: "), p_float_t(z_offset, 5), F("\nMeasured points:"));
|
||||
print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, z_values[0]);
|
||||
}
|
||||
|
||||
void mesh_bed_leveling::reset() {
|
||||
z_offset = 0;
|
||||
ZERO(z_values);
|
||||
@@ -63,7 +70,7 @@
|
||||
*/
|
||||
void mesh_bed_leveling::line_to_destination(const feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) {
|
||||
// Get current and destination cells for this line
|
||||
xy_uint8_t scel = cell_indexes(current_position), ecel = cell_indexes(destination);
|
||||
xy_uint8_t scel = cell_indexes(motion.position), ecel = cell_indexes(motion.destination);
|
||||
NOMORE(scel.x, GRID_MAX_CELLS_X - 1);
|
||||
NOMORE(scel.y, GRID_MAX_CELLS_Y - 1);
|
||||
NOMORE(ecel.x, GRID_MAX_CELLS_X - 1);
|
||||
@@ -71,12 +78,12 @@
|
||||
|
||||
// Start and end in the same cell? No split needed.
|
||||
if (scel == ecel) {
|
||||
current_position = destination;
|
||||
line_to_current_position(scaled_fr_mm_s);
|
||||
motion.position = motion.destination;
|
||||
motion.goto_current_position(scaled_fr_mm_s);
|
||||
return;
|
||||
}
|
||||
|
||||
#define MBL_SEGMENT_END(A) (current_position.A + (destination.A - current_position.A) * normalized_dist)
|
||||
#define MBL_SEGMENT_END(A) (motion.position.A + (motion.destination.A - motion.position.A) * normalized_dist)
|
||||
|
||||
float normalized_dist;
|
||||
xyze_pos_t dest;
|
||||
@@ -87,44 +94,39 @@
|
||||
if (ecel.x != scel.x && TEST(x_splits, gcx)) {
|
||||
// Split on the X grid line
|
||||
CBI(x_splits, gcx);
|
||||
dest = destination;
|
||||
destination.x = index_to_xpos[gcx];
|
||||
normalized_dist = (destination.x - current_position.x) / (dest.x - current_position.x);
|
||||
destination.y = MBL_SEGMENT_END(y);
|
||||
dest = motion.destination;
|
||||
motion.destination.x = index_to_xpos[gcx];
|
||||
normalized_dist = (motion.destination.x - motion.position.x) / (dest.x - motion.position.x);
|
||||
motion.destination.y = MBL_SEGMENT_END(y);
|
||||
}
|
||||
// Crosses on the Y and not already split on this Y?
|
||||
else if (ecel.y != scel.y && TEST(y_splits, gcy)) {
|
||||
// Split on the Y grid line
|
||||
CBI(y_splits, gcy);
|
||||
dest = destination;
|
||||
destination.y = index_to_ypos[gcy];
|
||||
normalized_dist = (destination.y - current_position.y) / (dest.y - current_position.y);
|
||||
destination.x = MBL_SEGMENT_END(x);
|
||||
dest = motion.destination;
|
||||
motion.destination.y = index_to_ypos[gcy];
|
||||
normalized_dist = (motion.destination.y - motion.position.y) / (dest.y - motion.position.y);
|
||||
motion.destination.x = MBL_SEGMENT_END(x);
|
||||
}
|
||||
else {
|
||||
// Must already have been split on these border(s)
|
||||
// This should be a rare case.
|
||||
current_position = destination;
|
||||
line_to_current_position(scaled_fr_mm_s);
|
||||
motion.position = motion.destination;
|
||||
motion.goto_current_position(scaled_fr_mm_s);
|
||||
return;
|
||||
}
|
||||
|
||||
destination.z = MBL_SEGMENT_END(z);
|
||||
destination.e = MBL_SEGMENT_END(e);
|
||||
motion.destination.z = MBL_SEGMENT_END(z);
|
||||
motion.destination.e = MBL_SEGMENT_END(e);
|
||||
|
||||
// Do the split and look for more borders
|
||||
line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
|
||||
|
||||
// Restore destination from stack
|
||||
destination = dest;
|
||||
motion.destination = dest;
|
||||
line_to_destination(scaled_fr_mm_s, x_splits, y_splits);
|
||||
}
|
||||
|
||||
#endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES
|
||||
|
||||
void mesh_bed_leveling::report_mesh() {
|
||||
SERIAL_ECHOLN(F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: "), p_float_t(z_offset, 5), F("\nMeasured points:"));
|
||||
print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, z_values[0]);
|
||||
}
|
||||
|
||||
#endif // MESH_BED_LEVELING
|
||||
|
||||
@@ -32,8 +32,7 @@ enum MeshLevelingState : char {
|
||||
MeshReset // G29 S5
|
||||
};
|
||||
|
||||
#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X))
|
||||
#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y))
|
||||
#include "../../../module/motion.h"
|
||||
|
||||
class mesh_bed_leveling {
|
||||
public:
|
||||
@@ -44,10 +43,12 @@ public:
|
||||
|
||||
mesh_bed_leveling();
|
||||
|
||||
static void report_mesh();
|
||||
|
||||
static void reset();
|
||||
|
||||
static void initialize();
|
||||
|
||||
static void report_mesh();
|
||||
|
||||
FORCE_INLINE static bool has_mesh() {
|
||||
GRID_LOOP(x, y) if (z_values[x][y]) return true;
|
||||
return false;
|
||||
@@ -73,11 +74,11 @@ public:
|
||||
static float get_mesh_y(const uint8_t i) { return index_to_ypos[i]; }
|
||||
|
||||
static uint8_t cell_index_x(const float x) {
|
||||
int8_t cx = (x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST);
|
||||
const int8_t cx = (x - mesh_min.x) * RECIPROCAL(MESH_X_DIST);
|
||||
return constrain(cx, 0, GRID_MAX_CELLS_X - 1);
|
||||
}
|
||||
static uint8_t cell_index_y(const float y) {
|
||||
int8_t cy = (y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST);
|
||||
const int8_t cy = (y - mesh_min.y) * RECIPROCAL(MESH_Y_DIST);
|
||||
return constrain(cy, 0, GRID_MAX_CELLS_Y - 1);
|
||||
}
|
||||
static xy_uint8_t cell_indexes(const float x, const float y) {
|
||||
@@ -86,11 +87,11 @@ public:
|
||||
static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); }
|
||||
|
||||
static int8_t probe_index_x(const float x) {
|
||||
int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST);
|
||||
const int8_t px = (x - mesh_min.x + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST);
|
||||
return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1;
|
||||
}
|
||||
static int8_t probe_index_y(const float y) {
|
||||
int8_t py = (y - (MESH_MIN_Y) + 0.5f * (MESH_Y_DIST)) * RECIPROCAL(MESH_Y_DIST);
|
||||
const int8_t py = (y - mesh_min.y + 0.5f * (MESH_Y_DIST)) * RECIPROCAL(MESH_Y_DIST);
|
||||
return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1;
|
||||
}
|
||||
static xy_int8_t probe_indexes(const float x, const float y) {
|
||||
|
||||
@@ -63,23 +63,25 @@ void unified_bed_leveling::report_state() {
|
||||
|
||||
int8_t unified_bed_leveling::storage_slot;
|
||||
|
||||
float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||
bed_mesh_t unified_bed_leveling::z_values;
|
||||
|
||||
#define _GRIDPOS(A,N) (MESH_MIN_##A + N * (MESH_##A##_DIST))
|
||||
#if !HAS_PROUI_MESH_EDIT
|
||||
#define _GRIDPOS(A,N) (MESH_MIN_##A + N * (MESH_##A##_DIST))
|
||||
|
||||
const float
|
||||
unified_bed_leveling::_mesh_index_to_xpos[GRID_MAX_POINTS_X] PROGMEM = ARRAY_N(GRID_MAX_POINTS_X,
|
||||
_GRIDPOS(X, 0), _GRIDPOS(X, 1), _GRIDPOS(X, 2), _GRIDPOS(X, 3),
|
||||
_GRIDPOS(X, 4), _GRIDPOS(X, 5), _GRIDPOS(X, 6), _GRIDPOS(X, 7),
|
||||
_GRIDPOS(X, 8), _GRIDPOS(X, 9), _GRIDPOS(X, 10), _GRIDPOS(X, 11),
|
||||
_GRIDPOS(X, 12), _GRIDPOS(X, 13), _GRIDPOS(X, 14), _GRIDPOS(X, 15)
|
||||
),
|
||||
unified_bed_leveling::_mesh_index_to_ypos[GRID_MAX_POINTS_Y] PROGMEM = ARRAY_N(GRID_MAX_POINTS_Y,
|
||||
_GRIDPOS(Y, 0), _GRIDPOS(Y, 1), _GRIDPOS(Y, 2), _GRIDPOS(Y, 3),
|
||||
_GRIDPOS(Y, 4), _GRIDPOS(Y, 5), _GRIDPOS(Y, 6), _GRIDPOS(Y, 7),
|
||||
_GRIDPOS(Y, 8), _GRIDPOS(Y, 9), _GRIDPOS(Y, 10), _GRIDPOS(Y, 11),
|
||||
_GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15)
|
||||
);
|
||||
const float
|
||||
unified_bed_leveling::_mesh_index_to_xpos[GRID_MAX_POINTS_X] PROGMEM = ARRAY_N(GRID_MAX_POINTS_X,
|
||||
_GRIDPOS(X, 0), _GRIDPOS(X, 1), _GRIDPOS(X, 2), _GRIDPOS(X, 3),
|
||||
_GRIDPOS(X, 4), _GRIDPOS(X, 5), _GRIDPOS(X, 6), _GRIDPOS(X, 7),
|
||||
_GRIDPOS(X, 8), _GRIDPOS(X, 9), _GRIDPOS(X, 10), _GRIDPOS(X, 11),
|
||||
_GRIDPOS(X, 12), _GRIDPOS(X, 13), _GRIDPOS(X, 14), _GRIDPOS(X, 15)
|
||||
),
|
||||
unified_bed_leveling::_mesh_index_to_ypos[GRID_MAX_POINTS_Y] PROGMEM = ARRAY_N(GRID_MAX_POINTS_Y,
|
||||
_GRIDPOS(Y, 0), _GRIDPOS(Y, 1), _GRIDPOS(Y, 2), _GRIDPOS(Y, 3),
|
||||
_GRIDPOS(Y, 4), _GRIDPOS(Y, 5), _GRIDPOS(Y, 6), _GRIDPOS(Y, 7),
|
||||
_GRIDPOS(Y, 8), _GRIDPOS(Y, 9), _GRIDPOS(Y, 10), _GRIDPOS(Y, 11),
|
||||
_GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15)
|
||||
);
|
||||
#endif
|
||||
|
||||
volatile int16_t unified_bed_leveling::encoder_diff;
|
||||
|
||||
@@ -93,7 +95,7 @@ void unified_bed_leveling::reset() {
|
||||
#if ENABLED(EXTENSIBLE_UI)
|
||||
GRID_LOOP(x, y) ExtUI::onMeshUpdate(x, y, 0);
|
||||
#endif
|
||||
if (was_enabled) report_current_position();
|
||||
if (was_enabled) motion.report_position();
|
||||
}
|
||||
|
||||
void unified_bed_leveling::invalidate() {
|
||||
@@ -173,8 +175,8 @@ void unified_bed_leveling::display_map(const uint8_t map_type) {
|
||||
SERIAL_ECHOPGM("\nBed Topography Report");
|
||||
if (human) {
|
||||
SERIAL_ECHOLNPGM(":\n");
|
||||
serial_echo_xy(4, MESH_MIN_X, MESH_MAX_Y);
|
||||
serial_echo_xy(twixt, MESH_MAX_X, MESH_MAX_Y);
|
||||
serial_echo_xy(4, mesh_min.x, mesh_max.y);
|
||||
serial_echo_xy(twixt, mesh_max.x, mesh_max.y);
|
||||
SERIAL_EOL();
|
||||
serial_echo_column_labels(eachsp - 2);
|
||||
}
|
||||
@@ -184,7 +186,7 @@ void unified_bed_leveling::display_map(const uint8_t map_type) {
|
||||
// Add XY probe offset from extruder because probe.probe_at_point() subtracts them when
|
||||
// moving to the XY position to be measured. This ensures better agreement between
|
||||
// the current Z position after G28 and the mesh values.
|
||||
const xy_int8_t curr = closest_indexes(xy_pos_t(current_position) + probe.offset_xy);
|
||||
const xy_int8_t curr = closest_indexes(xy_pos_t(motion.position) + probe.offset_xy);
|
||||
|
||||
if (!lcd) SERIAL_EOL();
|
||||
for (int8_t j = (GRID_MAX_POINTS_Y) - 1; j >= 0; j--) {
|
||||
@@ -207,6 +209,7 @@ void unified_bed_leveling::display_map(const uint8_t map_type) {
|
||||
const float f = z_values[i][j];
|
||||
if (lcd) {
|
||||
// TODO: Display on Graphical LCD
|
||||
TERN_(DWIN_LCD_PROUI, dwinMeshViewer());
|
||||
}
|
||||
else if (isnan(f))
|
||||
SERIAL_ECHO(human ? F(" . ") : F("NAN"));
|
||||
@@ -231,8 +234,8 @@ void unified_bed_leveling::display_map(const uint8_t map_type) {
|
||||
if (human) {
|
||||
serial_echo_column_labels(eachsp - 2);
|
||||
SERIAL_EOL();
|
||||
serial_echo_xy(4, MESH_MIN_X, MESH_MIN_Y);
|
||||
serial_echo_xy(twixt, MESH_MAX_X, MESH_MIN_Y);
|
||||
serial_echo_xy(4, mesh_min.x, mesh_min.y);
|
||||
serial_echo_xy(twixt, mesh_max.x, mesh_min.y);
|
||||
SERIAL_EOL();
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
@@ -38,9 +38,6 @@ enum MeshPointType : char { INVALID, REAL, SET_IN_BITMAP, CLOSEST };
|
||||
|
||||
struct mesh_index_pair;
|
||||
|
||||
#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X))
|
||||
#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y))
|
||||
|
||||
#if ENABLED(OPTIMIZED_MESH_STORAGE)
|
||||
typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||
#endif
|
||||
@@ -83,6 +80,16 @@ private:
|
||||
return smart_fill_one(pos.x, pos.y, dir.x, dir.y);
|
||||
}
|
||||
|
||||
// G29 sub-function handlers
|
||||
static void G29_handle_homing_and_setup();
|
||||
static void G29_handle_invalidate();
|
||||
static bool G29_handle_test_patterns();
|
||||
#if HAS_BED_PROBE
|
||||
static void G29_handle_tilt_mesh();
|
||||
#endif
|
||||
static bool G29_handle_phase_ops();
|
||||
static void G29_handle_post_processing();
|
||||
|
||||
#if ENABLED(UBL_DEVEL_DEBUGGING)
|
||||
static void g29_what_command();
|
||||
static void g29_eeprom_dump();
|
||||
@@ -116,8 +123,11 @@ public:
|
||||
static void set_store_from_mesh(const bed_mesh_t &in_values, mesh_store_t &stored_values);
|
||||
static void set_mesh_from_store(const mesh_store_t &stored_values, bed_mesh_t &out_values);
|
||||
#endif
|
||||
static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X],
|
||||
_mesh_index_to_ypos[GRID_MAX_POINTS_Y];
|
||||
|
||||
#if !HAS_PROUI_MESH_EDIT
|
||||
static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X],
|
||||
_mesh_index_to_ypos[GRID_MAX_POINTS_Y];
|
||||
#endif
|
||||
|
||||
#if HAS_MARLINUI_MENU
|
||||
static bool lcd_map_control;
|
||||
@@ -133,11 +143,11 @@ public:
|
||||
FORCE_INLINE static void set_z(const int8_t px, const int8_t py, const float z) { z_values[px][py] = z; }
|
||||
|
||||
static int8_t cell_index_x_raw(const float x) {
|
||||
return FLOOR((x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST));
|
||||
return FLOOR((x - mesh_min.x) * RECIPROCAL(MESH_X_DIST));
|
||||
}
|
||||
|
||||
static int8_t cell_index_y_raw(const float y) {
|
||||
return FLOOR((y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST));
|
||||
return FLOOR((y - mesh_min.y) * RECIPROCAL(MESH_Y_DIST));
|
||||
}
|
||||
|
||||
static bool cell_index_x_valid(const float x) {
|
||||
@@ -162,11 +172,11 @@ public:
|
||||
static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); }
|
||||
|
||||
static int8_t closest_x_index(const float x) {
|
||||
const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST);
|
||||
const int8_t px = (x - mesh_min.x + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST);
|
||||
return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1;
|
||||
}
|
||||
static int8_t closest_y_index(const float y) {
|
||||
const int8_t py = (y - (MESH_MIN_Y) + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST);
|
||||
const int8_t py = (y - mesh_min.y + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST);
|
||||
return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1;
|
||||
}
|
||||
static xy_int8_t closest_indexes(const xy_pos_t &xy) {
|
||||
@@ -259,7 +269,7 @@ public:
|
||||
* UBL_Z_RAISE_WHEN_OFF_MESH is specified, that value is returned.
|
||||
*/
|
||||
#ifdef UBL_Z_RAISE_WHEN_OFF_MESH
|
||||
if (!WITHIN(rx0, MESH_MIN_X, MESH_MAX_X) || !WITHIN(ry0, MESH_MIN_Y, MESH_MAX_Y))
|
||||
if (!WITHIN(rx0, mesh_min.x, mesh_max.x) || !WITHIN(ry0, mesh_min.y, mesh_max.y))
|
||||
return UBL_Z_RAISE_WHEN_OFF_MESH;
|
||||
#endif
|
||||
|
||||
@@ -287,12 +297,20 @@ public:
|
||||
|
||||
static constexpr float get_z_offset() { return 0.0f; }
|
||||
|
||||
static float get_mesh_x(const uint8_t i) {
|
||||
return i < (GRID_MAX_POINTS_X) ? pgm_read_float(&_mesh_index_to_xpos[i]) : MESH_MIN_X + i * (MESH_X_DIST);
|
||||
}
|
||||
static float get_mesh_y(const uint8_t i) {
|
||||
return i < (GRID_MAX_POINTS_Y) ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST);
|
||||
}
|
||||
static float _get_mesh_x(const uint8_t i) { return mesh_min.x + i * (MESH_X_DIST); }
|
||||
static float _get_mesh_y(const uint8_t i) { return mesh_min.y + i * (MESH_Y_DIST); }
|
||||
|
||||
#if HAS_PROUI_MESH_EDIT
|
||||
static float get_mesh_x(const uint8_t i) { return _get_mesh_x(i); }
|
||||
static float get_mesh_y(const uint8_t i) { return _get_mesh_y(i); }
|
||||
#else
|
||||
static float get_mesh_x(const uint8_t i) {
|
||||
return i < (GRID_MAX_POINTS_X) ? pgm_read_float(&_mesh_index_to_xpos[i]) : _get_mesh_x(i);
|
||||
}
|
||||
static float get_mesh_y(const uint8_t i) {
|
||||
return i < (GRID_MAX_POINTS_Y) ? pgm_read_float(&_mesh_index_to_ypos[i]) : _get_mesh_y(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UBL_SEGMENTED
|
||||
static bool line_to_destination_segmented(const feedRate_t scaled_fr_mm_s);
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
#include "../../../lcd/extui/ui_api.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(DWIN_LCD_PROUI)
|
||||
#include "../../../lcd/dwin/proui/meshviewer.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(UBL_HILBERT_CURVE)
|
||||
#include "../hilbert_curve.h"
|
||||
#endif
|
||||
@@ -315,305 +319,31 @@ void unified_bed_leveling::G29() {
|
||||
// Potentially disable Fixed-Time Motion for probing
|
||||
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
|
||||
|
||||
// Check for commands that require the printer to be homed
|
||||
if (may_move) {
|
||||
planner.synchronize();
|
||||
#if ALL(DWIN_LCD_PROUI, ZHOME_BEFORE_LEVELING)
|
||||
save_ubl_active_state_and_disable();
|
||||
gcode.process_subcommands_now(F("G28Z"));
|
||||
restore_ubl_active_state(false); // ...without telling ExtUI "done"
|
||||
#else
|
||||
// Send 'N' to force homing before G29 (internal only)
|
||||
if (axes_should_home() || parser.seen_test('N')) gcode.home_all_axes();
|
||||
#endif
|
||||
probe.use_probing_tool();
|
||||
// Handle homing and initial setup
|
||||
if (may_move) G29_handle_homing_and_setup();
|
||||
|
||||
#ifdef EVENT_GCODE_BEFORE_G29
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29);
|
||||
gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29));
|
||||
#endif
|
||||
// Handle mesh invalidation (I parameter)
|
||||
if (parser.seen('I')) G29_handle_invalidate();
|
||||
|
||||
// Position bed horizontally and Z probe vertically.
|
||||
#if HAS_SAFE_BED_LEVELING
|
||||
xyze_pos_t safe_position = current_position;
|
||||
#ifdef SAFE_BED_LEVELING_START_X
|
||||
safe_position.x = SAFE_BED_LEVELING_START_X;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_Y
|
||||
safe_position.y = SAFE_BED_LEVELING_START_Y;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_Z
|
||||
safe_position.z = SAFE_BED_LEVELING_START_Z;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_I
|
||||
safe_position.i = SAFE_BED_LEVELING_START_I;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_J
|
||||
safe_position.j = SAFE_BED_LEVELING_START_J;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_K
|
||||
safe_position.k = SAFE_BED_LEVELING_START_K;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_U
|
||||
safe_position.u = SAFE_BED_LEVELING_START_U;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_V
|
||||
safe_position.v = SAFE_BED_LEVELING_START_V;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_W
|
||||
safe_position.w = SAFE_BED_LEVELING_START_W;
|
||||
#endif
|
||||
|
||||
do_blocking_move_to(safe_position);
|
||||
#endif // HAS_SAFE_BED_LEVELING
|
||||
}
|
||||
|
||||
// Invalidate one or more nearby mesh points, possibly all.
|
||||
if (parser.seen('I')) {
|
||||
grid_count_t count = parser.has_value() ? parser.value_ushort() : 1;
|
||||
bool invalidate_all = count >= GRID_MAX_POINTS;
|
||||
if (!invalidate_all) {
|
||||
while (count--) {
|
||||
if ((count & 0x0F) == 0x0F) marlin.idle();
|
||||
const mesh_index_pair closest = find_closest_mesh_point_of_type(REAL, param.XY_pos);
|
||||
// No more REAL mesh points to invalidate? Assume the user meant
|
||||
// to invalidate the ENTIRE mesh, which can't be done with
|
||||
// find_closest_mesh_point (which only returns REAL points).
|
||||
if (closest.pos.x < 0) { invalidate_all = true; break; }
|
||||
z_values[closest.pos.x][closest.pos.y] = NAN;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(closest.pos, 0.0f));
|
||||
}
|
||||
}
|
||||
if (invalidate_all) {
|
||||
invalidate();
|
||||
SERIAL_ECHOPGM("Entire Mesh");
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOPGM("Locations");
|
||||
SERIAL_ECHOLNPGM(" invalidated.\n");
|
||||
}
|
||||
|
||||
if (parser.seen('Q')) {
|
||||
const int16_t test_pattern = parser.has_value() ? parser.value_int() : -99;
|
||||
if (!WITHIN(test_pattern, TERN0(UBL_DEVEL_DEBUGGING, -1), 2)) {
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("(Q) test pattern. (" TERN(UBL_DEVEL_DEBUGGING, "-1", "0") " to 2)\n"));
|
||||
return;
|
||||
}
|
||||
SERIAL_ECHOLNPGM("Applying test pattern.\n");
|
||||
switch (test_pattern) {
|
||||
|
||||
default:
|
||||
case -1: TERN_(UBL_DEVEL_DEBUGGING, g29_eeprom_dump()); break;
|
||||
|
||||
case 0:
|
||||
GRID_LOOP(x, y) { // Create a bowl shape similar to a poorly-calibrated Delta
|
||||
const float p1 = 0.5f * (GRID_MAX_POINTS_X) - x,
|
||||
p2 = 0.5f * (GRID_MAX_POINTS_Y) - y;
|
||||
z_values[x][y] += 2.0f * HYPOT(p1, p2);
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; ++x) { // Create a diagonal line several Mesh cells thick that is raised
|
||||
const uint8_t x2 = x + (x < (GRID_MAX_POINTS_Y) - 1 ? 1 : -1);
|
||||
z_values[x][x] += 9.999f;
|
||||
z_values[x][x2] += 9.999f; // We want the altered line several mesh points thick
|
||||
#if ENABLED(EXTENSIBLE_UI)
|
||||
ExtUI::onMeshUpdate(x, x, z_values[x][x]);
|
||||
ExtUI::onMeshUpdate(x, x2, z_values[x][x2]);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Allow the user to specify the height because 10mm is a little extreme in some cases.
|
||||
for (uint8_t x = (GRID_MAX_POINTS_X) / 3; x < 2 * (GRID_MAX_POINTS_X) / 3; x++) // Create a rectangular raised area in
|
||||
for (uint8_t y = (GRID_MAX_POINTS_Y) / 3; y < 2 * (GRID_MAX_POINTS_Y) / 3; y++) { // the center of the bed
|
||||
z_values[x][y] += parser.seen_test('C') ? param.C_constant : 9.99f;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Handle test patterns (Q parameter)
|
||||
if (parser.seen('Q') && !G29_handle_test_patterns()) return;
|
||||
|
||||
// Handle tilt mesh (J parameter)
|
||||
#if HAS_BED_PROBE
|
||||
if (parser.seen_test('J')) G29_handle_tilt_mesh();
|
||||
#endif
|
||||
|
||||
if (parser.seen_test('J')) {
|
||||
save_ubl_active_state_and_disable();
|
||||
tilt_mesh_based_on_probed_grid(param.J_grid_size == 0); // Zero size does 3-Point
|
||||
restore_ubl_active_state();
|
||||
#if ENABLED(UBL_G29_J_RECENTER)
|
||||
do_blocking_move_to_xy(0.5f * ((MESH_MIN_X) + (MESH_MAX_X)), 0.5f * ((MESH_MIN_Y) + (MESH_MAX_Y)));
|
||||
#endif
|
||||
report_current_position();
|
||||
SET_PROBE_DEPLOYED(true);
|
||||
}
|
||||
// Handle phase operations (P parameter)
|
||||
if (parser.seen_test('P') && !G29_handle_phase_ops()) return;
|
||||
|
||||
#endif // HAS_BED_PROBE
|
||||
|
||||
if (parser.seen_test('P')) {
|
||||
if (WITHIN(param.P_phase, 0, 1) && storage_slot == -1) {
|
||||
storage_slot = 0;
|
||||
SERIAL_ECHOLNPGM("Default storage slot 0 selected.");
|
||||
}
|
||||
|
||||
switch (param.P_phase) {
|
||||
case 0:
|
||||
//
|
||||
// Zero Mesh Data
|
||||
//
|
||||
reset();
|
||||
SERIAL_ECHOLNPGM("Mesh zeroed.");
|
||||
break;
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
|
||||
case 1: {
|
||||
//
|
||||
// Invalidate Entire Mesh and Automatically Probe Mesh in areas that can be reached by the probe
|
||||
//
|
||||
if (!parser.seen_test('C')) {
|
||||
invalidate();
|
||||
SERIAL_ECHOLNPGM("Mesh invalidated. Probing mesh.");
|
||||
}
|
||||
if (param.V_verbosity > 1)
|
||||
SERIAL_ECHOLN(F("Probing around ("), param.XY_pos.x, C(','), param.XY_pos.y, F(").\n"));
|
||||
probe_entire_mesh(param.XY_pos, parser.seen_test('T'), parser.seen_test('E'), parser.seen_test('U'));
|
||||
|
||||
report_current_position();
|
||||
SET_PROBE_DEPLOYED(true);
|
||||
} break;
|
||||
|
||||
#endif // HAS_BED_PROBE
|
||||
|
||||
case 2: {
|
||||
#if HAS_MARLINUI_MENU
|
||||
//
|
||||
// Manually Probe Mesh in areas that can't be reached by the probe
|
||||
//
|
||||
SERIAL_ECHOLNPGM("Manually probing unreachable points.");
|
||||
do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
|
||||
|
||||
if (parser.seen_test('C') && !param.XY_seen) {
|
||||
|
||||
/**
|
||||
* Use a good default location for the path.
|
||||
* The flipped > and < operators in these comparisons is intentional.
|
||||
* It should cause the probed points to follow a nice path on Cartesian printers.
|
||||
* It may make sense to have Delta printers default to the center of the bed.
|
||||
* Until that is decided, this can be forced with the X and Y parameters.
|
||||
*/
|
||||
param.XY_pos.set(
|
||||
#if IS_KINEMATIC
|
||||
X_HOME_POS, Y_HOME_POS
|
||||
#else
|
||||
probe.offset_xy.x > 0 ? X_BED_SIZE : 0,
|
||||
probe.offset_xy.y < 0 ? Y_BED_SIZE : 0
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
if (parser.seen('B')) {
|
||||
param.B_shim_thickness = parser.has_value() ? parser.value_float() : measure_business_card_thickness();
|
||||
if (ABS(param.B_shim_thickness) > 1.5f) {
|
||||
SERIAL_ECHOLNPGM("?Error in Business Card measurement.");
|
||||
return;
|
||||
}
|
||||
SET_PROBE_DEPLOYED(true);
|
||||
}
|
||||
|
||||
if (!position_is_reachable(param.XY_pos)) {
|
||||
SERIAL_ECHOLNPGM("XY outside printable radius.");
|
||||
return;
|
||||
}
|
||||
|
||||
const float height = parser.floatval('H', Z_CLEARANCE_BETWEEN_PROBES);
|
||||
manually_probe_remaining_mesh(param.XY_pos, height, param.B_shim_thickness, parser.seen_test('T'));
|
||||
|
||||
SERIAL_ECHOLNPGM("G29 P2 finished.");
|
||||
|
||||
report_current_position();
|
||||
|
||||
#else
|
||||
|
||||
SERIAL_ECHOLNPGM("?P2 is only available when an LCD is present.");
|
||||
return;
|
||||
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
/**
|
||||
* Populate invalid mesh areas. Proceed with caution.
|
||||
* Two choices are available:
|
||||
* - Specify a constant with the 'C' parameter.
|
||||
* - Allow 'G29 P3' to choose a 'reasonable' constant.
|
||||
*/
|
||||
|
||||
if (param.C_seen) {
|
||||
if (param.R_repetition >= GRID_MAX_POINTS) {
|
||||
set_all_mesh_points_to_value(param.C_constant);
|
||||
}
|
||||
else {
|
||||
while (param.R_repetition--) { // this only populates reachable mesh points near
|
||||
const mesh_index_pair closest = find_closest_mesh_point_of_type(INVALID, param.XY_pos);
|
||||
const xy_int8_t &cpos = closest.pos;
|
||||
if (cpos.x < 0) {
|
||||
// No more REAL INVALID mesh points to populate, so we ASSUME
|
||||
// user meant to populate ALL INVALID mesh points to value
|
||||
GRID_LOOP(x, y) if (isnan(z_values[x][y])) z_values[x][y] = param.C_constant;
|
||||
break; // No more invalid Mesh Points to populate
|
||||
}
|
||||
else {
|
||||
z_values[cpos.x][cpos.y] = param.C_constant;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(cpos, param.C_constant));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float cvf = parser.value_float();
|
||||
switch ((int)TRUNC(cvf * 10.0f) - 30) { // 3.1 -> 1
|
||||
#if ENABLED(UBL_G29_P31)
|
||||
case 1: {
|
||||
|
||||
// P3.1 use least squares fit to fill missing mesh values
|
||||
// P3.10 zero weighting for distance, all grid points equal, best fit tilted plane
|
||||
// P3.11 10X weighting for nearest grid points versus farthest grid points
|
||||
// P3.12 100X distance weighting
|
||||
// P3.13 1000X distance weighting, approaches simple average of nearest points
|
||||
|
||||
const float weight_power = (cvf - 3.10f) * 100.0f, // 3.12345 -> 2.345
|
||||
weight_factor = weight_power ? POW(10.0f, weight_power) : 0;
|
||||
smart_fill_wlsf(weight_factor);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 0: // P3 or P3.0
|
||||
default: // and anything P3.x that's not P3.1
|
||||
smart_fill_mesh(); // Do a 'Smart' fill using nearby known values
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // Fine Tune (i.e., Edit) the Mesh
|
||||
#if HAS_MARLINUI_MENU
|
||||
fine_tune_mesh(param.XY_pos, parser.seen_test('T'));
|
||||
#else
|
||||
SERIAL_ECHOLNPGM("?P4 is only available when an LCD is present.");
|
||||
return;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 5: adjust_mesh_to_mean(param.C_seen, param.C_constant); break;
|
||||
|
||||
case 6: shift_mesh_height(param.C_constant); break;
|
||||
}
|
||||
}
|
||||
// Handle post-processing and cleanup
|
||||
G29_handle_post_processing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle post-processing and cleanup
|
||||
*/
|
||||
void unified_bed_leveling::G29_handle_post_processing() {
|
||||
#if ENABLED(UBL_DEVEL_DEBUGGING)
|
||||
|
||||
//
|
||||
@@ -661,7 +391,7 @@ void unified_bed_leveling::G29() {
|
||||
// Store a Mesh in the EEPROM
|
||||
//
|
||||
|
||||
if (parser.seen('S')) { // Store (or Save) Current Mesh Data
|
||||
else if (parser.seen('S')) { // Store (or Save) Current Mesh Data
|
||||
param.KLS_storage_slot = parser.has_value() ? (int8_t)parser.value_int() : storage_slot;
|
||||
|
||||
if (param.KLS_storage_slot == -1) // Special case: 'Export' the mesh to the
|
||||
@@ -706,7 +436,337 @@ void unified_bed_leveling::G29() {
|
||||
#endif
|
||||
|
||||
probe.use_probing_tool(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle phase operations (P parameter)
|
||||
* @return true if successful, false if error occurred
|
||||
*/
|
||||
bool unified_bed_leveling::G29_handle_phase_ops() {
|
||||
if (WITHIN(param.P_phase, 0, 1) && storage_slot == -1) {
|
||||
storage_slot = 0;
|
||||
SERIAL_ECHOLNPGM("Default storage slot 0 selected.");
|
||||
}
|
||||
|
||||
switch (param.P_phase) {
|
||||
case 0:
|
||||
//
|
||||
// Zero Mesh Data
|
||||
//
|
||||
reset();
|
||||
SERIAL_ECHOLNPGM("Mesh zeroed.");
|
||||
break;
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
|
||||
case 1: {
|
||||
//
|
||||
// Invalidate Entire Mesh and Automatically Probe Mesh in areas that can be reached by the probe
|
||||
//
|
||||
if (!parser.seen_test('C')) {
|
||||
invalidate();
|
||||
SERIAL_ECHOLNPGM("Mesh invalidated. Probing mesh.");
|
||||
}
|
||||
if (param.V_verbosity > 1)
|
||||
SERIAL_ECHOLN(F("Probing around ("), param.XY_pos.x, C(','), param.XY_pos.y, F(").\n"));
|
||||
probe_entire_mesh(param.XY_pos, parser.seen_test('T'), parser.seen_test('E'), parser.seen_test('U'));
|
||||
|
||||
motion.report_position();
|
||||
SET_PROBE_DEPLOYED(true);
|
||||
} break;
|
||||
|
||||
#endif // HAS_BED_PROBE
|
||||
|
||||
case 2: {
|
||||
#if HAS_MARLINUI_MENU
|
||||
//
|
||||
// Manually Probe Mesh in areas that can't be reached by the probe
|
||||
//
|
||||
SERIAL_ECHOLNPGM("Manually probing unreachable points.");
|
||||
motion.do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
|
||||
|
||||
if (parser.seen_test('C') && !param.XY_seen) {
|
||||
|
||||
/**
|
||||
* Use a good default location for the path.
|
||||
* The flipped > and < operators in these comparisons is intentional.
|
||||
* It should cause the probed points to follow a nice path on Cartesian printers.
|
||||
* It may make sense to have Delta printers default to the center of the bed.
|
||||
* Until that is decided, this can be forced with the X and Y parameters.
|
||||
*/
|
||||
param.XY_pos.set(
|
||||
#if IS_KINEMATIC
|
||||
X_HOME_POS, Y_HOME_POS
|
||||
#else
|
||||
probe.offset_xy.x > 0 ? X_BED_SIZE : 0,
|
||||
probe.offset_xy.y < 0 ? Y_BED_SIZE : 0
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
if (parser.seen('B')) {
|
||||
param.B_shim_thickness = parser.has_value() ? parser.value_float() : measure_business_card_thickness();
|
||||
if (ABS(param.B_shim_thickness) > 1.5f) {
|
||||
SERIAL_ECHOLNPGM("?Error in Business Card measurement.");
|
||||
return false;
|
||||
}
|
||||
SET_PROBE_DEPLOYED(true);
|
||||
}
|
||||
|
||||
if (!motion.can_reach(param.XY_pos)) {
|
||||
SERIAL_ECHOLNPGM("XY outside printable radius.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const float height = parser.floatval('H', Z_CLEARANCE_BETWEEN_PROBES);
|
||||
manually_probe_remaining_mesh(param.XY_pos, height, param.B_shim_thickness, parser.seen_test('T'));
|
||||
|
||||
SERIAL_ECHOLNPGM("G29 P2 finished.");
|
||||
|
||||
motion.report_position();
|
||||
|
||||
#else
|
||||
|
||||
SERIAL_ECHOLNPGM("?P2 is only available when an LCD is present.");
|
||||
return false;
|
||||
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
/**
|
||||
* Populate invalid mesh areas. Proceed with caution.
|
||||
* Two choices are available:
|
||||
* - Specify a constant with the 'C' parameter.
|
||||
* - Allow 'G29 P3' to choose a 'reasonable' constant.
|
||||
*/
|
||||
|
||||
if (param.C_seen) {
|
||||
if (param.R_repetition >= GRID_MAX_POINTS) {
|
||||
set_all_mesh_points_to_value(param.C_constant);
|
||||
}
|
||||
else {
|
||||
while (param.R_repetition--) { // this only populates reachable mesh points near
|
||||
const mesh_index_pair closest = find_closest_mesh_point_of_type(INVALID, param.XY_pos);
|
||||
const xy_int8_t &cpos = closest.pos;
|
||||
if (cpos.x < 0) {
|
||||
// No more REAL INVALID mesh points to populate, so we ASSUME
|
||||
// user meant to populate ALL INVALID mesh points to value
|
||||
GRID_LOOP(x, y) if (isnan(z_values[x][y])) z_values[x][y] = param.C_constant;
|
||||
break; // No more invalid Mesh Points to populate
|
||||
}
|
||||
else {
|
||||
z_values[cpos.x][cpos.y] = param.C_constant;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(cpos, param.C_constant));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float cvf = parser.value_float();
|
||||
switch ((int)TRUNC(cvf * 10.0f) - 30) { // 3.1 -> 1
|
||||
#if ENABLED(UBL_G29_P31)
|
||||
case 1: {
|
||||
|
||||
// P3.1 use least squares fit to fill missing mesh values
|
||||
// P3.10 zero weighting for distance, all grid points equal, best fit tilted plane
|
||||
// P3.11 10X weighting for nearest grid points versus farthest grid points
|
||||
// P3.12 100X distance weighting
|
||||
// P3.13 1000X distance weighting, approaches simple average of nearest points
|
||||
|
||||
const float weight_power = (cvf - 3.10f) * 100.0f, // 3.12345 -> 2.345
|
||||
weight_factor = weight_power ? POW(10.0f, weight_power) : 0;
|
||||
smart_fill_wlsf(weight_factor);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 0: // P3 or P3.0
|
||||
default: // and anything P3.x that's not P3.1
|
||||
smart_fill_mesh(); // Do a 'Smart' fill using nearby known values
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // Fine Tune (i.e., Edit) the Mesh
|
||||
#if HAS_MARLINUI_MENU
|
||||
fine_tune_mesh(param.XY_pos, parser.seen_test('T'));
|
||||
#else
|
||||
SERIAL_ECHOLNPGM("?P4 is only available when an LCD is present.");
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 5: adjust_mesh_to_mean(param.C_seen, param.C_constant); break;
|
||||
|
||||
case 6: shift_mesh_height(param.C_constant); break;
|
||||
|
||||
default:
|
||||
SERIAL_ECHOLNPGM("?Invalid P value.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle homing and initial setup for G29 command
|
||||
* @param may_move Whether the command requires printer movement
|
||||
* @return true if successful, false if error occurred
|
||||
*/
|
||||
void unified_bed_leveling::G29_handle_homing_and_setup() {
|
||||
planner.synchronize();
|
||||
#if ALL(DWIN_LCD_PROUI, ZHOME_BEFORE_LEVELING)
|
||||
save_ubl_active_state_and_disable();
|
||||
gcode.process_subcommands_now(F("G28Z"));
|
||||
restore_ubl_active_state(false); // ...without telling ExtUI "done"
|
||||
#else
|
||||
// Send 'N' to force homing before G29 (internal only)
|
||||
if (motion.axes_should_home() || parser.seen_test('N')) gcode.home_all_axes();
|
||||
#endif
|
||||
probe.use_probing_tool();
|
||||
|
||||
#ifdef EVENT_GCODE_BEFORE_G29
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Before G29 G-code: ", EVENT_GCODE_BEFORE_G29);
|
||||
gcode.process_subcommands_now(F(EVENT_GCODE_BEFORE_G29));
|
||||
#endif
|
||||
|
||||
// Position bed horizontally and Z probe vertically.
|
||||
#if HAS_SAFE_BED_LEVELING
|
||||
xyze_pos_t safe_position = motion.position;
|
||||
#ifdef SAFE_BED_LEVELING_START_X
|
||||
safe_position.x = SAFE_BED_LEVELING_START_X;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_Y
|
||||
safe_position.y = SAFE_BED_LEVELING_START_Y;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_Z
|
||||
safe_position.z = SAFE_BED_LEVELING_START_Z;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_I
|
||||
safe_position.i = SAFE_BED_LEVELING_START_I;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_J
|
||||
safe_position.j = SAFE_BED_LEVELING_START_J;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_K
|
||||
safe_position.k = SAFE_BED_LEVELING_START_K;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_U
|
||||
safe_position.u = SAFE_BED_LEVELING_START_U;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_V
|
||||
safe_position.v = SAFE_BED_LEVELING_START_V;
|
||||
#endif
|
||||
#ifdef SAFE_BED_LEVELING_START_W
|
||||
safe_position.w = SAFE_BED_LEVELING_START_W;
|
||||
#endif
|
||||
motion.blocking_move(safe_position);
|
||||
#endif // HAS_SAFE_BED_LEVELING
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mesh invalidation (I parameter)
|
||||
*/
|
||||
void unified_bed_leveling::G29_handle_invalidate() {
|
||||
// Invalidate one or more nearby mesh points, possibly all.
|
||||
grid_count_t count = parser.has_value() ? parser.value_ushort() : 1;
|
||||
bool invalidate_all = count >= GRID_MAX_POINTS;
|
||||
if (!invalidate_all) {
|
||||
while (count--) {
|
||||
if ((count & 0x0F) == 0x0F) marlin.idle();
|
||||
const mesh_index_pair closest = find_closest_mesh_point_of_type(REAL, param.XY_pos);
|
||||
// No more REAL mesh points to invalidate? Assume the user meant
|
||||
// to invalidate the ENTIRE mesh, which can't be done with
|
||||
// find_closest_mesh_point (which only returns REAL points).
|
||||
if (closest.pos.x < 0) { invalidate_all = true; break; }
|
||||
z_values[closest.pos.x][closest.pos.y] = NAN;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(closest.pos, 0.0f));
|
||||
}
|
||||
}
|
||||
if (invalidate_all) {
|
||||
invalidate();
|
||||
SERIAL_ECHOPGM("Entire Mesh");
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOPGM("Locations");
|
||||
SERIAL_ECHOLNPGM(" invalidated.\n");
|
||||
}
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
/**
|
||||
* Handle tilt mesh (J parameter)
|
||||
*/
|
||||
void unified_bed_leveling::G29_handle_tilt_mesh() {
|
||||
save_ubl_active_state_and_disable();
|
||||
tilt_mesh_based_on_probed_grid(param.J_grid_size == 0); // Zero size does 3-Point
|
||||
restore_ubl_active_state();
|
||||
#if ENABLED(UBL_G29_J_RECENTER)
|
||||
motion.blocking_move_xy(0.5f * (mesh_min.x + mesh_max.x), 0.5f * (mesh_min.y + mesh_max.y));
|
||||
#endif
|
||||
motion.report_position();
|
||||
SET_PROBE_DEPLOYED(true);
|
||||
}
|
||||
#endif // HAS_BED_PROBE
|
||||
|
||||
/**
|
||||
* Handle test patterns (Q parameter)
|
||||
* @return true if successful, false if error occurred
|
||||
*/
|
||||
bool unified_bed_leveling::G29_handle_test_patterns() {
|
||||
const int16_t test_pattern = parser.has_value() ? parser.value_int() : -99;
|
||||
if (!WITHIN(test_pattern, TERN0(UBL_DEVEL_DEBUGGING, -1), 2)) {
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("(Q) test pattern. (" TERN(UBL_DEVEL_DEBUGGING, "-1", "0") " to 2)\n"));
|
||||
return false;
|
||||
}
|
||||
SERIAL_ECHOLNPGM("Applying test pattern.\n");
|
||||
switch (test_pattern) {
|
||||
|
||||
default:
|
||||
case -1: TERN_(UBL_DEVEL_DEBUGGING, g29_eeprom_dump()); break;
|
||||
|
||||
case 0:
|
||||
// Create a bowl shape similar to a poorly-calibrated Delta
|
||||
GRID_LOOP(x, y) {
|
||||
const float p1 = 0.5f * (GRID_MAX_POINTS_X) - x,
|
||||
p2 = 0.5f * (GRID_MAX_POINTS_Y) - y;
|
||||
z_values[x][y] += 2.0f * HYPOT(p1, p2);
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Create a diagonal line several Mesh cells thick that is raised
|
||||
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; ++x) {
|
||||
const uint8_t x2 = x + (x < (GRID_MAX_POINTS_Y) - 1 ? 1 : -1);
|
||||
z_values[x][x] += 9.999f;
|
||||
z_values[x][x2] += 9.999f; // We want the altered line several mesh points thick
|
||||
#if ENABLED(EXTENSIBLE_UI)
|
||||
ExtUI::onMeshUpdate(x, x, z_values[x][x]);
|
||||
ExtUI::onMeshUpdate(x, x2, z_values[x][x2]);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Allow the user to specify the height because 10mm is a little extreme in some cases.
|
||||
for (uint8_t x = (GRID_MAX_POINTS_X) / 3; x < 2 * (GRID_MAX_POINTS_X) / 3; x++) // Create a rectangular raised area in
|
||||
for (uint8_t y = (GRID_MAX_POINTS_Y) / 3; y < 2 * (GRID_MAX_POINTS_Y) / 3; y++) { // the center of the bed
|
||||
z_values[x][y] += parser.seen_test('C') ? param.C_constant : 9.99f;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void unified_bed_leveling::shift_mesh_height(const float zoffs) {
|
||||
GRID_LOOP(x, y)
|
||||
if (!isnan(z_values[x][y])) {
|
||||
z_values[x][y] += zoffs;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -747,17 +807,6 @@ void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const float off
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* G29 P6 C<offset> : Shift Mesh Height by a uniform constant.
|
||||
*/
|
||||
void unified_bed_leveling::shift_mesh_height(const float zoffs) {
|
||||
GRID_LOOP(x, y)
|
||||
if (!isnan(z_values[x][y])) {
|
||||
z_values[x][y] += zoffs;
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
|
||||
}
|
||||
}
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
/**
|
||||
* G29 P1 T<maptype> V<verbosity> : Probe Entire Mesh
|
||||
@@ -783,6 +832,10 @@ void unified_bed_leveling::shift_mesh_height(const float zoffs) {
|
||||
TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), point_num, int(GRID_MAX_POINTS)));
|
||||
TERN_(HAS_BACKLIGHT_TIMEOUT, ui.refresh_backlight_timeout());
|
||||
|
||||
#if ENABLED(DWIN_LCD_PROUI)
|
||||
if (!hmiFlag.cancel_lev) dwinRedrawScreen(); else break;
|
||||
#endif
|
||||
|
||||
#if HAS_MARLINUI_MENU
|
||||
if (ui.button_pressed()) {
|
||||
ui.quick_feedback(false); // Preserve button state for click-and-hold
|
||||
@@ -816,6 +869,9 @@ void unified_bed_leveling::shift_mesh_height(const float zoffs) {
|
||||
|
||||
} while (best.pos.x >= 0 && --count);
|
||||
|
||||
if (TERN0(DWIN_LCD_PROUI, hmiFlag.cancel_lev))
|
||||
goto EXIT_PROBE_MESH;
|
||||
|
||||
GRID_LOOP(x, y) if (z_values[x][y] == HUGE_VALF) z_values[x][y] = NAN; // Restore NAN for HUGE_VALF marks
|
||||
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::G29_FINISH));
|
||||
@@ -827,10 +883,16 @@ void unified_bed_leveling::shift_mesh_height(const float zoffs) {
|
||||
|
||||
probe.move_z_after_probing();
|
||||
|
||||
do_blocking_move_to_xy(
|
||||
constrain(nearby.x - probe.offset_xy.x, MESH_MIN_X, MESH_MAX_X),
|
||||
constrain(nearby.y - probe.offset_xy.y, MESH_MIN_Y, MESH_MAX_Y)
|
||||
);
|
||||
#if ENABLED(DWIN_LCD_PROUI)
|
||||
bedlevel.smart_fill_mesh();
|
||||
#else
|
||||
motion.blocking_move_xy(
|
||||
constrain(nearby.x - probe.offset_xy.x, mesh_min.x, mesh_max.x),
|
||||
constrain(nearby.y - probe.offset_xy.y, mesh_min.y, mesh_max.y)
|
||||
);
|
||||
#endif
|
||||
|
||||
EXIT_PROBE_MESH:
|
||||
|
||||
restore_ubl_active_state();
|
||||
}
|
||||
@@ -874,7 +936,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
marlin.idle();
|
||||
gcode.reset_stepper_timeout(); // Keep steppers powered
|
||||
if (encoder_diff) {
|
||||
do_blocking_move_to_z(current_position.z + float(encoder_diff) * multiplier);
|
||||
motion.blocking_move_z(motion.position.z + float(encoder_diff) * multiplier);
|
||||
encoder_diff = 0;
|
||||
}
|
||||
}
|
||||
@@ -884,7 +946,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
||||
const float z_step = 0.01f;
|
||||
move_z_with_encoder(z_step);
|
||||
return current_position.z;
|
||||
return motion.position.z;
|
||||
}
|
||||
|
||||
static void echo_and_take_a_measurement() { SERIAL_ECHOLNPGM(" and take a measurement."); }
|
||||
@@ -893,10 +955,10 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
ui.capture();
|
||||
save_ubl_active_state_and_disable(); // Disable bed level correction for probing
|
||||
|
||||
do_blocking_move_to(
|
||||
motion.blocking_move(
|
||||
xyz_pos_t({
|
||||
0.5f * ((MESH_MAX_X) - (MESH_MIN_X)),
|
||||
0.5f * ((MESH_MAX_Y) - (MESH_MIN_Y)),
|
||||
0.5f * (mesh_min.x + mesh_max.x),
|
||||
0.5f * (mesh_min.y + mesh_max.y),
|
||||
MANUAL_PROBE_START_Z
|
||||
#ifdef SAFE_BED_LEVELING_START_I
|
||||
, SAFE_BED_LEVELING_START_I
|
||||
@@ -927,14 +989,14 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
echo_and_take_a_measurement();
|
||||
|
||||
const float z1 = measure_point_with_encoder();
|
||||
do_z_clearance_by(SIZE_OF_LITTLE_RAISE);
|
||||
motion.do_z_clearance_by(SIZE_OF_LITTLE_RAISE);
|
||||
|
||||
SERIAL_ECHOPGM("Remove shim");
|
||||
LCD_MESSAGE(MSG_UBL_BC_REMOVE);
|
||||
echo_and_take_a_measurement();
|
||||
|
||||
const float z2 = measure_point_with_encoder();
|
||||
do_z_clearance_by(Z_CLEARANCE_BETWEEN_PROBES);
|
||||
motion.do_z_clearance_by(Z_CLEARANCE_BETWEEN_PROBES);
|
||||
|
||||
const float thickness = ABS(z1 - z2);
|
||||
|
||||
@@ -956,7 +1018,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart());
|
||||
|
||||
save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained
|
||||
do_blocking_move_to_xy_z(current_position, z_clearance);
|
||||
motion.blocking_move_xy_z(motion.position, z_clearance);
|
||||
|
||||
ui.return_to_status();
|
||||
|
||||
@@ -969,12 +1031,12 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
|
||||
const xyz_pos_t ppos = { get_mesh_x(lpos.x), get_mesh_y(lpos.y), z_clearance };
|
||||
|
||||
if (!position_is_reachable(ppos)) break; // SHOULD NOT OCCUR (find_closest_mesh_point only returns reachable points)
|
||||
if (!motion.can_reach(ppos)) break; // SHOULD NOT OCCUR (find_closest_mesh_point only returns reachable points)
|
||||
|
||||
LCD_MESSAGE(MSG_UBL_MOVING_TO_NEXT);
|
||||
|
||||
do_blocking_move_to(ppos);
|
||||
do_z_clearance(z_clearance);
|
||||
motion.blocking_move(ppos);
|
||||
motion.do_z_clearance(z_clearance);
|
||||
|
||||
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
||||
ui.capture();
|
||||
@@ -995,11 +1057,11 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
|
||||
if (_click_and_hold([]{
|
||||
SERIAL_ECHOLNPGM("\nMesh only partially populated.");
|
||||
do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE);
|
||||
motion.do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE);
|
||||
})) return restore_ubl_active_state();
|
||||
|
||||
// Store the Z position minus the shim height
|
||||
z_values[lpos.x][lpos.y] = current_position.z - thick;
|
||||
z_values[lpos.x][lpos.y] = motion.position.z - thick;
|
||||
|
||||
// Tell the external UI to update
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, z_values[lpos.x][lpos.y]));
|
||||
@@ -1012,7 +1074,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
if (do_ubl_mesh_map) display_map(param.T_map_type); // show user where we're probing
|
||||
|
||||
restore_ubl_active_state();
|
||||
do_blocking_move_to_xy_z(pos, Z_CLEARANCE_DEPLOY_PROBE);
|
||||
motion.blocking_move_xy_z(pos, Z_CLEARANCE_DEPLOY_PROBE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1033,7 +1095,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
|
||||
mesh_index_pair location;
|
||||
|
||||
if (!position_is_reachable(pos)) {
|
||||
if (!motion.can_reach(pos)) {
|
||||
SERIAL_ECHOLNPGM("(X,Y) outside printable radius.");
|
||||
return;
|
||||
}
|
||||
@@ -1043,7 +1105,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
LCD_MESSAGE(MSG_UBL_FINE_TUNE_MESH);
|
||||
ui.capture(); // Take over control of the LCD encoder
|
||||
|
||||
do_blocking_move_to_xy_z(pos, Z_TWEEN_SAFE_CLEARANCE); // Move to the given XY with probe clearance
|
||||
motion.blocking_move_xy_z(pos, Z_TWEEN_SAFE_CLEARANCE); // Move to the given XY with probe clearance
|
||||
|
||||
MeshFlags done_flags{0};
|
||||
const xy_int8_t &lpos = location.pos;
|
||||
@@ -1062,18 +1124,18 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
// location is used on the next loop
|
||||
const xyz_pos_t raw = { get_mesh_x(lpos.x), get_mesh_y(lpos.y), Z_TWEEN_SAFE_CLEARANCE };
|
||||
|
||||
if (!position_is_reachable(raw)) break; // SHOULD NOT OCCUR (find_closest_mesh_point_of_type only returns reachable)
|
||||
if (!motion.can_reach(raw)) break; // SHOULD NOT OCCUR (find_closest_mesh_point_of_type only returns reachable)
|
||||
|
||||
do_blocking_move_to(raw); // Move the nozzle to the edit point with probe clearance
|
||||
motion.blocking_move(raw); // Move the nozzle to the edit point with probe clearance
|
||||
|
||||
TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset)); // Move Z to the given 'H' offset before editing
|
||||
TERN_(UBL_MESH_EDIT_MOVES_Z, motion.blocking_move_z(h_offset)); // Move Z to the given 'H' offset before editing
|
||||
|
||||
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
||||
|
||||
if (do_ubl_mesh_map) display_map(param.T_map_type); // Display the current point
|
||||
|
||||
#if IS_TFTGLCD_PANEL
|
||||
ui.ubl_plot(lpos.x, lpos.y); // update plot screen
|
||||
ui.ubl_plot(lpos.x, lpos.y); // Update plot screen
|
||||
#endif
|
||||
|
||||
ui.refresh();
|
||||
@@ -1084,23 +1146,23 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
|
||||
ui.ubl_mesh_edit_start(new_z);
|
||||
|
||||
SET_SOFT_ENDSTOP_LOOSE(true);
|
||||
motion.set_soft_endstop_loose(true);
|
||||
|
||||
do {
|
||||
marlin.idle_no_sleep();
|
||||
new_z = ui.ubl_mesh_value();
|
||||
TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset + new_z)); // Move the nozzle as the point is edited
|
||||
TERN_(UBL_MESH_EDIT_MOVES_Z, motion.blocking_move_z(h_offset + new_z)); // Move the nozzle as the point is edited
|
||||
SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
|
||||
} while (!ui.button_pressed());
|
||||
|
||||
SET_SOFT_ENDSTOP_LOOSE(false);
|
||||
motion.set_soft_endstop_loose(false);
|
||||
|
||||
if (!lcd_map_control) ui.return_to_status(); // Just editing a single point? Return to status
|
||||
|
||||
// Button held down? Abort editing
|
||||
if (_click_and_hold([]{
|
||||
ui.return_to_status();
|
||||
do_z_clearance(Z_TWEEN_SAFE_CLEARANCE);
|
||||
motion.do_z_clearance(Z_TWEEN_SAFE_CLEARANCE);
|
||||
set_message_with_feedback(GET_TEXT_F(MSG_EDITING_STOPPED));
|
||||
})) break;
|
||||
|
||||
@@ -1120,7 +1182,7 @@ void set_message_with_feedback(FSTR_P const fstr) {
|
||||
if (do_ubl_mesh_map) display_map(param.T_map_type);
|
||||
restore_ubl_active_state();
|
||||
|
||||
do_blocking_move_to_xy_z(pos, Z_TWEEN_SAFE_CLEARANCE);
|
||||
motion.blocking_move_xy_z(pos, Z_TWEEN_SAFE_CLEARANCE);
|
||||
|
||||
LCD_MESSAGE(MSG_UBL_DONE_EDITING_MESH);
|
||||
SERIAL_ECHOLNPGM("Done Editing Mesh");
|
||||
@@ -1191,9 +1253,9 @@ bool unified_bed_leveling::G29_parse_parameters() {
|
||||
}
|
||||
|
||||
param.XY_seen.x = parser.seenval('X');
|
||||
float sx = param.XY_seen.x ? parser.value_float() : current_position.x;
|
||||
float sx = param.XY_seen.x ? parser.value_float() : DIFF_TERN(HAS_BED_PROBE, motion.position.x, probe.offset.x);
|
||||
param.XY_seen.y = parser.seenval('Y');
|
||||
float sy = param.XY_seen.y ? parser.value_float() : current_position.y;
|
||||
float sy = param.XY_seen.y ? parser.value_float() : DIFF_TERN(HAS_BED_PROBE, motion.position.y, probe.offset.y);
|
||||
|
||||
if (param.XY_seen.x != param.XY_seen.y) {
|
||||
SERIAL_ECHOLNPGM("Both X & Y locations must be specified.\n");
|
||||
@@ -1202,8 +1264,8 @@ bool unified_bed_leveling::G29_parse_parameters() {
|
||||
|
||||
// If X or Y are not valid, use center of the bed values
|
||||
// (for UBL_HILBERT_CURVE default to lower-left corner instead)
|
||||
if (!COORDINATE_OKAY(sx, X_MIN_BED, X_MAX_BED)) sx = TERN(UBL_HILBERT_CURVE, 0, X_CENTER);
|
||||
if (!COORDINATE_OKAY(sy, Y_MIN_BED, Y_MAX_BED)) sy = TERN(UBL_HILBERT_CURVE, 0, Y_CENTER);
|
||||
if (!COORDINATE_OKAY(sx, X_MIN_BED, X_MAX_BED)) sx = TERN(UBL_HILBERT_CURVE, 0, DIFF_TERN(HAS_BED_PROBE, X_CENTER, probe.offset.x));
|
||||
if (!COORDINATE_OKAY(sy, Y_MIN_BED, Y_MAX_BED)) sy = TERN(UBL_HILBERT_CURVE, 0, DIFF_TERN(HAS_BED_PROBE, Y_CENTER, probe.offset.y));
|
||||
|
||||
if (err_flag) return UBL_ERR;
|
||||
|
||||
@@ -1358,7 +1420,7 @@ mesh_index_pair unified_bed_leveling::find_furthest_invalid_mesh_point() {
|
||||
// Also for round beds, there are grid points outside the bed the nozzle can't reach.
|
||||
// Prune them from the list and ignore them till the next Phase (manual nozzle probing).
|
||||
|
||||
if (!(d->probe_relative ? probe.can_reach(mpos) : position_is_reachable(mpos)))
|
||||
if (!(d->probe_relative ? probe.can_reach(mpos) : motion.can_reach(mpos)))
|
||||
return false;
|
||||
d->closest.pos.set(i, j);
|
||||
return true;
|
||||
@@ -1402,12 +1464,12 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh
|
||||
// Also for round beds, there are grid points outside the bed the nozzle can't reach.
|
||||
// Prune them from the list and ignore them till the next Phase (manual nozzle probing).
|
||||
|
||||
if (!(probe_relative ? probe.can_reach(mpos) : position_is_reachable(mpos)))
|
||||
if (!(probe_relative ? probe.can_reach(mpos) : motion.can_reach(mpos)))
|
||||
continue;
|
||||
|
||||
// Reachable. Check if it's the best_so_far location to the nozzle.
|
||||
|
||||
const xy_pos_t diff = current_position - mpos;
|
||||
const xy_pos_t diff = motion.position - mpos;
|
||||
const float distance = (ref - mpos).magnitude() + diff.magnitude() * 0.1f;
|
||||
|
||||
// factor in the distance from the current location for the normal case
|
||||
@@ -1535,10 +1597,10 @@ void unified_bed_leveling::smart_fill_mesh() {
|
||||
#ifndef G29J_MESH_TILT_MARGIN
|
||||
#define G29J_MESH_TILT_MARGIN 0
|
||||
#endif
|
||||
const float x_min = _MAX((X_MIN_POS) + (G29J_MESH_TILT_MARGIN), MESH_MIN_X, probe.min_x()),
|
||||
x_max = _MIN((X_MAX_POS) - (G29J_MESH_TILT_MARGIN), MESH_MAX_X, probe.max_x()),
|
||||
y_min = _MAX((Y_MIN_POS) + (G29J_MESH_TILT_MARGIN), MESH_MIN_Y, probe.min_y()),
|
||||
y_max = _MIN((Y_MAX_POS) - (G29J_MESH_TILT_MARGIN), MESH_MAX_Y, probe.max_y()),
|
||||
const float x_min = _MAX((X_MIN_POS) + (G29J_MESH_TILT_MARGIN), mesh_min.x, probe.min_x()),
|
||||
x_max = _MIN((X_MAX_POS) - (G29J_MESH_TILT_MARGIN), mesh_max.x, probe.max_x()),
|
||||
y_min = _MAX((Y_MIN_POS) + (G29J_MESH_TILT_MARGIN), mesh_min.y, probe.min_y()),
|
||||
y_max = _MIN((Y_MAX_POS) - (G29J_MESH_TILT_MARGIN), mesh_max.y, probe.max_y()),
|
||||
dx = (x_max - x_min) / (param.J_grid_size - 1),
|
||||
dy = (y_max - y_min) / (param.J_grid_size - 1);
|
||||
|
||||
@@ -1760,25 +1822,23 @@ void unified_bed_leveling::smart_fill_mesh() {
|
||||
SERIAL_ECHOLNPGM("Probe Offset M851 Z", p_float_t(probe.offset.z, 7));
|
||||
#endif
|
||||
|
||||
SERIAL_ECHOLNPGM("MESH_MIN_X " STRINGIFY(MESH_MIN_X) "=", MESH_MIN_X); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("MESH_MIN_Y " STRINGIFY(MESH_MIN_Y) "=", MESH_MIN_Y); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("MESH_MAX_X " STRINGIFY(MESH_MAX_X) "=", MESH_MAX_X); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("MESH_MAX_Y " STRINGIFY(MESH_MAX_Y) "=", MESH_MAX_Y); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("GRID_MAX_POINTS_X ", GRID_MAX_POINTS_X); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("mesh_min ", mesh_min.x, ", ", mesh_min.y); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("mesh_max ", mesh_max.x, ", ", mesh_max.y); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("GRID_MAX_POINTS_X ", GRID_MAX_POINTS_X); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("MESH_X_DIST ", MESH_X_DIST);
|
||||
SERIAL_ECHOLNPGM("MESH_Y_DIST ", MESH_Y_DIST); serial_delay(50);
|
||||
SERIAL_ECHOLNPGM("MESH_Y_DIST ", MESH_Y_DIST); serial_delay(50);
|
||||
|
||||
SERIAL_ECHOPGM("X-Axis Mesh Points at: ");
|
||||
for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) {
|
||||
SERIAL_ECHO(p_float_t(LOGICAL_X_POSITION(get_mesh_x(i)), 3), F(" "));
|
||||
SERIAL_ECHO(p_float_t(motion.logical_x(get_mesh_x(i)), 3), F(" "));
|
||||
serial_delay(25);
|
||||
}
|
||||
SERIAL_EOL();
|
||||
|
||||
SERIAL_ECHOPGM("Y-Axis Mesh Points at: ");
|
||||
for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; ++i) {
|
||||
SERIAL_ECHO(p_float_t(LOGICAL_Y_POSITION(get_mesh_y(i)), 3), F(" "));
|
||||
SERIAL_ECHO(p_float_t(motion.logical_y(get_mesh_y(i)), 3), F(" "));
|
||||
serial_delay(25);
|
||||
}
|
||||
SERIAL_EOL();
|
||||
|
||||
@@ -53,11 +53,11 @@
|
||||
* just do the required Z-Height correction, call the Planner's buffer_line() routine, and leave
|
||||
*/
|
||||
#if HAS_POSITION_MODIFIERS
|
||||
xyze_pos_t start = current_position, end = destination;
|
||||
xyze_pos_t start = motion.position, end = motion.destination;
|
||||
planner.apply_modifiers(start);
|
||||
planner.apply_modifiers(end);
|
||||
#else
|
||||
const xyze_pos_t &start = current_position, &end = destination;
|
||||
const xyze_pos_t &start = motion.position, &end = motion.destination;
|
||||
#endif
|
||||
|
||||
const xy_uint8_t istart = cell_indexes(start), iend = cell_indexes(end);
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
end.z += UBL_Z_RAISE_WHEN_OFF_MESH;
|
||||
planner.buffer_segment(end, scaled_fr_mm_s, extruder);
|
||||
current_position = destination;
|
||||
motion.position = motion.destination;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -96,7 +96,7 @@
|
||||
// Replace NAN corrections with 0.0 to prevent NAN propagation.
|
||||
if (!isnan(z0)) end.z += z0;
|
||||
planner.buffer_segment(end, scaled_fr_mm_s, extruder);
|
||||
current_position = destination;
|
||||
motion.position = motion.destination;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,10 +190,10 @@
|
||||
}
|
||||
|
||||
// At the final destination? Usually not, but when on a Y Mesh Line it's completed.
|
||||
if (xy_pos_t(current_position) != xy_pos_t(end))
|
||||
if (xy_pos_t(motion.position) != xy_pos_t(end))
|
||||
goto FINAL_MOVE;
|
||||
|
||||
current_position = destination;
|
||||
motion.position = motion.destination;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -240,10 +240,10 @@
|
||||
DEBUG_ECHOLNPGM("[ubl] skip Y segment");
|
||||
}
|
||||
|
||||
if (xy_pos_t(current_position) != xy_pos_t(end))
|
||||
if (xy_pos_t(motion.position) != xy_pos_t(end))
|
||||
goto FINAL_MOVE;
|
||||
|
||||
current_position = destination;
|
||||
motion.position = motion.destination;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -324,10 +324,10 @@
|
||||
if (cnt.x < 0 || cnt.y < 0) break; // Too far! Exit the loop and go to FINAL_MOVE
|
||||
}
|
||||
|
||||
if (xy_pos_t(current_position) != xy_pos_t(end))
|
||||
if (xy_pos_t(motion.position) != xy_pos_t(end))
|
||||
goto FINAL_MOVE;
|
||||
|
||||
current_position = destination;
|
||||
motion.position = motion.destination;
|
||||
}
|
||||
|
||||
#else // UBL_SEGMENTED
|
||||
@@ -347,15 +347,15 @@
|
||||
/**
|
||||
* Prepare a segmented linear move for DELTA/SCARA/CARTESIAN with UBL and FADE semantics.
|
||||
* This calls planner.buffer_segment multiple times for small incremental moves.
|
||||
* Returns true if did NOT move, false if moved (requires current_position update).
|
||||
* Returns true if did NOT move, false if moved (requires motion.position update).
|
||||
*/
|
||||
|
||||
bool __O2 unified_bed_leveling::line_to_destination_segmented(const feedRate_t scaled_fr_mm_s) {
|
||||
|
||||
if (!position_is_reachable(destination)) // fail if moving outside reachable boundary
|
||||
return true; // did not move, so current_position still accurate
|
||||
if (!motion.can_reach(motion.destination)) // Fail if moving outside reachable boundary
|
||||
return true; // Did not move, so motion.position still accurate
|
||||
|
||||
const xyze_pos_t total = destination - current_position;
|
||||
const xyze_pos_t total = motion.destination - motion.position;
|
||||
|
||||
const float cart_xy_mm_2 = HYPOT2(total.x, total.y),
|
||||
cart_xy_mm = SQRT(cart_xy_mm_2); // Total XY distance
|
||||
@@ -383,22 +383,22 @@
|
||||
// Note that E segment distance could vary slightly as z mesh height
|
||||
// changes for each segment, but small enough to ignore.
|
||||
|
||||
xyze_pos_t raw = current_position;
|
||||
xyze_pos_t raw = motion.position;
|
||||
|
||||
// Just do plain segmentation if UBL is inactive or the target is above the fade height
|
||||
if (!planner.leveling_active || !planner.leveling_active_at_z(destination.z)) {
|
||||
if (!planner.leveling_active || !planner.leveling_active_at_z(motion.destination.z)) {
|
||||
while (--segments) {
|
||||
raw += diff;
|
||||
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints);
|
||||
planner.buffer_line(raw, scaled_fr_mm_s, motion.extruder, hints);
|
||||
}
|
||||
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, hints);
|
||||
planner.buffer_line(motion.destination, scaled_fr_mm_s, motion.extruder, hints);
|
||||
return false; // Did not set current from destination
|
||||
}
|
||||
|
||||
// Otherwise perform per-segment leveling
|
||||
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
const float fade_scaling_factor = planner.fade_scaling_factor_for_z(destination.z);
|
||||
const float fade_scaling_factor = planner.fade_scaling_factor_for_z(motion.destination.z);
|
||||
#endif
|
||||
|
||||
// Move to first segment destination
|
||||
@@ -414,8 +414,8 @@
|
||||
// for mesh inset area.
|
||||
|
||||
xy_int8_t icell = {
|
||||
int8_t((raw.x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST)),
|
||||
int8_t((raw.y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST))
|
||||
int8_t((raw.x - mesh_min.x) * RECIPROCAL(MESH_X_DIST)),
|
||||
int8_t((raw.y - mesh_min.y) * RECIPROCAL(MESH_Y_DIST))
|
||||
};
|
||||
LIMIT(icell.x, 0, GRID_MAX_CELLS_X);
|
||||
LIMIT(icell.y, 0, GRID_MAX_CELLS_Y);
|
||||
@@ -456,13 +456,13 @@
|
||||
|
||||
for (;;) { // for all segments within this mesh cell
|
||||
|
||||
if (--segments == 0) raw = destination; // if this is last segment, use destination for exact
|
||||
if (--segments == 0) raw = motion.destination; // If this is last segment, use destination for exact
|
||||
|
||||
const float z_cxcy = (z_cxy0 + z_cxym * cell.y) // interpolated mesh z height along cell.x at cell.y
|
||||
TERN_(ENABLE_LEVELING_FADE_HEIGHT, * fade_scaling_factor); // apply fade factor to interpolated height
|
||||
|
||||
const float oldz = raw.z; raw.z += z_cxcy;
|
||||
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints);
|
||||
planner.buffer_line(raw, scaled_fr_mm_s, motion.extruder, hints);
|
||||
raw.z = oldz;
|
||||
|
||||
if (segments == 0) // done with last segment
|
||||
@@ -483,7 +483,7 @@
|
||||
} // segment loop
|
||||
} // cell loop
|
||||
|
||||
return false; // caller will update current_position
|
||||
return false; // caller will update motion.position
|
||||
}
|
||||
|
||||
#endif // UBL_SEGMENTED
|
||||
|
||||
@@ -134,7 +134,7 @@ void ControllerFan::update() {
|
||||
} while (0)
|
||||
|
||||
#if ENABLED(FAN_SOFT_PWM)
|
||||
soft_pwm_speed = speed;
|
||||
soft_pwm_speed = speed >> 1; // Controller Fan Soft PWM uses 0-127 as 0-100% so cut the 0-255 range in half.
|
||||
#else
|
||||
SET_CONTROLLER_FAN();
|
||||
#if PIN_EXISTS(CONTROLLER_FAN2)
|
||||
|
||||
@@ -54,10 +54,11 @@ EmergencyParser emergency_parser;
|
||||
#endif
|
||||
|
||||
#if ENABLED(REALTIME_REPORTING_COMMANDS)
|
||||
// From motion.h, which cannot be included here
|
||||
void report_current_position_moving();
|
||||
void quickpause_stepper();
|
||||
void quickresume_stepper();
|
||||
#include "../module/motion.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
bool realtime_ramping_pause_flag = false;
|
||||
#endif
|
||||
|
||||
void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
|
||||
@@ -150,7 +151,7 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
|
||||
case EP_M4:
|
||||
switch (c) {
|
||||
case '1' :state = EP_M41; break;
|
||||
#if ENABLED(FT_MOTION_RESONANCE_TEST)
|
||||
#if ENABLED(FTM_RESONANCE_TEST)
|
||||
case '9': state = EP_M49; break;
|
||||
#endif
|
||||
default: state = EP_IGNORE;
|
||||
@@ -222,9 +223,9 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
|
||||
case EP_M876SN: hostui.handle_response(M876_reason); break;
|
||||
#endif
|
||||
#if ENABLED(REALTIME_REPORTING_COMMANDS)
|
||||
case EP_GRBL_STATUS: report_current_position_moving(); break;
|
||||
case EP_GRBL_PAUSE: quickpause_stepper(); break;
|
||||
case EP_GRBL_RESUME: quickresume_stepper(); break;
|
||||
case EP_GRBL_STATUS: motion.report_position_moving(); break;
|
||||
case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, motion.quickpause_stepper()); break;
|
||||
case EP_GRBL_RESUME: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = false, motion.quickresume_stepper()); break;
|
||||
#endif
|
||||
#if ENABLED(SOFT_RESET_VIA_SERIAL)
|
||||
case EP_KILL: hal.reboot(); break;
|
||||
|
||||
@@ -93,3 +93,7 @@ private:
|
||||
};
|
||||
|
||||
extern EmergencyParser emergency_parser;
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
extern bool realtime_ramping_pause_flag;
|
||||
#endif
|
||||
|
||||
@@ -136,7 +136,7 @@ void EasythreedUI::loadButton() {
|
||||
if (READ(BTN_RETRACT) && READ(BTN_FEED)) { // Switch in center position (stop)
|
||||
flag = false; // Restore flag to false
|
||||
filament_status = FS_IDLE; // Go back to idle state
|
||||
quickstop_stepper(); // Hard-stop all the steppers ... now!
|
||||
motion.quickstop_stepper(); // Hard-stop all the steppers ... now!
|
||||
thermalManager.disable_all_heaters(); // And disable all the heaters
|
||||
blink_interval_ms = LED_ON;
|
||||
}
|
||||
|
||||
@@ -318,9 +318,9 @@ bool I2CPositionEncoder::test_axis() {
|
||||
// Only works on XYZ Cartesian machines for the time being
|
||||
if (!(encoderAxis == X_AXIS || encoderAxis == Y_AXIS || encoderAxis == Z_AXIS)) return false;
|
||||
|
||||
const float startPosition = soft_endstop.min[encoderAxis] + 10,
|
||||
endPosition = soft_endstop.max[encoderAxis] - 10;
|
||||
const feedRate_t fr_mm_s = FLOOR(homing_feedrate(encoderAxis));
|
||||
const float startPosition = motion.soft_endstop.min[encoderAxis] + 10,
|
||||
endPosition = motion.soft_endstop.max[encoderAxis] - 10;
|
||||
const feedRate_t fr_mm_s = FLOOR(motion.homing_feedrate(encoderAxis));
|
||||
|
||||
ec = false;
|
||||
|
||||
@@ -373,13 +373,13 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) {
|
||||
|
||||
int32_t startCount, stopCount;
|
||||
|
||||
const feedRate_t fr_mm_s = homing_feedrate(encoderAxis);
|
||||
const feedRate_t fr_mm_s = motion.homing_feedrate(encoderAxis);
|
||||
|
||||
bool oldec = ec;
|
||||
ec = false;
|
||||
|
||||
startDistance = 20;
|
||||
endDistance = soft_endstop.max[encoderAxis] - 20;
|
||||
endDistance = motion.soft_endstop.max[encoderAxis] - 20;
|
||||
travelDistance = endDistance - startDistance;
|
||||
|
||||
xyze_pos_t startCoord, endCoord;
|
||||
@@ -400,7 +400,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) {
|
||||
delay(250);
|
||||
startCount = get_position();
|
||||
|
||||
//do_blocking_move_to(endCoord);
|
||||
//motion.blocking_move(endCoord);
|
||||
|
||||
TERN_(HAS_EXTRUDERS, endCoord.e = planner.get_axis_position_mm(E_AXIS));
|
||||
planner.buffer_line(endCoord, fr_mm_s, 0);
|
||||
|
||||
@@ -92,14 +92,14 @@ void FWRetract::reset() {
|
||||
*/
|
||||
void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) {
|
||||
// Prevent two retracts or recovers in a row
|
||||
if (retracted[active_extruder] == retracting) return;
|
||||
if (retracted[motion.extruder] == retracting) return;
|
||||
|
||||
// Prevent two swap-retract or recovers in a row
|
||||
#if HAS_MULTI_EXTRUDER
|
||||
// Allow G10 S1 only after G11
|
||||
if (swapping && retracted_swap[active_extruder] == retracting) return;
|
||||
if (swapping && retracted_swap[motion.extruder] == retracting) return;
|
||||
// G11 priority to recover the long retract if activated
|
||||
if (!retracting) swapping = retracted_swap[active_extruder];
|
||||
if (!retracting) swapping = retracted_swap[motion.extruder];
|
||||
#else
|
||||
constexpr bool swapping = false;
|
||||
#endif
|
||||
@@ -108,7 +108,7 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
|
||||
SERIAL_ECHOLNPGM(
|
||||
"retracting ", AS_DIGIT(retracting),
|
||||
" swapping ", swapping,
|
||||
" active extruder ", active_extruder
|
||||
" active extruder ", motion.extruder
|
||||
);
|
||||
EXTRUDER_LOOP() {
|
||||
SERIAL_ECHOLNPGM("retracted[", e, "] ", AS_DIGIT(retracted[e]));
|
||||
@@ -116,8 +116,8 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
|
||||
SERIAL_ECHOLNPGM("retracted_swap[", e, "] ", AS_DIGIT(retracted_swap[e]));
|
||||
#endif
|
||||
}
|
||||
SERIAL_ECHOLNPGM("current_position.z ", current_position.z);
|
||||
SERIAL_ECHOLNPGM("current_position.e ", current_position.e);
|
||||
SERIAL_ECHOLNPGM("motion.position.z ", motion.position.z);
|
||||
SERIAL_ECHOLNPGM("motion.position.e ", motion.position.e);
|
||||
SERIAL_ECHOLNPGM("current_hop ", current_hop);
|
||||
//*/
|
||||
|
||||
@@ -125,7 +125,7 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
|
||||
* (swapping ? settings.swap_retract_length : settings.retract_length);
|
||||
|
||||
// The current position will be the destination for E and Z moves
|
||||
destination = current_position;
|
||||
motion.destination = motion.position;
|
||||
|
||||
#if ENABLED(RETRACT_SYNC_MIXING)
|
||||
const uint8_t old_mixing_tool = mixer.get_current_vtool();
|
||||
@@ -135,8 +135,8 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
|
||||
const feedRate_t fr_max_z = planner.settings.max_feedrate_mm_s[Z_AXIS];
|
||||
if (retracting) {
|
||||
// Retract by moving from a faux E position back to the current E position
|
||||
current_retract[active_extruder] = base_retract;
|
||||
prepare_internal_move_to_destination( // set current from destination
|
||||
current_retract[motion.extruder] = base_retract;
|
||||
motion.prepare_internal_move_to_destination( // Set current from destination
|
||||
MUL_TERN(RETRACT_SYNC_MIXING, settings.retract_feedrate_mm_s, MIXING_STEPPERS)
|
||||
);
|
||||
|
||||
@@ -144,7 +144,7 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
|
||||
if (!current_hop && settings.retract_zraise > 0.01f) { // Apply hop only once
|
||||
current_hop += settings.retract_zraise; // Add to the hop total (again, only once)
|
||||
// Raise up, set_current_to_destination. Maximum Z feedrate
|
||||
prepare_internal_move_to_destination(fr_max_z);
|
||||
motion.prepare_internal_move_to_destination(fr_max_z);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -152,43 +152,42 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
|
||||
if (current_hop) {
|
||||
current_hop = 0;
|
||||
// Lower Z, set_current_to_destination. Maximum Z feedrate
|
||||
prepare_internal_move_to_destination(fr_max_z);
|
||||
motion.prepare_internal_move_to_destination(fr_max_z);
|
||||
}
|
||||
|
||||
// Adjust the current E position by the extra amount to recover
|
||||
// Sync the planner position so the extra amount is recovered
|
||||
const float extra_recover = swapping ? settings.swap_retract_recover_extra : settings.retract_recover_extra;
|
||||
if (extra_recover) {
|
||||
current_position.e -= extra_recover; // Adjust the current E position by the extra amount to recover
|
||||
sync_plan_position_e(); // Sync the planner position so the extra amount is recovered
|
||||
}
|
||||
if (extra_recover) motion.set_and_sync_e(motion.position.e - extra_recover);
|
||||
|
||||
current_retract[active_extruder] = 0;
|
||||
current_retract[motion.extruder] = 0;
|
||||
|
||||
// Recover E, set_current_to_destination
|
||||
const feedRate_t fr_mm_s = swapping ? settings.swap_retract_recover_feedrate_mm_s : settings.retract_recover_feedrate_mm_s;
|
||||
prepare_internal_move_to_destination(MUL_TERN(RETRACT_SYNC_MIXING, fr_mm_s, MIXING_STEPPERS));
|
||||
motion.prepare_internal_move_to_destination(MUL_TERN(RETRACT_SYNC_MIXING, fr_mm_s, MIXING_STEPPERS));
|
||||
}
|
||||
|
||||
TERN_(RETRACT_SYNC_MIXING, mixer.T(old_mixing_tool)); // Restore original mixing tool
|
||||
|
||||
retracted.set(active_extruder, retracting); // Active extruder now retracted / recovered
|
||||
retracted.set(motion.extruder, retracting); // Active extruder now retracted / recovered
|
||||
|
||||
// If swap retract/recover update the retracted_swap flag too
|
||||
#if HAS_MULTI_EXTRUDER
|
||||
if (swapping) retracted_swap.set(active_extruder, retracting);
|
||||
if (swapping) retracted_swap.set(motion.extruder, retracting);
|
||||
#endif
|
||||
|
||||
/* // debugging
|
||||
SERIAL_ECHOLNPGM("retracting ", AS_DIGIT(retracting));
|
||||
SERIAL_ECHOLNPGM("swapping ", AS_DIGIT(swapping));
|
||||
SERIAL_ECHOLNPGM("active_extruder ", active_extruder);
|
||||
SERIAL_ECHOLNPGM("motion.extruder ", motion.extruder);
|
||||
EXTRUDER_LOOP() {
|
||||
SERIAL_ECHOLNPGM("retracted[", e, "] ", AS_DIGIT(retracted[e]));
|
||||
#if HAS_MULTI_EXTRUDER
|
||||
SERIAL_ECHOLNPGM("retracted_swap[", e, "] ", AS_DIGIT(retracted_swap[e]));
|
||||
#endif
|
||||
}
|
||||
SERIAL_ECHOLNPGM("current_position.z ", current_position.z);
|
||||
SERIAL_ECHOLNPGM("current_position.e ", current_position.e);
|
||||
SERIAL_ECHOLNPGM("motion.position.z ", motion.position.z);
|
||||
SERIAL_ECHOLNPGM("motion.position.e ", motion.position.e);
|
||||
SERIAL_ECHOLNPGM("current_hop ", current_hop);
|
||||
//*/
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user