Compare commits

..

2 Commits

Author SHA1 Message Date
D.R.racer fba81a5d55 Version changed (3.10.2-BETA1 build 4708) 2022-02-18 17:02:58 +01:00
DRracer f65256347a
Merge pull request #3409 from leptun/MK3_3.10.2_crash_on_thermistor_pullup
MK3 3.10.2 crash on thermistor pullup
2022-02-16 09:18:38 +01:00
818 changed files with 77639 additions and 256849 deletions

View File

@ -1,21 +0,0 @@
# If a statement is wrapped to more than one line, than dangle the closing
# parenthesis on it's own line.
dangle_parens = True
dangle_align = 'child'
# If true, the parsers may infer whether or not an argument list is sortable
# (without annotation).
autosort = True
# How wide to allow formatted cmake files
line_width = 100
additional_commands = {
"target_sources": {
"kwargs": {
"PUBLIC": "*",
"PRIVATE": "*",
"INTERFACE": "*",
}
},
}

View File

@ -15,3 +15,4 @@ max_line_length = 100
[lang/po/*.po]
end_of_line = crlf
trim_trailing_whitespace = false

3
.gitattributes vendored
View File

@ -1,2 +1 @@
lang/po/*.po text eol=crlf diff=po
lang/po/*.pot text diff=po
lang/po/*.po text eol=crlf

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]<Enter comprehensive title>"
labels: bug
assignees: ''
---
Please, before you create a new bug report, please make sure you searched in open and closed issues and couldn't find anything that matches.
**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
**Printer firmware version**- [e.g. 3.8.1, 3.8.1-RC1, ...]
**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
**MMU upgrade firmware version [e.g. 1.0.6, 1.0.6-RC2, ...]
**SD card or USB/Octoprint**
Please let us know if you print via SD card or USB/Octoprint
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Please describe steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**G-code**
Please attach a G-code. This will make it easier for us to replicate the error.
**Video**
Please attach a video. It usually helps to solve the problem.

View File

@ -1,96 +0,0 @@
name: Bug report
description: File a bug report
title: '[BUG] '
labels:
- bug
body:
- type: markdown
attributes:
value: |
Before you create a new bug report, please check if an issue with it already exists (either open or closed) by using the search bar on the issues page. If it does, comment there. Even if it's closed, we can reopen it based on your comment.
- type: dropdown
id: printer_model
attributes:
label: Printer model
description: Enter the printer model(s) where you encountered the issue
options:
- MK3S/+
- MK3
- MK2.5S
- MK2.5
validations:
required: true
- type: dropdown
id: mmu_model
attributes:
label: MMU model
description: Enter the MMU model(s) where you encountered the issue
multiple: false
options:
- No-MMU
- MMU3
- MMU2S
validations:
required: true
- type: input
id: firmware_version
attributes:
label: Firmware versions
description: |
If you're using a custom firmware (not downloaded from Prusa), please note that!
placeholder: '3.14.0, 3.12.0-RC1, 3.14.0 and 3.0.2...'
validations:
required: true
- type: input
id: optional_upgrades
attributes:
label: Upgrades and modifications
description: 'If your printer has upgrades or was modified, please note that! If not, please write None or leave blank.'
placeholder: |
None, custom extruder/hotend (which), different frame, ...
- type: dropdown
id: printing_from
attributes:
label: Printing from...
multiple: false
options:
- SD Card
- PrusaLink
- PrusaConnect
- OctoPrint
- Other host software
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe the bug
description: Write a concise description of the bug.
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: How to reproduce
description: |
If you are able to reproduce the issue - meaning that you can trigger it yourself by following certain steps - please describe the step-by-step process in as much detail as possible!
- type: textarea
id: expected_behavior
attributes:
label: Expected behavior
description: |
If the printer did something unexpected, or if the procedure is missing a step that would resolve the issue, please provide a step-by-step process of how it should behave.
- type: textarea
id: files
attributes:
label: Files
description: |
Provide at least one of these (ideally as many as you can) to help developers track down the bug.
*To upload files, compress them into a .zip file and drag them to the text area to upload.* Images and videos can be uploaded directly.
- **gcode** file
- **3mf project** which includes the model and printer settings
- **video** or **photos** of the issue happening
**Crash dump: Do not share the file publicly**, as the crash dump contains a raw snapshot of the printer's memory and may include unencrypted sensitive information.
Please send the crash dump file to Prusa by emailing it to reports@prusa3d.com and referencing this issue. In reply to the email, you will be automatically assigned a reference code to be mentioned in the issue. Sharing this file is important and helps us investigate the bug.

View File

@ -1,25 +0,0 @@
name: Community
description: Related to "Community made" features
title: '[Community made] '
labels:
- community_made
body:
- type: markdown
attributes:
value: >
Prusa Research will NOT follow up these issues!
The maintainers of the "Community made" feature should/will react.
Please, before you create a new "Community made" ticket, please make sure you searched in open and closed issues and couldn't find anything that matches.
- type: textarea
id: which_community
attributes:
label: Which Community made feature do you want to address?
validations:
required: true
- type: textarea
id: What_about_community
attributes:
label: What is your request/question/suggestion?
validations:
required: true

View File

@ -1,11 +0,0 @@
contact_links:
- name: Do you need Support?
url: https://help.prusa3d.com/article/customer-support_2287
about: If you are not sure whether what you are reporting is a bug, please contact our support team first. We are providing full 24/7 customer support.
- name: Knowledge Base
url: https://help.prusa3d.com/
about: We have a comprehensive help documentation that could be helpful for troubleshooting.
- name: Prusa Forum
url: https://forum.prusa3d.com/
about: Please get in touch on our Prusa Forum! (Not an official support channel)
blank_issues_enabled: false

20
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View File

@ -0,0 +1,20 @@
---
name: Enhancement
about: Suggest an idea for this project
title: " [ENHANCEMENT]<Enter comprehensive title>"
labels: enhancement
assignees: ''
---
Please, before you create a new feature request, please make sure you searched in open and closed issues and couldn't find anything that matches.
Enter what type of printer or upgrade the enhancement applies to.
**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
**Is your enhancement related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.

View File

@ -1,35 +0,0 @@
name: Enhancement
description: Suggest an improvement of the existing functionality
title: '[ENHANCEMENT] '
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
Before you create a new enhancement, please check if an issue with it already exists (either open or closed) by using the search bar on the issues page.
- type: checkboxes
id: printer_model
attributes:
label: Printer model
description: Select the printer model(s) where you would like this enhancement
options:
- label: MK3S/+
- label: MK3
- label: MK2.5S
- label: MK2.5
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe the enhancement
description: How would this enhancement improve your experience? Do you have a specific use case where this enhancemnet is especially needed?
validations:
required: true
- type: textarea
id: expected_functionality
attributes:
label: Expected functionality
description: |
Describe the way the enhancement would change existing functionality. You can also describe it in a step-by-step basis if applicable.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE REQUEST]<Enter comprehensive title>"
labels: feature request
assignees: ''
---
Please, before you create a new feature request, please make sure you searched in open and closed issues and couldn't find anything that matches.
If it makes sense, enter what type of printer or upgrade the feature request applies to.
**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.

View File

@ -1,35 +0,0 @@
name: Feature request
description: Suggest new functionality
title: '[FEATURE REQUEST] '
labels:
- feature request
body:
- type: markdown
attributes:
value: |
Before you create a new feature request, please check if an issue with it already exists (either open or closed) by using the search bar on the issues page.
- type: checkboxes
id: printer_model
attributes:
label: Printer model
description: Select the printer model(s) where you would like this feature
options:
- label: MK3S/+
- label: MK3
- label: MK2.5S
- label: MK2.5
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe the feature
description: How would this feature improve the printer? Are there specific use cases where this would be beneficial? Describe how you would use it.
validations:
required: true
- type: textarea
id: expected_functionality
attributes:
label: Expected functionality
description: |
Describe the way the feature would work. You can also describe it in a step-by-step basis if applicable.

12
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@ -0,0 +1,12 @@
---
name: Question
about: What do you want to know?
title: "[QUESTION]<Enter comprehensive title>"
labels: question
assignees: ''
---
Please, before you create a new question, please make sure you searched in open and closed issues and couldn't find anything that matches.
**What is your question?**

View File

@ -1,16 +0,0 @@
name: Question
description: Ask a firmware specific question
title: '[QUESTION] '
labels:
- question
body:
- type: markdown
attributes:
value: |
Before you create a new question, please check if an issue with it already exists (either open or closed) by using the search bar on the issues page.
- type: textarea
id: question
attributes:
label: Question
validations:
required: true

View File

@ -1,178 +0,0 @@
name: ci-build
on:
pull_request:
branches:
- '*'
push:
branches: [ MK3, MK3_* ]
tags:
- 'v*'
- 't*'
- 'c*'
env:
GH_ANNOTATIONS: 1
jobs:
build:
runs-on: ubuntu-latest
steps:
# setup base required dependencies
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install cmake ninja-build python3-pyelftools python3-regex python3-polib
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout ${{ github.event.pull_request.head.ref }}
uses: actions/checkout@v4
if: ${{ github.event.pull_request }}
with:
ref: ${{ github.event.pull_request.head.sha }}
submodules: true
fetch-depth: 0
- name: Checkout ${{ github.event.ref }}
uses: actions/checkout@v4
if: ${{ !github.event.pull_request }}
with:
ref: ${{ github.event.ref }}
submodules: true
fetch-depth: 0
- name: Cache Dependencies
uses: actions/cache@v4
id: cache-pkgs
with:
path: ".dependencies"
key: "build-deps-1_0_0-linux"
- name: Setup build dependencies
run: |
./utils/bootstrap.py
- name: Cache permissions
run: sudo chmod -R 744 .dependencies
- name: Build
run: |
mkdir build
cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake/AvrGcc.cmake" -DCMAKE_BUILD_TYPE=Release -G Ninja
ninja
- name: Upload artifacts
if: ${{ !github.event.pull_request }}
uses: actions/upload-artifact@v4
with:
name: Firmware
path: build/*.hex
- name: RELEASE THE KRAKEN
if: startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/tags/t') || startsWith(github.ref, 'refs/tags/c')
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: ${{ github.ref_name }}
draft: true
files: |
${{ github.workspace }}/build/release/*.hex
${{ github.workspace }}/build/release/*.zip
check-lang:
runs-on: ubuntu-latest
steps:
# setup base required dependencies
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install gcc-11 g++11 lcov cmake ninja-build python3-pyelftools python3-regex python3-polib
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout ${{ github.event.pull_request.head.ref }}
uses: actions/checkout@v4
if: ${{ github.event.pull_request }}
with:
ref: ${{ github.event.pull_request.head.sha }}
submodules: true
fetch-depth: 0
- name: Checkout ${{ github.event.ref }}
uses: actions/checkout@v4
if: ${{ !github.event.pull_request }}
with:
ref: ${{ github.event.ref }}
submodules: true
fetch-depth: 0
- name: Cache Dependencies
uses: actions/cache@v4
id: cache-pkgs
with:
path: ".dependencies"
key: "build-deps-1_0_0-linux"
- name: Setup build dependencies
run: |
./utils/bootstrap.py
- name: Cache permissions
run: sudo chmod -R 744 .dependencies
- name: Run check
run: |
mkdir build
cd build
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="../cmake/AvrGcc.cmake" -DCMAKE_BUILD_TYPE=Release -G Ninja
ninja check_lang
tests:
runs-on: ubuntu-latest
steps:
# setup base required dependencies
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install gcc-11 g++11 lcov cmake ninja-build python3-pyelftools python3-regex python3-polib
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout ${{ github.event.pull_request.head.ref }}
uses: actions/checkout@v4
if: ${{ github.event.pull_request }}
with:
ref: ${{ github.event.pull_request.head.sha }}
submodules: true
fetch-depth: 0
- name: Checkout ${{ github.event.ref }}
uses: actions/checkout@v4
if: ${{ !github.event.pull_request }}
with:
ref: ${{ github.event.ref }}
submodules: true
fetch-depth: 0
- name: Cache Dependencies
uses: actions/cache@v4
id: cache-pkgs
with:
path: ".dependencies"
key: "build-deps-1_0_0-linux"
- name: Setup build dependencies
run: |
./utils/bootstrap.py
- name: Cache permissions
run: sudo chmod -R 744 .dependencies
- name: Run check
run: |
mkdir build
cd build
cmake .. -G Ninja
ninja test_run_all

View File

@ -1,56 +0,0 @@
#!/bin/sh
MESSAGE=$1
BASE_DIR=$2
PR_DIR=$3
shift 3
# this assumes we're running from the repository root
AVR_SIZE=$(echo .dependencies/avr-gcc-*/bin/avr-size)
test -x "$AVR_SIZE" || exit 2
avr_size()
{
"$AVR_SIZE" --mcu=atmega2560 -C "$@"
}
avr_flash()
{
avr_size "$@" | sed -ne 's/^Program: *\([0-9]\+\).*/\1/p'
}
avr_ram()
{
avr_size "$@" | sed -ne 's/^Data: *\([0-9]\+\).*/\1/p'
}
cat <<EOF > "$MESSAGE"
All values in bytes. Δ Delta to base
| Target| ΔFlash | ΔSRAM | Used Flash | Used SRAM | Free Flash | Free SRAM |
| ------| ------ | ----- | -----------| --------- | ---------- | --------- |
EOF
einsy_max_upload_size=$(grep "prusa_einsy_rambo.upload.maximum_size" .dependencies/prusa3dboards-*/boards.txt | cut -d "=" -f2)
einsy_max_upload_data_size=8192
for TARGET in $@
do
# strip the multilang prefix
variant=${TARGET%_MULTILANG}
base_bin=$(echo ${BASE_DIR}/build_gen/$variant/${variant}_lang_base)
base_flash=$(avr_flash "$base_bin")
base_ram=$(avr_ram "$base_bin")
pr_bin=$(echo ${PR_DIR}/build_gen/$variant/${variant}_lang_base)
pr_flash=$(avr_flash "$pr_bin")
pr_ram=$(avr_ram "$pr_bin")
flash_d=$(($pr_flash - $base_flash))
ram_d=$(($pr_ram - $base_ram))
flash_free=$(($einsy_max_upload_size - $pr_flash))
ram_free=$(($einsy_max_upload_data_size - $pr_ram))
echo "| \`$TARGET\` | $flash_d | $ram_d | $pr_flash | $pr_ram | $flash_free | $ram_free |" >> "$MESSAGE"
done

View File

@ -1,79 +0,0 @@
name: pr-size
on:
pull_request_target:
branches: [ MK3, MK3_* ]
env:
TARGETS: "MK3S_MULTILANG MK3_MULTILANG"
jobs:
build:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
# setup base required dependencies
- name: Setup dependencies
run: |
sudo apt-get update
sudo apt-get install cmake ninja-build python3-pyelftools python3-regex python3-polib
# build the base branch
- name: Checkout base
uses: actions/checkout@v4
- name: Cache Dependencies
uses: actions/cache@v4
id: cache-pkgs
with:
path: ".dependencies"
key: "build-deps-1_0_0-linux"
- name: Setup build dependencies
run: |
./utils/bootstrap.py
- name: Cache permissions
run: sudo chmod -R 744 .dependencies
- name: Build base
run: |
rm -rf build-base
mkdir build-base
cd build-base
cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake/AvrGcc.cmake" -DCMAKE_BUILD_TYPE=Release -G Ninja
ninja $TARGETS
# save pr-size for later use
- name: Save base data
run: |
cp -f ./.github/workflows/pr-size.sh build-base
# build the PR branch
- name: Checkout PR
uses: actions/checkout@v4
with:
clean: false
ref: ${{ github.event.pull_request.head.sha }}
- name: Build PR
run: |
rm -rf build-pr
mkdir build-pr
cd build-pr
cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake/AvrGcc.cmake" -DCMAKE_BUILD_TYPE=Release -G Ninja
ninja $TARGETS
# extract/show build differences
- name: Calculate binary changes
run: |
rm -rf build-changes
./build-base/pr-size.sh build-changes build-base build-pr $TARGETS
- name: Add PR Comment
uses: mshick/add-pr-comment@v2
with:
message-path: build-changes

View File

@ -1,30 +0,0 @@
name: Mark stale issues
on:
schedule:
# 1:30 AM on MON/THU
- cron: "30 1 * * 1,2,3,4"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Don't ever mark PRs as stale.
days-before-pr-stale: -1
stale-issue-message: 'Thank you for your contribution to our project. This issue has not received any updates for 60 days and may be considered "stale." If this issue is still important to you, please add an update within the next 7 days to keep it open. Administrators can manually reopen the issue if necessary.'
close-issue-message: 'This issue has been closed due to lack of recent activity. Please consider opening a new one if needed.'
# Don't act on things assigned to a milestone or assigned to someone.
exempt-all-milestones: true
exempt-all-assignees: true
enable-statistics: true
# Disable this and change the operations per run back to 30 when this goes live.
debug-only: false
operations-per-run: 200
stale-issue-label: 'stale-issue'
stale-pr-label: 'stale-pr'
ascending: true

84
.gitignore vendored
View File

@ -1,31 +1,57 @@
# IDE data
/.settings
/.project
/.cproject
# cmake
/build/
/build_gen/
/.dependencies
/compile_commands.json
# Temporary configuration
/Firmware/Configuration_prusa.h
# Temporary language files
/lang/po/*.mo
/lang/tmp/
/lang/Firmware-intl.hex
/lang/Firmware-intl-en_*.hex
/lang/*.map
# Temporary files and directories
*[~#]
*.tmp
*.bak
.DS_Store
.settings
.project
.cproject
Debug
__pycache__
# Generated files
Firmware/Configuration_prusa.h
Firmware/Doc
/Firmware/.vs/Firmware/v14
/Firmware/__vm
/Firmware/Firmware.sln
/Firmware/Firmware.vcxproj
/Firmware/Firmware.vcxproj.filters
/Firmware/Firmware - Shortcut.lnk
/Firmware/variants/1_75mm_MK3-MMU-EINSy10a-E3Dv6full.h.bak
/Firmware/Marlin_main.cpp~RF12cfae7.TMP
/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h.bak
/html
/latex
/Doxyfile
/Firmware/builds/1_75mm_MK3-EINY04-E3Dv6full
/Firmware/Configuration_prusa.h.bak
/Firmware/Configuration_prusa_backup.h
/Firmware/ultralcd_implementation_hitachi_HD44780.h.bak
/Firmware/ultralcd.cpp.bak
/Firmware/temperature.cpp.bak
/Firmware/pins.h.bak
/Firmware/Marlin_main.cpp.bak
/Firmware/language_pl.h.bak
/Firmware/language_it.h.bak
/Firmware/language_es.h.bak
/Firmware/language_en.h.bak
/Firmware/language_de.h.bak
/Firmware/language_cz.h.bak
/Firmware/variants/1_75mm_MK2-MultiMaterial-RAMBo13a-E3Dv6full.h
/Firmware/variants/1_75mm_MK2-MultiMaterial-RAMBo10a-E3Dv6full.h
/Firmware/variants/1_75mm_MK2-EINY01-E3Dv6full.h.bak
/Firmware/variants/1_75mm_MK1-RAMBo13a-E3Dv6full.h
/Firmware/variants/1_75mm_MK1-RAMBo10a-E3Dv6full.h
/lang/*.bin
/lang/*.hex
/lang/*.dat
/lang/*.tmp
/lang/*.out
/lang/not_tran*.txt
/lang/not_used*.txt
/lang/progmem1.chr
/lang/progmem1.lss
/lang/progmem1.txt
/lang/progmem1.var
/lang/text.sym
/lang/textaddr.txt
/build-env/
/Firmware/Doc/
/Firmware/Firmware.vcxproj
/Firmware/Configuration_prusa_bckp.h
/Firmware/variants/printers.h
Configuration.tmp
config.tmp

35
.travis.yml Normal file
View File

@ -0,0 +1,35 @@
dist: trusty
before_install:
- sudo apt-get install -y ninja-build
# Arduino IDE adds a lot of noise caused by network traffic, trying to firewall it off
- sudo iptables -P INPUT DROP
- sudo iptables -P FORWARD DROP
- sudo iptables -P OUTPUT ACCEPT
- sudo iptables -A INPUT -i lo -j ACCEPT
- sudo iptables -A OUTPUT -o lo -j ACCEPT
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
script:
- bash -x test.sh
- cp Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK3S-EINSy10a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK3-EINSy10a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK25S-RAMBo13a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK25S-RAMBo10a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK25-RAMBo13a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK25-RAMBo10a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK2-RAMBo13a-E3Dv6full variant failed" && false; }
- rm Firmware/Configuration_prusa.h
- cp Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h
- bash -x build.sh || { echo "1_75mm_MK2-RAMBo10a-E3Dv6full variant failed" && false; }

View File

@ -1,10 +0,0 @@
[
{
"name": "avr-gcc",
"toolchainFile": "${workspaceFolder}/cmake/AvrGcc.cmake",
"cmakeSettings": {
"CMAKE_MAKE_PROGRAM": "${workspaceFolder}/.dependencies/ninja-1.12.1/ninja",
"CMAKE_BUILD_TYPE": "Release"
}
}
]

View File

@ -1,11 +0,0 @@
buildType:
default: debug
choices:
debug:
short: Debug
long: Emit debug information
buildType: Debug
release:
short: Release
long: Optimize generated code
buildType: Release

10
.vscode/settings.json vendored
View File

@ -1,10 +0,0 @@
{
"cmake.configureOnOpen": true,
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json",
"cmake.cmakePath": "${workspaceFolder}/.dependencies/cmake-3.22.5/bin/cmake",
"cmake.generator": "Ninja",
"files.insertFinalNewline": true,
"files.associations": {
"xlocale": "cpp"
}
}

View File

@ -1,658 +1,24 @@
cmake_minimum_required(VERSION 3.19)
include(cmake/Utilities.cmake)
include(cmake/GetGitRevisionDescription.cmake)
include(cmake/ReproducibleBuild.cmake)
include(cmake/ProjectVersion.cmake)
resolve_version_variables()
OPTION(ENFORCE_VERSION_MATCH "Enforce checking that configuration.h matches any parsed git tags" OFF)
OPTION(NO_TAG_IS_FATAL "If tag parsing fails, issue a fatal error" OFF)
set(PROJECT_VERSION_HASH
"<auto>"
CACHE
STRING
"Version suffix to be appended to the final filename (<ver+PROJECT_VERSION_HASH>). Overrides git hash if set."
)
if(PROJECT_VERSION_HASH STREQUAL "<auto>")
set(PROJECT_VERSION_HASH "${FW_COMMIT_HASH}")
endif()
set(PROJECT_VERSION_FULL
"<auto>"
CACHE
STRING
"Full version string to be shown on the info screen in settings. Overrides git version if set."
)
if(PROJECT_VERSION_FULL STREQUAL "<auto>")
set(PROJECT_VERSION_FULL "${FW_COMMIT_DSC}")
endif()
set(PROJECT_REPOSITORY
"Unknown"
CACHE STRING "Repository string to be shown on the info screen in settings."
)
set(CUSTOM_COMPILE_OPTIONS
""
CACHE STRING "Allows adding custom C/C++ flags"
)
#set(FN_VERSION_SUFFIX "FW${PROJECT_VERSION}+${PROJECT_VERSION_HASH}")
set(FN_VERSION_SUFFIX "FW_${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_REV}")
if(PROJECT_VERSION_FLV AND PROJECT_VERSION_FLV_VER)
set (FN_VERSION_SUFFIX "${FN_VERSION_SUFFIX}-${PROJECT_VERSION_FLV}${PROJECT_VERSION_FLV_VER}")
endif()
set(FN_VERSION_DEBUG_SUFFIX "${FN_VERSION_SUFFIX}+${PROJECT_VERSION_COMMIT}")
# Inform user about the resolved settings from Configuration.h
message(STATUS "Project version (Configuration.h): ${PROJECT_VERSION}")
#message(STATUS "Project version major............: ${PROJECT_VERSION_MAJOR}") #For debuging
#message(STATUS "Project version minor............: ${PROJECT_VERSION_MINOR}") #For debuging
#message(STATUS "Project version revision.........: ${PROJECT_VERSION_REV}") #For debuging
#message(STATUS "Project version flavor...........: ${PROJECT_VERSION_FLV}") #For debuging
#message(STATUS "Project version fla-revison......: ${PROJECT_VERSION_FLV_VER}") #For debuging
#message(STATUS "Project version commit number....: ${PROJECT_VERSION_COMMIT}") #For debuging
message(STATUS "Filename suffix..................: ${FN_VERSION_SUFFIX}")
message(STATUS "Filename debug suffix ...........: ${FN_VERSION_DEBUG_SUFFIX}")
#message(STATUS "Host OS .........................: ${CMAKE_HOST_SYSTEM_NAME}")
# testing
# SET(FW_COMMIT_DSC "v3.13.0-1234")
if(NOT "${PROJECT_VERSION_HASH}" STREQUAL "UNKNOWN" AND NOT "${FW_COMMIT_DSC}" MATCHES ".+NOTFOUND.+") # else -> no commit hash is known... likely no git.
string(REGEX MATCH "[v|t|c]([0-9]+)\.([0-9]+)\.([0-9]+)-?(${DEV_TAG_REGEX})?([0-9]+)?-([0-9]+)" TAG_VERSION "${FW_COMMIT_DSC}")
if (CMAKE_MATCH_4) # Do we have a build type?
decode_flavor_code(PROJECT_VER_TAG_FLV "${CMAKE_MATCH_4}" "${CMAKE_MATCH_5}")
else()
# No dev status found, it must be a final tag.
decode_flavor_code(PROJECT_VER_TAG_FLV "RELEASED" "0")
endif()
if(ENFORCE_VERSION_MATCH)
if(NOT ${CMAKE_MATCH_1} STREQUAL ${PROJECT_VERSION_MAJOR})
message(FATAL_ERROR "Major version of current tag disagrees with Configuration.h ${CMAKE_MATCH_1}!=${PROJECT_VERSION_MAJOR}")
endif()
if(NOT ${CMAKE_MATCH_2} STREQUAL ${PROJECT_VERSION_MINOR})
message(FATAL_ERROR "Minor version of current tag disagrees with Configuration.h ${CMAKE_MATCH_2}!=${PROJECT_VERSION_MINOR}")
endif()
if(NOT ${CMAKE_MATCH_3} STREQUAL ${PROJECT_VERSION_REV})
message(FATAL_ERROR "Rev version of current tag disagrees with Configuration.h ${CMAKE_MATCH_3}!=${PROJECT_VERSION_REV}")
endif()
if(NOT ${PROJECT_VER_TAG_FLV} STREQUAL ${PROJECT_VERSION_TWEAK})
message(FATAL_ERROR "Dev status of current tag disagrees with Configuration.h ${PROJECT_VER_TAG_FLV}!=${PROJECT_VERSION_TWEAK}")
endif()
# Note - we don't check the commit counter, that'd be too much of a headache. Maybe it
# should be an error only on a tagged build?
MESSAGE(STATUS "Configuration.h and tag match: OK (${PROJECT_VERSION}/${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${PROJECT_VER_TAG_FLV})")
else()
MESSAGE(STATUS "Configuration.h and tag (not enforced): (${PROJECT_VERSION}/${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${PROJECT_VER_TAG_FLV})")
endif()
MESSAGE(STATUS "Commit Nr: Configuration.h: ${PROJECT_VERSION_COMMIT} Tag: ${CMAKE_MATCH_6}")
MESSAGE(STATUS "These tag values will override Configuration.h")
SET(PROJECT_VERSION ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${PROJECT_VER_TAG_FLV})
SET(PROJECT_VERSION_COMMIT ${CMAKE_MATCH_6})
git_get_repository(PROJECT_REPOSITORY)
else(GIT_FOUND)
if (NO_TAG_IS_FATAL)
MESSAGE(FATAL_ERROR "Git was not found or an error occurred parsing the tag. This is a fatal error according to the settings.")
else()
MESSAGE(STATUS "Git was not found or an error occurred parsing the tag. Falling back to Configuration.h values (${PROJECT_VERSION}).")
endif()
set(FW_COMMIT_HASH ${FW_COMMIT_HASH_UNKNOWN}) # Clear it, the code expects a binary...
set(PROJECT_VERSION_TIMESTAMP "0")
endif()
if(CMAKE_MATCH_1 AND CMAKE_MATCH_2)
set(FN_VERSION_SUFFIX "FW_${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
endif()
if(CMAKE_MATCH_4 AND CMAKE_MATCH_5)
set (FN_VERSION_SUFFIX "${FN_VERSION_SUFFIX}-${CMAKE_MATCH_4}${CMAKE_MATCH_5}")
endif()
if(CMAKE_MATCH_6 AND PROJECT_VERSION_HASH)
set(FN_VERSION_DEBUG_SUFFIX "${FN_VERSION_SUFFIX}+${CMAKE_MATCH_6}_${PROJECT_VERSION_HASH}")
endif()
# Inform user about the resolved settings from github
message(STATUS "Project version git..............: ${PROJECT_VERSION}")
message(STATUS "Project version git hash.........: ${PROJECT_VERSION_HASH}")
message(STATUS "Project version git description..: ${PROJECT_VERSION_FULL}")
#message(STATUS "Project version git major........: ${CMAKE_MATCH_1}") #For debuging
#message(STATUS "Project version git minor........: ${CMAKE_MATCH_2}") #For debuging
#message(STATUS "Project version git revision.....: ${CMAKE_MATCH_3}") #For debuging
#message(STATUS "Project version git flavor.......: ${CMAKE_MATCH_4}") #For debuging
#message(STATUS "Project version git fla-revison..: ${CMAKE_MATCH_5}") #For debuging
#message(STATUS "Project version git commit number: ${CMAKE_MATCH_6}") #For debuging
message(STATUS "Filename suffix .................: ${FN_VERSION_SUFFIX}")
message(STATUS "Filename debug suffix ...........: ${FN_VERSION_DEBUG_SUFFIX}")
# Language configuration
set(MAIN_LANGUAGES
cs de es fr it pl
CACHE STRING "The list of 'main' languages to be included, in the correct order"
)
set(COMMUNITY_LANGUAGES
nl
ro
hu
hr
sk
sv
no
CACHE STRING "The list of community languages to be included, in the correct order"
)
set(SELECTED_LANGUAGES ${MAIN_LANGUAGES} ${COMMUNITY_LANGUAGES})
get_dependency_directory(prusa3dboards PRUSA_BOARDS_DIR)
project(Prusa-Firmware VERSION ${PROJECT_VERSION})
add_subdirectory(lib)
# Get LANG_MAX_SIZE from sources
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/Firmware/config.h MAX_SIZE_LINE
REGEX "^#define \+LANG_SIZE_RESERVED \+"
)
string(REGEX MATCH "0x[0-9]+" MAX_SIZE_HEX "${MAX_SIZE_LINE}")
math(EXPR LANG_MAX_SIZE "${MAX_SIZE_HEX}" OUTPUT_FORMAT DECIMAL)
message("Language maximum size (from config.h): ${LANG_MAX_SIZE} bytes")
# Ditto, this in xflash_layout.h but needs invocation of the preprocessor... :-/
set(LANG_BIN_MAX 249856)
# Check GCC Version
get_recommended_gcc_version(RECOMMENDED_TOOLCHAIN_VERSION)
if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL
${RECOMMENDED_TOOLCHAIN_VERSION}
)
message(WARNING "Recommended AVR toolchain is ${RECOMMENDED_TOOLCHAIN_VERSION}"
", but you have ${CMAKE_CXX_COMPILER_VERSION}"
)
elseif(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(
WARNING
"Recommended compiler for host tools and unittests is GCC, you have ${CMAKE_CXX_COMPILER_ID}."
)
endif()
# append custom C/C++ flags
if(CUSTOM_COMPILE_OPTIONS)
string(REPLACE " " ";" CUSTOM_COMPILE_OPTIONS "${CUSTOM_COMPILE_OPTIONS}")
add_compile_options(${CUSTOM_COMPILE_OPTIONS})
endif()
#
# Global Compiler & Linker Configuration
#
# enable warnings
add_compile_options(-Wall -Wextra -Wno-expansion-to-defined -Wsign-compare)
# default standards for all targets
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# support _DEBUG macro (some code uses to recognize debug builds)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(_DEBUG)
endif()
#
# Firmware - get file lists.
#
set(FW_SOURCES
adc.cpp
backlight.cpp
BlinkM.cpp
bootapp.c
cardreader.cpp
cmdqueue.cpp
Configuration.cpp
ConfigurationStore.cpp
Dcodes.cpp
eeprom.cpp
fancheck.cpp
Filament_sensor.cpp
first_lay_cal.cpp
heatbed_pwm.cpp
host.cpp
la10compat.cpp
language.c
lcd.cpp
Marlin_main.cpp
MarlinSerial.cpp
meatpack.cpp
menu.cpp
mesh_bed_calibration.cpp
mesh_bed_leveling.cpp
messages.cpp
mmu2.cpp
mmu2_crc.cpp
mmu2_error_converter.cpp
mmu2_fsensor.cpp
mmu2_log.cpp
mmu2_marlin1.cpp
mmu2_power.cpp
mmu2_progress_converter.cpp
mmu2_protocol.cpp
mmu2_protocol_logic.cpp
mmu2_reporting.cpp
mmu2_serial.cpp
motion_control.cpp
optiboot_xflash.cpp
pat9125.cpp
planner.cpp
power_panic.cpp
printer_state.cpp
Prusa_farm.cpp
rbuf.c
Sd2Card.cpp
SdBaseFile.cpp
SdFatUtil.cpp
SdFile.cpp
SdVolume.cpp
sm4.cpp
sound.cpp
speed_lookuptable.cpp
spi.c
SpoolJoin.cpp
stepper.cpp
stopwatch.cpp
strtod.c
swi2c.c
Tcodes.cpp
temperature.cpp
timer02.c
Timer.cpp
tmc2130.cpp
tone04.c
twi.cpp
uart2.cpp
ultralcd.cpp
util.cpp
xflash.c
xflash_dump.cpp
xyzcal.cpp
)
list(TRANSFORM FW_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/Firmware/)
set(AVR_SOURCES
wiring_digital.c
WInterrupts.c
wiring_pulse.c
hooks.c
wiring.c
wiring_analog.c
wiring_shift.c
CDC.cpp
PluggableUSB.cpp
HardwareSerial.cpp
HardwareSerial0.cpp
HardwareSerial1.cpp
HardwareSerial3.cpp
IPAddress.cpp
HardwareSerial2.cpp
Print.cpp
Stream.cpp
Tone.cpp
USBCore.cpp
WMath.cpp
WString.cpp
abi.cpp
main.cpp
)
list(TRANSFORM AVR_SOURCES PREPEND ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/)
#
# Target configuration
#
if(CMAKE_CROSSCOMPILING)
set_source_epoch(${PROJECT_VERSION_TIMESTAMP})
# default optimization flags
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -g -DNDEBUG")
set(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
set(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
# mcu and target-related settings
add_compile_options(
-mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_PRUSA_EINSY_RAMBO
-DARDUINO_ARCH_AVR
)
add_link_options(-mmcu=atmega2560 -Wl,-u,vfprintf -lprintf_flt -lm)
# disable some C++ language features
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-threadsafe-statics>)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
# disable exceptions
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-unwind-tables>)
# split and gc sections
add_compile_options(-ffunction-sections -fdata-sections)
add_link_options(-ffunction-sections -fdata-sections -Wl,--gc-sections)
# LTO (with custom options)
add_compile_options(-flto -fno-fat-lto-objects)
add_link_options(-flto)
# Create this target before we apply the GC options
add_library(avr_core STATIC ${AVR_SOURCES})
set_reproducible_target(avr_core)
target_include_directories(
avr_core PRIVATE ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/
${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/
)
endif()
# Meta targets to build absolutely everything
add_custom_target(ALL_FIRMWARE)
add_custom_target(ALL_ENGLISH)
add_custom_target(ALL_MULTILANG)
add_dependencies(ALL_FIRMWARE ALL_ENGLISH ALL_MULTILANG)
set_target_properties(ALL_MULTILANG PROPERTIES EXCLUDE_FROM_ALL FALSE)
function(add_base_binary variant_name)
add_executable(${variant_name} ${FW_SOURCES} ${FW_HEADERS} ${VARIANT_CFG_DST})
set_target_properties(${variant_name} PROPERTIES EXCLUDE_FROM_ALL TRUE)
set_reproducible_target(${variant_name})
target_include_directories(
${variant_name}
PRIVATE ${PRUSA_BOARDS_DIR}/cores/prusa_einsy_rambo/
${PRUSA_BOARDS_DIR}/variants/prusa_einsy_rambo/ ${CMAKE_SOURCE_DIR}/Firmware
)
target_link_libraries(${variant_name} avr_core)
# configure linker script
set(LINKER_SCRIPT ${PRUSA_BOARDS_DIR}/ldscripts/avr6.xn)
target_link_options(${variant_name} PUBLIC -Wl,-T,${LINKER_SCRIPT})
# limit the text section to 248K (256K - 8k reserved for the bootloader)
target_link_options(${variant_name} PUBLIC -Wl,--defsym=__TEXT_REGION_LENGTH__=248K)
# produce ASM listing. Note we also specify the .map as a byproduct so it gets cleaned because
# link_options doesn't have a "generated outputs" feature.
add_custom_command(
TARGET ${variant_name}
POST_BUILD
COMMAND ${CMAKE_OBJDUMP} --prefix ${CMAKE_SOURCE_DIR} -CSd ${variant_name} > ${variant_name}.asm
BYPRODUCTS ${variant_name}.asm ${variant_name}.map
)
# inform about the firmware's size in terminal
add_custom_command(
TARGET ${variant_name}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo_append "${variant_name} "
COMMAND ${CMAKE_SIZE_UTIL} -C --mcu=atmega2560 ${variant_name}
)
report_size(${variant_name})
# generate linker map file
target_link_options(
${variant_name} PUBLIC -Wl,-Map=${CMAKE_CURRENT_BINARY_DIR}/${variant_name}.map
)
decode_tweak_version(PROJECT_VERSION_FLV PROJECT_VERSION_FLV_VER)
target_compile_definitions(
${variant_name}
PRIVATE CMAKE_CONTROL FW_REPOSITORY="${PROJECT_REPOSITORY}"
FW_COMMIT_HASH="${FW_COMMIT_HASH}"
FW_COMMIT_HASH_LENGTH=${FW_COMMIT_HASH_LENGTH}
FW_MAJOR=${PROJECT_VERSION_MAJOR}
FW_MINOR=${PROJECT_VERSION_MINOR}
FW_REVISION=${PROJECT_VERSION_REV}
FW_COMMITNR=${PROJECT_VERSION_COMMIT}
)
if(NOT PROJECT_VERSION_FLV STREQUAL "RELEASED")
target_compile_definitions(
${variant_name}
PRIVATE
FW_FLAVERSION=${PROJECT_VERSION_FLV_VER}
FW_FLAVOR=${PROJECT_VERSION_FLV}
)
endif()
endfunction()
function(fw_add_variant variant_name)
set(variant_header "variants/${variant_name}.h")
string(REPLACE "1_75mm_" "" variant_name "${variant_name}")
string(REPLACE "-E3Dv6full" "" variant_name "${variant_name}")
# Single-language build
set(FW_EN "${variant_name}_ENGLISH")
#MK3S_MK3S+_FW_3.13.2-RC1_ENGLISH.hex
set(hex_variant_name "${variant_name}")
if(hex_variant_name STRGREATER_EQUAL "MK3S")
string(REPLACE "MK3S" "MK3S_MK3S+" hex_variant_name ${hex_variant_name})
endif()
set(FW_HEX "${CMAKE_BINARY_DIR}/${hex_variant_name}_${FN_VERSION_SUFFIX}_ENGLISH.hex")
#message(STATUS "Hex filename: ${FW_HEX}")
add_base_binary(${FW_EN})
target_compile_definitions(${FW_EN} PUBLIC LANG_MODE=0 FW_VARIANT="${variant_header}")
add_custom_command(
TARGET ${FW_EN}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O ihex ${FW_EN} ${FW_EN}.hex
COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_EN}.hex ${FW_HEX}
BYPRODUCTS ${FW_EN}.hex ${FW_HEX}
COMMENT "Generating ${FW_EN}.hex"
)
add_dependencies(ALL_ENGLISH ${FW_EN})
# Multi-language build/s
set(FW_LANG_BASE "${variant_name}_lang_base")
set(FW_LANG_PATCH "${variant_name}_lang_patch")
add_base_binary(${FW_LANG_BASE})
target_compile_definitions(${FW_LANG_BASE} PUBLIC LANG_MODE=1 FW_VARIANT="${variant_header}")
# Construct language map
set(LANG_TMP_DIR lang)
set(LANG_MAP ${LANG_TMP_DIR}/${variant_name}_lang.map)
add_custom_command(
OUTPUT ${LANG_MAP}
COMMAND ${CMAKE_OBJCOPY} -O binary ${FW_LANG_BASE} ${FW_LANG_PATCH}.bin
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/lang/lang-map.py ${FW_LANG_BASE} ${FW_LANG_PATCH}.bin > ${LANG_MAP}
COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${FW_LANG_PATCH}.bin ${FW_LANG_PATCH}.hex
DEPENDS ${FW_LANG_BASE}
BYPRODUCTS ${FW_LANG_PATCH}.bin ${FW_LANG_PATCH}.hex
COMMENT "Generating ${variant_name} language map"
)
# Base targets for language checks
add_custom_target(check_lang_${variant_name})
add_dependencies(check_lang check_lang_${variant_name})
# Build language catalogs
set(LANG_BINS "")
foreach(LANG IN LISTS SELECTED_LANGUAGES)
set(LANG_BIN ${LANG_TMP_DIR}/${variant_name}_${LANG}.bin)
set(PO_FILE "${CMAKE_SOURCE_DIR}/lang/po/Firmware_${LANG}.po")
# Full language checks
add_custom_target(
check_lang_${variant_name}_${LANG}
COMMENT "Checking ${variant_name} language ${LANG}"
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/lang/lang-check.py --map ${LANG_MAP} ${PO_FILE}
DEPENDS ${LANG_MAP} ${PO_FILE}
USES_TERMINAL
)
add_dependencies(check_lang_${variant_name} check_lang_${variant_name}_${LANG})
add_dependencies(check_lang_${LANG} check_lang_${variant_name}_${LANG})
add_custom_command(
OUTPUT ${LANG_BIN}
# Check po file for errors _only_
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/lang/lang-check.py --errors-only --map ${LANG_MAP} ${PO_FILE}
# Build the catalog
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/lang/lang-build.py ${LANG_MAP} ${PO_FILE} ${LANG_BIN}
# Check bin size
COMMAND ${CMAKE_COMMAND} -DLANG_MAX_SIZE=${LANG_MAX_SIZE} -DLANG_FILE=${LANG_BIN} -P
${PROJECT_CMAKE_DIR}/Check_lang_size.cmake
DEPENDS ${LANG_MAP} ${PO_FILE}
COMMENT "Generating ${variant_name}_${LANG}.bin"
)
list(APPEND LANG_BINS ${LANG_BIN})
endforeach()
string(FIND ${variant_name} "MK3" HAS_XFLASH)
if(${HAS_XFLASH} GREATER_EQUAL 0)
# X-Flash based build (catalogs appended to patched binary)
set(FW_LANG_FINAL "${variant_name}_MULTILANG")
set(hex_variant_name "${variant_name}")
#MK3S_MK3S+_FW_3.13.2-RC1+7651_deadbeef_MULTILANG.hex
if(hex_variant_name STRGREATER_EQUAL "MK3S")
string(REPLACE "MK3S" "MK3S_MK3S+" hex_variant_name ${hex_variant_name})
endif()
set(LANG_HEX ${CMAKE_BINARY_DIR}/${hex_variant_name}_${FN_VERSION_SUFFIX}_MULTILANG.hex)
set(LANG_DEBUG_HEX ${CMAKE_BINARY_DIR}/${hex_variant_name}_${FN_VERSION_DEBUG_SUFFIX}_MULTILANG.hex)
#message(STATUS "Hex filename .....: ${LANG_HEX}")
#message(STATUS "Hex debug filename: ${LANG_DEBUG_HEX}")
set(LANG_CATBIN ${LANG_TMP_DIR}/${variant_name}_cat.bin)
set(LANG_CATHEX ${LANG_TMP_DIR}/${variant_name}_cat.hex)
add_custom_command(
OUTPUT ${LANG_CATBIN}
COMMAND ${CMAKE_COMMAND} -E cat ${LANG_BINS} > ${LANG_CATBIN}
DEPENDS ${LANG_BINS}
COMMENT "Merging language catalogs"
)
#[[
#add_custom_command(OUTPUT ${LANG_FINAL_BIN}
# COMMAND ${CMAKE_COMMAND} -DLANG_MAX_SIZE=${LANG_BIN_MAX} -DLANG_FILE=${LANG_FINAL_BIN}
# -P ${PROJECT_CMAKE_DIR}/Check_final_lang_bin_size.cmake
# APPEND)
#]]
add_custom_command(
OUTPUT ${LANG_CATHEX}
COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${LANG_CATBIN} ${LANG_CATHEX}
DEPENDS ${LANG_CATBIN}
COMMENT "Generating Hex for language data"
)
add_custom_command(
OUTPUT ${FW_LANG_FINAL}.hex
COMMAND ${CMAKE_COMMAND} -E cat ${FW_LANG_PATCH}.hex ${LANG_CATHEX} > ${FW_LANG_FINAL}.hex
COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${LANG_HEX}
BYPRODUCTS ${LANG_HEX}
COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${LANG_DEBUG_HEX}
BYPRODUCTS ${LANG_DEBUG_HEX}
COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${CMAKE_BINARY_DIR}/release/${hex_variant_name}_${FN_VERSION_SUFFIX}_MULTILANG.hex
BYPRODUCTS ${CMAKE_BINARY_DIR}/release/${hex_variant_name}_${FN_VERSION_SUFFIX}_MULTILANG.hex
DEPENDS ${FW_LANG_PATCH}.hex ${LANG_CATHEX}
COMMENT "Generating final ${FW_LANG_FINAL}.hex"
)
add_custom_target(${FW_LANG_FINAL} DEPENDS ${FW_LANG_FINAL}.hex)
add_dependencies(ALL_MULTILANG ${FW_LANG_FINAL})
else()
set(ALL_VARIANT_HEXES "")
# Non-xflash, e.g. MK2.5
foreach(LANG IN LISTS SELECTED_LANGUAGES)
set(FW_LANG_FINAL ${variant_name}_en-${LANG})
set(LANG_HEX ${CMAKE_BINARY_DIR}/${variant_name}_${FN_VERSION_SUFFIX}_en-${LANG}.hex)
set(LANG_DEBUG_HEX ${CMAKE_BINARY_DIR}/${variant_name}_${FN_VERSION_DEBUG_SUFFIX}_en-${LANG}.hex)
set(LANG_BIN ${LANG_TMP_DIR}/${variant_name}_${LANG}.bin)
# Patched binary with pre-baked secondary language
add_custom_command(
OUTPUT ${FW_LANG_FINAL}.bin
COMMAND ${CMAKE_COMMAND} -E copy ${FW_LANG_PATCH}.bin ${FW_LANG_FINAL}.bin
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/lang/lang-patchsec.py ${FW_LANG_BASE} ${LANG_BIN}
${FW_LANG_FINAL}.bin
DEPENDS ${FW_LANG_BASE} ${FW_LANG_PATCH}.bin ${LANG_BIN}
COMMENT "Generating ${FW_LANG_FINAL}.bin"
)
# Final hex files
add_custom_command(
OUTPUT ${FW_LANG_FINAL}.hex
COMMAND ${CMAKE_OBJCOPY} -I binary -O ihex ${FW_LANG_FINAL}.bin ${FW_LANG_FINAL}.hex
COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${LANG_HEX}
BYPRODUCTS ${LANG_HEX}
COMMAND ${CMAKE_COMMAND} -E create_hardlink ${FW_LANG_FINAL}.hex ${LANG_DEBUG_HEX}
BYPRODUCTS ${LANG_DEBUG_HEX}
DEPENDS ${FW_LANG_FINAL}.bin
COMMENT "Creating ${FW_LANG_FINAL}.hex"
)
add_custom_target(${FW_LANG_FINAL} DEPENDS ${FW_LANG_FINAL}.hex)
list(APPEND ALL_VARIANT_HEXES ${FW_LANG_FINAL})
endforeach()
add_custom_target("${variant_name}-All-Languages" DEPENDS ${ALL_VARIANT_HEXES})
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
add_custom_command(TARGET "${variant_name}-All-Languages"
POST_BUILD
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory "release"
COMMAND ${CMAKE_COMMAND} -E tar "cfv" "release/${variant_name}_${FN_VERSION_SUFFIX}.zip" --format=zip ${variant_name}_${FN_VERSION_SUFFIX}_en*.hex
BYPRODUCTS "${CMAKE_BINARY_DIR}/release/${variant_name}_${FN_VERSION_SUFFIX}.zip"
)
endif()
add_dependencies(ALL_MULTILANG "${variant_name}-All-Languages")
endif()
endfunction()
if(CMAKE_CROSSCOMPILING)
# Main target for language checks
add_custom_target(check_lang)
foreach(LANG IN LISTS SELECTED_LANGUAGES)
add_custom_target(check_lang_${LANG})
add_dependencies(check_lang check_lang_${LANG})
endforeach()
# build a list of all supported variants
file(
GLOB ALL_VARIANTS
RELATIVE ${PROJECT_SOURCE_DIR}/Firmware/variants
${PROJECT_SOURCE_DIR}/Firmware/variants/*.h
)
list(TRANSFORM ALL_VARIANTS REPLACE "\.h$" "")
set(FW_VARIANTS
${ALL_VARIANTS}
CACHE STRING "Firmware variants to be built"
)
foreach(THIS_VAR IN LISTS FW_VARIANTS)
if(NOT ${THIS_VAR} IN_LIST ALL_VARIANTS)
message(FATAL_ERROR "Variant ${THIS_VAR} does not exist")
endif()
message("Variant added: ${THIS_VAR}")
# Generate a file in a subfolder so that we can organize things a little more neatly in VS code
set(DIR_NAME ${THIS_VAR})
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME})
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME}/CMakeLists.txt
"project(${DIR_NAME} VERSION ${PROJECT_VERSION})\nfw_add_variant(${THIS_VAR})"
)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/build_gen/${DIR_NAME})
endforeach(THIS_VAR IN LISTS FW_VARIANTS)
endif()
SET(REVO_FW_ZIP_NAME "E3D_REVO_FW_MK3_MK3S_MK3S+_${FN_VERSION_SUFFIX}.zip")
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
add_custom_command(TARGET ALL_MULTILANG
POST_BUILD
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/release
BYPRODUCTS ${CMAKE_BINARY_DIR}/release/${REVO_FW_ZIP_NAME}
COMMAND ${CMAKE_COMMAND} -E tar "cfv" "${REVO_FW_ZIP_NAME}" --format=zip *E3DREVO*.hex
COMMAND ${CMAKE_COMMAND} -E rm *E3DREVO*.hex
)
endif()
#
# Tests
#
if(NOT CMAKE_CROSSCOMPILING)
enable_testing()
add_subdirectory(tests)
endif()
cmake_minimum_required(VERSION 3.1)
set (CMAKE_CXX_STANDARD 11)
project(cmake_test)
# Prepare "Catch" library for other executables
set(CATCH_INCLUDE_DIR Catch2)
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
# Make test executable
set(TEST_SOURCES
Tests/tests.cpp
Tests/Example_test.cpp
Tests/Timer_test.cpp
Tests/AutoDeplete_test.cpp
Tests/PrusaStatistics_test.cpp
Firmware/Timer.cpp
Firmware/AutoDeplete.cpp
)
add_executable(tests ${TEST_SOURCES})
target_include_directories(tests PRIVATE Tests)
target_link_libraries(tests Catch)

13287
Catch2/catch.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
# Community made
Community made features aren't fully supported by Prusa and the owners are responsible to maintain them.
In case the feature isn't maintained OR causes issues Prusa will deactivate these.
## Prusa-Firmware build
- `PF-build.sh`
- Maintainers: **@3d-gussner**
- Co-maintainers:
- Contributors: **@mkbel**, **@ropaha**, **@deliopoulos**, **@DRracer**, **wavexx**, **@leptun**, **@andrewluebke**, **@kuhnmarek**
- [X] **Active** since February 2019
- [X] **Maintained** since January 2019
### How-to use PF-build.sh
Start `./PF-build.sh` and follow the instructions
Help `./PF-build.sh -h`
# MK404 Simulator
## MK404-build.sh
**MK404 is a community 3d printer simulator created by @vintagepc**
Please checkout and support his github repository [MK404](https://github.com/vintagepc/MK404) and the [MK404 Wiki](https://github.com/vintagepc/MK404/wiki)
At this moment the `MK404-build.sh` script is only supported on Linux
- `MK404-build.sh`
- Maintainers: **@3d-gussner**
- Co-maintainers:
- Contributors:
- [X] **Active** since August 2021
- [X] **Maintained** since August 2021
### How-to use MK404-build.sh
After compiling with `PF-build.sh` you get the option to start the `MK404` simulator with the fresh compiled firmware. (Linux only at this moment)
Help `./MK404-build.sh -h`
# Translations
- see [/lang/Community_made_translations.md](https://github.com/prusa3d/Prusa-Firmware/blob/MK3/lang/Community_made_translations.md)
# Arc interpolation features
**Arc interpolation features by @FormerLurker**
Please read more about it [here](https://github.com/prusa3d/Prusa-Firmware/pull/2657) and [here](https://github.com/FormerLurker/ArcWelderPlugin)
- Maintainers: **@FormerLurker**
- Co-maintainers:
- Contributors:
- [X] **Active** since January 2023
- [X] **Maintained** since May 2020
# MeatPack
**MeatPack by @scottmudge**
Please read more about it [here](https://github.com/prusa3d/Prusa-Firmware/pull/2955), [here](https://github.com/prusa3d/Prusa-Firmware/pull/4067) and [here](https://github.com/scottmudge/OctoPrint-MeatPack/)
- Maintainers: **@scottmudge**
- Co-maintainers:
- Contributors:
- [X] **Active** since April 2023
- [X] **Maintained** since January 2021
# E3D Revo
**The E3D REVO support is a community effort thanks to these Contributors, E3D and others.**
- Maintainers: **E3D**
- Co-maintainers:
- Contributors: @alexiri @kromeninja @ulab @JWvP @snafu1282 @matthiazzz @sdh2 @jdrozdz @peschkaj @MarcelTh @zuidwijk @davejhilton @WhiterRice @NightSkySK @D-an-W
- [X] **Active** since June 2023
- [X] **Maintained** since April 2023

79
Firmware/AutoDeplete.cpp Normal file
View File

@ -0,0 +1,79 @@
//! @file
//! @author: Marek Bel
//! @date Jan 3, 2019
#include "AutoDeplete.h"
#include "assert.h"
//! @brief bit field marking depleted filaments
//!
//! binary 1 marks filament as depleted
//! Zero initialized value means, that no filament is depleted.
static uint8_t depleted;
static const uint8_t filamentCount = 5;
//! @return binary 1 for all filaments
//! @par fCount number of filaments
static constexpr uint8_t allDepleted(uint8_t fCount)
{
return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 1));
}
//! @brief Is filament available for printing?
//! @par filament Filament number to be checked
//! @retval true Filament is available for printing.
//! @retval false Filament is not available for printing.
static bool loaded(uint8_t filament)
{
if (depleted & (1 << filament)) return false;
return true;
}
//! @brief Mark filament as not available for printing.
//! @par filament filament to be marked
void ad_markDepleted(uint8_t filament)
{
assert(filament < filamentCount);
if (filament < filamentCount)
{
depleted |= 1 << filament;
}
}
//! @brief Mark filament as available for printing.
//! @par filament filament to be marked
void ad_markLoaded(uint8_t filament)
{
assert(filament < filamentCount);
if (filament < filamentCount)
{
depleted &= ~(1 << filament);
}
}
//! @brief Get alternative filament, which is not depleted
//! @par filament filament
//! @return Filament, if it is depleted, returns next available,
//! if all filaments are depleted, returns filament function parameter.
uint8_t ad_getAlternative(uint8_t filament)
{
assert(filament < filamentCount);
for (uint8_t i = 0; i<filamentCount; ++i)
{
uint8_t nextFilament = (filament + i) % filamentCount;
if (loaded(nextFilament)) return nextFilament;
}
return filament;
}
//! @brief Are all filaments depleted?
//! @retval true All filaments are depleted.
//! @retval false All filaments are not depleted.
bool ad_allDepleted()
{
if (allDepleted(filamentCount) == depleted)
{
return true;
}
return false;
}

17
Firmware/AutoDeplete.h Normal file
View File

@ -0,0 +1,17 @@
//! @file
//! @author: Marek Bel
//! @brief Filament auto deplete engine for multi-material prints with MMUv2 (Now marketed as SpoolJoin)
//!
//! Interface for marking MMUv2 filaments as depleted and getting alternative filament for printing.
#ifndef AUTODEPLETE_H
#define AUTODEPLETE_H
#include <stdint.h>
void ad_markDepleted(uint8_t filament);
void ad_markLoaded(uint8_t filament);
uint8_t ad_getAlternative(uint8_t filament);
bool ad_allDepleted();
#endif /* AUTODEPLETE_H */

View File

@ -15,7 +15,7 @@
void SendColors(byte red, byte grn, byte blu)
{
Wire.begin();
Wire.begin();
Wire.beginTransmission(0x09);
Wire.write('o'); //to disable ongoing script, only needs to be used once
Wire.write('n');

View File

@ -1,9 +1,10 @@
#include "Configuration.h"
#include "Configuration_var.h"
#include "Configuration_prusa.h"
const uint16_t _nPrinterType PROGMEM=PRINTER_TYPE;
const char _sPrinterName[] PROGMEM=PRINTER_NAME;
const uint16_t _nPrinterMmuType PROGMEM=PRINTER_MMU_TYPE;
const char _sPrinterMmuName[] PROGMEM=PRINTER_MMU_NAME;
static_assert(TEMP_HYSTERESIS > 0, "TEMP_HYSTERESIS must be greater than 0");
uint16_t nPrinterType;
PGM_P sPrinterName;

View File

@ -1,61 +1,69 @@
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
#include <stdint.h>
#include "boards.h"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define _CONCAT(x,y) x##y
#define CONCAT(x,y) _CONCAT(x,y)
//-//
#include <avr/pgmspace.h>
extern const uint16_t _nPrinterType;
extern const char _sPrinterName[] PROGMEM;
extern const uint16_t _nPrinterMmuType;
extern const char _sPrinterMmuName[] PROGMEM;
extern uint16_t nPrinterType;
extern PGM_P sPrinterName;
// Firmware version.
// NOTE: These are ONLY used if you are not building via cmake and/or not in a git repository.
// Otherwise the repository information takes precedence.
#ifndef CMAKE_CONTROL
// Firmware version
#define FW_MAJOR 3
#define FW_MINOR 14
#define FW_REVISION 1
#define FW_COMMITNR 8225
#define FW_FLAVOR RC //uncomment if DEV, ALPHA, BETA or RC
#define FW_FLAVERSION 1 //uncomment if FW_FLAVOR is defined and versioning is needed. Limited to max 8.
#endif
#define FW_MINOR 10
#define FW_REVISION 2
#define FW_FLAVOR BETA //uncomment if DEBUG, DEVEL, APLHA, BETA or RC
#define FW_FLAVERSION 1 //uncomment if FW_FLAVOR is defined and versioning is needed.
#ifndef FW_FLAVOR
#define FW_TWEAK (FIRMWARE_REVISION_RELEASED)
#define FW_VERSION STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION)
#define FW_VERSION_FULL STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION) "-" STR(FW_COMMITNR)
#else
// Construct the TWEAK value as it is expected from the enum.
#define FW_TWEAK (CONCAT(FIRMWARE_REVISION_,FW_FLAVOR) + FW_FLAVERSION)
#define FW_VERSION STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION) "-" STR(FW_FLAVOR) "" STR(FW_FLAVERSION)
#define FW_VERSION_FULL STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION) "-" STR(FW_FLAVOR) "" STR(FW_FLAVERSION) "+" STR(FW_COMMITNR)
#endif
// The full version string and repository source are set via cmake
#ifndef CMAKE_CONTROL
#define FW_COMMIT_HASH_LENGTH 1
#define FW_COMMIT_HASH "0"
#define FW_COMMIT_NR 4708
// FW_VERSION_UNKNOWN means this is an unofficial build.
// The firmware should only be checked into github with this symbol.
#define FW_DEV_VERSION FW_VERSION_UNKNOWN
#define FW_REPOSITORY "Unknown"
#endif
#define FW_VERSION_FULL FW_VERSION "-" STR(FW_COMMIT_NR)
// G-code language level
#define GCODE_LEVEL 1
#ifndef SOURCE_DATE_EPOCH
#define SOURCE_DATE_EPOCH __DATE__
#endif
#ifndef SOURCE_TIME_EPOCH
#define SOURCE_TIME_EPOCH __TIME__
// Debug version has debugging enabled (the symbol DEBUG_BUILD is set).
// The debug build may be a bit slower than the non-debug build, therefore the debug build should
// not be shipped to a customer.
#define FW_VERSION_DEBUG 6
// This is a development build. A development build is either built from an unofficial git repository,
// or from an unofficial branch, or it does not have a label set. Only the build server should set this build type.
#define FW_VERSION_DEVEL 5
// This is an alpha release. Only the build server should set this build type.
#define FW_VERSION_ALPHA 4
// This is a beta release. Only the build server should set this build type.
#define FW_VERSION_BETA 3
// This is a release candidate build. Only the build server should set this build type.
#define FW_VERSION_RC 2
// This is a final release. Only the build server should set this build type.
#define FW_VERSION_GOLD 1
// This is an unofficial build. The firmware should only be checked into github with this symbol,
// the build server shall never produce builds with this build type.
#define FW_VERSION_UNKNOWN 0
#if FW_DEV_VERSION == FW_VERSION_DEBUG
#define DEBUG_BUILD
#else
#undef DEBUG_BUILD
#endif
#include "Configuration_var.h"
#include "Configuration_prusa.h"
#define FW_PRUSA3D_MAGIC "PRUSA3DFW"
#define FW_PRUSA3D_MAGIC_LEN 10
@ -70,8 +78,10 @@ extern const char _sPrinterMmuName[] PROGMEM;
// startup. Implementation of an idea by Prof Braino to inform user that any changes made to this
// build by the user have been successfully uploaded into firmware.
#define STRING_VERSION_CONFIG_H SOURCE_DATE_EPOCH " " SOURCE_TIME_EPOCH // build date and time
#define STRING_CONFIG_H_AUTHOR FW_REPOSITORY // Who made the changes.
//#define STRING_VERSION "1.0.2"
#define STRING_VERSION_CONFIG_H __DATE__ " " __TIME__ // build date and time
#define STRING_CONFIG_H_AUTHOR "(none, default config)" // Who made the changes.
// SERIAL_PORT selects which serial port should be used for communication with the host.
// This allows the connection of wireless adapters (for instance) to non-default port pins.
@ -81,9 +91,6 @@ extern const char _sPrinterMmuName[] PROGMEM;
// This determines the communication speed of the printer
#define BAUDRATE 115200
// Enable g-code compression (see https://github.com/scottmudge/OctoPrint-MeatPack)
#define ENABLE_MEATPACK
// This enables the serial port associated to the Bluetooth interface
//#define BTENABLED // Enable BT interface on AT90USB devices
@ -122,6 +129,13 @@ extern const char _sPrinterMmuName[] PROGMEM;
#define TEMP_HYSTERESIS 5 // (degC) range of +/- temperatures considered "close" to the target one
#define TEMP_WINDOW 1 // (degC) Window around target to start the residency timer x degC early.
// If your bed has low resistance e.g. .6 ohm and throws the fuse you can duty cycle it to reduce the
// average current. The value should be an integer and the heat bed will be turned on for 1 interval of
// HEATER_BED_DUTY_CYCLE_DIVIDER intervals.
//#define HEATER_BED_DUTY_CYCLE_DIVIDER 4
// If you want the M105 heater power reported in watts, define the BED_WATTS, and (shared for all extruders) EXTRUDER_WATTS
//#define EXTRUDER_WATTS (12.0*12.0/6.7) // P=I^2/R
//#define BED_WATTS (12.0*12.0/1.1) // P=I^2/R
@ -141,7 +155,7 @@ extern const char _sPrinterMmuName[] PROGMEM;
// If you are using a pre-configured hotend then you can use one of the value sets by uncommenting it
// Ultimaker
// MakerGear
// #define DEFAULT_Kp 7.0
@ -177,15 +191,15 @@ The issue: If a thermistor come off, it will read a lower temperature than actua
The system will turn the heater on forever, burning up the filament and anything
else around.
After the temperature reaches the target for the first time, this feature will
start measuring for how long the current temperature stays below the target
After the temperature reaches the target for the first time, this feature will
start measuring for how long the current temperature stays below the target
minus _HYSTERESIS (set_temperature - THERMAL_RUNAWAY_PROTECTION_HYSTERESIS).
If it stays longer than _PERIOD, it means the thermistor temperature
cannot catch up with the target, so something *may be* wrong. Then, to be on the
safe side, the system will he halt.
Bear in mind the count down will just start AFTER the first time the
Bear in mind the count down will just start AFTER the first time the
thermistor temperature is over the target, so you will have no problem if
your extruder heater takes 2 minutes to hit the target on heating.
@ -259,6 +273,7 @@ your extruder heater takes 2 minutes to hit the target on heating.
#define DISABLE_Y 0
#define DISABLE_Z 0
#define DISABLE_E 0// For all extruders
#define DISABLE_INACTIVE_EXTRUDER 1 //disable only inactive extruders and keep active extruder enabled
// ENDSTOP SETTINGS:
@ -277,13 +292,131 @@ your extruder heater takes 2 minutes to hit the target on heating.
#define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS)
#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS)
#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS)
#define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS)
#define Z_HEIGHT_HIDE_LIVE_ADJUST_MENU 2.0f
#define HOME_Z_SEARCH_THRESHOLD 0.15f // Threshold of the Z height in calibration
//============================= Bed Auto Leveling ===========================
//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line)
#define Z_PROBE_REPEATABILITY_TEST // If not commented out, Z-Probe Repeatability test will be included if Auto Bed Leveling is Enabled.
#ifdef ENABLE_AUTO_BED_LEVELING
// There are 2 different ways to pick the X and Y locations to probe:
// - "grid" mode
// Probe every point in a rectangular grid
// You must specify the rectangle, and the density of sample points
// This mode is preferred because there are more measurements.
// It used to be called ACCURATE_BED_LEVELING but "grid" is more descriptive
// - "3-point" mode
// Probe 3 arbitrary points on the bed (that aren't colinear)
// You must specify the X & Y coordinates of all 3 points
#define AUTO_BED_LEVELING_GRID
// with AUTO_BED_LEVELING_GRID, the bed is sampled in a
// AUTO_BED_LEVELING_GRID_POINTSxAUTO_BED_LEVELING_GRID_POINTS grid
// and least squares solution is calculated
// Note: this feature occupies 10'206 byte
#ifdef AUTO_BED_LEVELING_GRID
// set the rectangle in which to probe
#define LEFT_PROBE_BED_POSITION 15
#define RIGHT_PROBE_BED_POSITION 170
#define BACK_PROBE_BED_POSITION 180
#define FRONT_PROBE_BED_POSITION 20
// set the number of grid points per dimension
// I wouldn't see a reason to go above 3 (=9 probing points on the bed)
#define AUTO_BED_LEVELING_GRID_POINTS 2
#else // not AUTO_BED_LEVELING_GRID
// with no grid, just probe 3 arbitrary points. A simple cross-product
// is used to esimate the plane of the print bed
#define ABL_PROBE_PT_1_X 15
#define ABL_PROBE_PT_1_Y 180
#define ABL_PROBE_PT_2_X 15
#define ABL_PROBE_PT_2_Y 20
#define ABL_PROBE_PT_3_X 170
#define ABL_PROBE_PT_3_Y 20
#endif // AUTO_BED_LEVELING_GRID
// these are the offsets to the probe relative to the extruder tip (Hotend - Probe)
// X and Y offsets must be integers
#define X_PROBE_OFFSET_FROM_EXTRUDER -25
#define Y_PROBE_OFFSET_FROM_EXTRUDER -29
#define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35
#define Z_RAISE_BEFORE_HOMING 5 // (in mm) Raise Z before homing (G28) for Probe Clearance.
// Be sure you have this distance over your Z_MAX_POS in case
#define XY_TRAVEL_SPEED 8000 // X and Y axis travel speed between probes, in mm/min
#define Z_RAISE_BEFORE_PROBING 15 //How much the extruder will be raised before traveling to the first probing point.
#define Z_RAISE_BETWEEN_PROBINGS 5 //How much the extruder will be raised when traveling from between next probing points
//#define Z_PROBE_SLED // turn on if you have a z-probe mounted on a sled like those designed by Charles Bell
//#define SLED_DOCKING_OFFSET 5 // the extra distance the X axis must travel to pickup the sled. 0 should be fine but you can push it further if you'd like.
//If defined, the Probe servo will be turned on only during movement and then turned off to avoid jerk
//The value is the delay to turn the servo off after powered on - depends on the servo speed; 300ms is good value, but you can try lower it.
// You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile.
// #define PROBE_SERVO_DEACTIVATION_DELAY 300
//If you have enabled the Bed Auto Leveling and are using the same Z Probe for Z Homing,
//it is highly recommended you let this Z_SAFE_HOMING enabled!
//#define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area.
// When defined, it will:
// - Allow Z homing only after X and Y homing AND stepper drivers still enabled
// - If stepper drivers timeout, it will need X and Y homing again before Z homing
// - Position the probe in a defined XY point before Z Homing when homing all axis (G28)
// - Block Z homing only when the probe is outside bed area.
#ifdef Z_SAFE_HOMING
#define Z_SAFE_HOMING_X_POINT (X_MAX_LENGTH/2) // X point for Z homing when homing all axis (G28)
#define Z_SAFE_HOMING_Y_POINT (Y_MAX_LENGTH/2) // Y point for Z homing when homing all axis (G28)
#endif
#ifdef AUTO_BED_LEVELING_GRID // Check if Probe_Offset * Grid Points is greater than Probing Range
#if X_PROBE_OFFSET_FROM_EXTRUDER < 0
#if (-(X_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION))
#error "The X axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS"
#endif
#else
#if ((X_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION))
#error "The X axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS"
#endif
#endif
#if Y_PROBE_OFFSET_FROM_EXTRUDER < 0
#if (-(Y_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION))
#error "The Y axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS"
#endif
#else
#if ((Y_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION))
#error "The Y axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS"
#endif
#endif
#endif
#endif // ENABLE_AUTO_BED_LEVELING
// The position of the homing switches
//#define MANUAL_HOME_POSITIONS // If defined, MANUAL_*_HOME_POS below will be used
//#define BED_CENTER_AT_0_0 // If defined, the center of the bed is at (X=0, Y=0)
@ -291,6 +424,13 @@ your extruder heater takes 2 minutes to hit the target on heating.
//Manual homing switch locations:
// For deltabots this means top and center of the Cartesian print volume.
// Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing).
// The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder).
// For the other hotends it is their distance from the extruder 0 hotend.
// #define EXTRUDER_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis
// #define EXTRUDER_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis
// The speed change that does not require acceleration (i.e. the software might assume it can be done instantaneously)
#define DEFAULT_XJERK 10 // (mm/sec)
#define DEFAULT_YJERK 10 // (mm/sec)
@ -301,6 +441,26 @@ your extruder heater takes 2 minutes to hit the target on heating.
//=============================Additional Features===========================
//===========================================================================
// Custom M code points
#define CUSTOM_M_CODES
#ifdef CUSTOM_M_CODES
#define CUSTOM_M_CODE_SET_Z_PROBE_OFFSET 851
#define Z_PROBE_OFFSET_RANGE_MIN -15
#define Z_PROBE_OFFSET_RANGE_MAX -5
#endif
// EEPROM
// The microcontroller can store settings in the EEPROM, e.g. max velocity...
// M500 - stores parameters in EEPROM
// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
//define this to enable EEPROM support
//#define EEPROM_SETTINGS
//to disable EEPROM Serial responses and decrease program space by ~1700 byte: comment this out:
// please keep turned on if you can.
//#define EEPROM_CHITCHAT
// Host Keepalive
//
// When enabled Marlin will send a busy status message to the host
@ -324,15 +484,16 @@ your extruder heater takes 2 minutes to hit the target on heating.
#define SDSUPPORT
#define LCD_WIDTH 20
#define LCD_HEIGHT 4
#define LCD_BACKLIGHT_LEVEL_HIGH 130
#define LCD_BACKLIGHT_LEVEL_LOW 50
#define LCD_BACKLIGHT_FORCE_ON 30
#define LCD_BACKLIGHT_TIMEOUT 15
// Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino
//#define FAST_PWM_FAN
// Temperature status LEDs that display the hotend and bet temperature.
// If all hotends and bed temperature and temperature setpoint are < 54C then the BLUE led is on.
// Otherwise the RED led is on. There is 1C hysteresis.
//#define TEMP_STAT_LEDS
// Use software PWM to drive the fan, as for the heaters. This uses a very low frequency
// which is not ass annoying as with the hardware PWM. On the other hand, if this frequency
// is too low, you should also increment SOFT_PWM_SCALE.
@ -358,16 +519,56 @@ your extruder heater takes 2 minutes to hit the target on heating.
//define BlinkM/CyzRgb Support
//#define BLINKM
/*********************************************************************\
* R/C SERVO support
* Sponsored by TrinityLabs, Reworked by codexmas
**********************************************************************/
// Number of servos
//
// If you select a configuration below, this will receive a default value and does not need to be set manually
// set it manually if you have more servos than extruders and wish to manually control some
// leaving it undefined or defining as 0 will disable the servo subsystem
// If unsure, leave commented / disabled
//
//#define NUM_SERVOS 3 // Servo index starts with 0 for M280 command
#define DEFAULT_NOMINAL_FILAMENT_DIA 1.75 //Enter the diameter (in mm) of the filament generally used (3.0 mm or 1.75 mm). Used by the volumetric extrusion.
// Calibration status of the machine, to be stored into the EEPROM,
// (unsigned char*)EEPROM_CALIBRATION_STATUS
enum CalibrationStatus
{
// Freshly assembled, needs to peform a self-test and the XYZ calibration.
CALIBRATION_STATUS_ASSEMBLED = 255,
// For the wizard: self test has been performed, now the XYZ calibration is needed.
CALIBRATION_STATUS_XYZ_CALIBRATION = 250,
// For the wizard: factory assembled, needs to run Z calibration.
CALIBRATION_STATUS_Z_CALIBRATION = 240,
// The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode.
CALIBRATION_STATUS_LIVE_ADJUST = 230,
// Calibrated, ready to print.
CALIBRATION_STATUS_CALIBRATED = 1,
// Legacy: resetted by issuing a G86 G-code.
// This value can only be expected after an upgrade from the initial MK2 firmware releases.
// Currently the G86 sets the calibration status to
CALIBRATION_STATUS_UNKNOWN = 0,
};
// Try to maintain a minimum distance from the bed even when Z is
// unknown when doing the following operations
#define MIN_Z_FOR_LOAD 35 // lcd filament loading or autoload (values for load and unload have been unified to prevent movement between unload & load operations!)
#define MIN_Z_FOR_UNLOAD 35 // lcd filament unloading
#define MIN_Z_FOR_LOAD 50 // lcd filament loading or autoload
#define MIN_Z_FOR_UNLOAD 50 // lcd filament unloading
#define MIN_Z_FOR_SWAP 27 // filament change (including M600)
#define MIN_Z_FOR_PREHEAT 10 // lcd preheat
#include "Configuration_adv.h"
#include "thermistortables.h"
#endif //__CONFIGURATION_H

View File

@ -3,41 +3,111 @@
#include "Marlin.h"
#include "planner.h"
#include "temperature.h"
#include "ultralcd.h"
#include "ConfigurationStore.h"
#include "Configuration_var.h"
#include "Configuration_prusa.h"
#ifdef MESH_BED_LEVELING
#include "mesh_bed_leveling.h"
#endif
#ifdef TMC2130
#include "tmc2130.h"
#endif
M500_conf cs;
//! @brief Write data to EEPROM
//! @param pos destination in EEPROM, 0 is start
//! @param value value to be written
//! @param size size of type pointed by value
//! @param name name of variable written, used only for debug input if DEBUG_EEPROM_WRITE defined
//! @retval true success
//! @retval false failed
#ifdef DEBUG_EEPROM_WRITE
static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const char* name)
#else //DEBUG_EEPROM_WRITE
static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const char*)
#endif //DEBUG_EEPROM_WRITE
{
#ifdef DEBUG_EEPROM_WRITE
printf_P(PSTR("EEPROM_WRITE_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name);
#endif //DEBUG_EEPROM_WRITE
while (size--)
{
eeprom_update_byte(pos, *value);
if (eeprom_read_byte(pos) != *value) {
SERIAL_ECHOLNPGM("EEPROM Error");
return false;
}
pos++;
value++;
}
return true;
}
#ifdef DEBUG_EEPROM_READ
static void EEPROM_readData(uint8_t* pos, uint8_t* value, uint8_t size, const char* name)
#else //DEBUG_EEPROM_READ
static void EEPROM_readData(uint8_t* pos, uint8_t* value, uint8_t size, const char*)
#endif //DEBUG_EEPROM_READ
{
#ifdef DEBUG_EEPROM_READ
printf_P(PSTR("EEPROM_READ_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name);
#endif //DEBUG_EEPROM_READ
while(size--)
{
*value = eeprom_read_byte(pos);
pos++;
value++;
}
}
#define EEPROM_VERSION "V2"
#ifdef EEPROM_SETTINGS
void Config_StoreSettings()
{
strcpy(cs.version,"000"); //!< invalidate data first @TODO use erase to save one erase cycle
if (EEPROM_writeData(reinterpret_cast<uint8_t*>(EEPROM_M500_base),reinterpret_cast<uint8_t*>(&cs),sizeof(cs),0), "cs, invalid version")
{
strcpy(cs.version,EEPROM_VERSION); //!< validate data if write succeed
EEPROM_writeData(reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), reinterpret_cast<uint8_t*>(cs.version), sizeof(cs.version), "cs.version valid");
}
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Settings Stored");
}
#endif //EEPROM_SETTINGS
#ifndef DISABLE_M503
void Config_PrintSettings(uint8_t level)
{ // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown
#ifdef TMC2130
printf_P(PSTR(
"%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n"
printf_P(PSTR(
"%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n"
"%SUStep resolution: \n%S M350 X%d Y%d Z%d E%d\n"
"%SMaximum feedrates - normal (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n"
"%SMaximum feedrates - stealth (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n"
"%SMaximum acceleration - normal (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n"
"%SMaximum acceleration - stealth (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n"
"%SAcceleration: P=print, R=retract, T=travel\n%S M204 P%.2f R%.2f T%.2f\n"
"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (us), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%lu X%.2f Y%.2f Z%.2f E%.2f\n"
"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
"%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n"
),
echomagic, echomagic, cs.axis_steps_per_mm[X_AXIS], cs.axis_steps_per_mm[Y_AXIS], cs.axis_steps_per_mm[Z_AXIS], cs.axis_steps_per_mm[E_AXIS],
echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
echomagic, echomagic, cs.axis_ustep_resolution[X_AXIS], cs.axis_ustep_resolution[Y_AXIS], cs.axis_ustep_resolution[Z_AXIS], cs.axis_ustep_resolution[E_AXIS],
echomagic, echomagic, cs.max_feedrate_normal[X_AXIS], cs.max_feedrate_normal[Y_AXIS], cs.max_feedrate_normal[Z_AXIS], cs.max_feedrate_normal[E_AXIS],
echomagic, echomagic, cs.max_feedrate_silent[X_AXIS], cs.max_feedrate_silent[Y_AXIS], cs.max_feedrate_silent[Z_AXIS], cs.max_feedrate_silent[E_AXIS],
echomagic, echomagic, cs.max_acceleration_mm_per_s2_normal[X_AXIS], cs.max_acceleration_mm_per_s2_normal[Y_AXIS], cs.max_acceleration_mm_per_s2_normal[Z_AXIS], cs.max_acceleration_mm_per_s2_normal[E_AXIS],
echomagic, echomagic, cs.max_acceleration_mm_per_s2_silent[X_AXIS], cs.max_acceleration_mm_per_s2_silent[Y_AXIS], cs.max_acceleration_mm_per_s2_silent[Z_AXIS], cs.max_acceleration_mm_per_s2_silent[E_AXIS],
echomagic, echomagic, cs.max_acceleration_units_per_sq_second_normal[X_AXIS], cs.max_acceleration_units_per_sq_second_normal[Y_AXIS], cs.max_acceleration_units_per_sq_second_normal[Z_AXIS], cs.max_acceleration_units_per_sq_second_normal[E_AXIS],
echomagic, echomagic, cs.max_acceleration_units_per_sq_second_silent[X_AXIS], cs.max_acceleration_units_per_sq_second_silent[Y_AXIS], cs.max_acceleration_units_per_sq_second_silent[Z_AXIS], cs.max_acceleration_units_per_sq_second_silent[E_AXIS],
echomagic, echomagic, cs.acceleration, cs.retract_acceleration, cs.travel_acceleration,
echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.min_segment_time_us, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
#else //TMC2130
printf_P(PSTR(
@ -45,70 +115,60 @@ void Config_PrintSettings(uint8_t level)
"%SMaximum feedrates (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n"
"%SMaximum acceleration (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n"
"%SAcceleration: P=print, R=retract, T=travel\n%S M204 P%.2f R%.2f T%.2f\n"
"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (us), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%lu X%.2f Y%.2f Z%.2f E%.2f\n"
"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
"%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n"
),
echomagic, echomagic, cs.axis_steps_per_mm[X_AXIS], cs.axis_steps_per_mm[Y_AXIS], cs.axis_steps_per_mm[Z_AXIS], cs.axis_steps_per_mm[E_AXIS],
echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
echomagic, echomagic, max_feedrate[X_AXIS], max_feedrate[Y_AXIS], max_feedrate[Z_AXIS], max_feedrate[E_AXIS],
echomagic, echomagic, max_acceleration_mm_per_s2[X_AXIS], max_acceleration_mm_per_s2[Y_AXIS], max_acceleration_mm_per_s2[Z_AXIS], max_acceleration_mm_per_s2[E_AXIS],
echomagic, echomagic, max_acceleration_units_per_sq_second[X_AXIS], max_acceleration_units_per_sq_second[Y_AXIS], max_acceleration_units_per_sq_second[Z_AXIS], max_acceleration_units_per_sq_second[E_AXIS],
echomagic, echomagic, cs.acceleration, cs.retract_acceleration, cs.travel_acceleration,
echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.min_segment_time_us, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
#endif //TMC2130
);
);
#ifdef PIDTEMP
printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"),
echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd));
printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"),
echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd));
#endif
#ifdef PIDTEMPBED
printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"),
echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd));
printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"),
echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd));
#endif
#ifdef FWRETRACT
printf_P(PSTR(
"%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n"
"%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n"
"%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n"
),
echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift,
echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60,
echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0)
);
printf_P(PSTR(
"%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n"
"%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n"
"%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n"
),
echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift,
echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60,
echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0)
);
#if EXTRUDERS > 1
printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"),
echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap);
printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"),
echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap);
#endif
if (cs.volumetric_enabled) {
printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"),
echomagic, echomagic, cs.filament_size[0]);
if (cs.volumetric_enabled) {
printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"),
echomagic, echomagic, cs.filament_size[0]);
#if EXTRUDERS > 1
printf_P(PSTR("%S M200 T1 D%.2f\n"),
echomagic, echomagic, cs.filament_size[1]);
printf_P(PSTR("%S M200 T1 D%.2f\n"),
echomagic, echomagic, cs.filament_size[1]);
#if EXTRUDERS > 2
printf_P(PSTR("%S M200 T1 D%.2f\n"),
echomagic, echomagic, cs.filament_size[2]);
printf_P(PSTR("%S M200 T1 D%.2f\n"),
echomagic, echomagic, cs.filament_size[2]);
#endif
#endif
} else {
printf_P(PSTR("%SFilament settings: Disabled\n"), echomagic);
}
#endif
if (level >= 10) {
if (level >= 10) {
#ifdef LIN_ADVANCE
printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"),
printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"),
echomagic, echomagic, extruder_advance_K);
#endif //LIN_ADVANCE
}
// Arc Interpolation Settings
printf_P(PSTR(
"%SArc Settings: P:Max length(mm) S:Min length (mm) N:Corrections R:Min segments F:Segments/sec.\n%S M214 P%.2f S%.2f N%d R%d F%d\n"),
echomagic, echomagic, cs.mm_per_arc_segment, cs.min_mm_per_arc_segment, cs.n_arc_correction, cs.min_arc_segments, cs.arc_segments_per_sec);
#ifdef THERMAL_MODEL
thermal_model_report_settings();
#endif
printf_P(PSTR(
"%SStatistics:\n%S M78 S%lu T%lu\n"),
echomagic, echomagic, eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED), eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME));
}
}
#endif
@ -117,10 +177,14 @@ void Config_PrintSettings(uint8_t level)
static_assert (EXTRUDERS == 1, "ConfigurationStore M500_conf not implemented for more extruders, fix filament_size array size.");
static_assert (NUM_AXIS == 4, "ConfigurationStore M500_conf not implemented for more axis."
"Fix axis_steps_per_mm max_feedrate_normal max_acceleration_mm_per_s2_normal max_jerk max_feedrate_silent"
" max_acceleration_mm_per_s2_silent array size.");
"Fix axis_steps_per_unit max_feedrate_normal max_acceleration_units_per_sq_second_normal max_jerk max_feedrate_silent"
" max_acceleration_units_per_sq_second_silent array size.");
#ifdef ENABLE_AUTO_BED_LEVELING
static_assert (false, "zprobe_zoffset was not initialized in printers in field to -(Z_PROBE_OFFSET_FROM_EXTRUDER), so it contains"
"0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf");
#endif
static_assert (sizeof(M500_conf) == 209, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, "
static_assert (sizeof(M500_conf) == 196, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, "
"or if you added members in the end of struct, ensure that historically uninitialized values will be initialized."
"If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM,"
"leave as it is to keep fast code, or reorder struct members to pack more tightly.");
@ -169,98 +233,101 @@ static const M500_conf default_conf PROGMEM =
{16,16,16,16},
#endif
DEFAULT_TRAVEL_ACCELERATION,
DEFAULT_MM_PER_ARC_SEGMENT,
DEFAULT_MIN_MM_PER_ARC_SEGMENT,
DEFAULT_N_ARC_CORRECTION,
DEFAULT_MIN_ARC_SEGMENTS,
DEFAULT_ARC_SEGMENTS_PER_SEC
};
void Config_StoreSettings()
static bool is_uninitialized(void* addr, uint8_t len)
{
strcpy_P(cs.version, default_conf.version);
eeprom_update_block_notify(reinterpret_cast<uint8_t*>(&cs), reinterpret_cast<uint8_t*>(EEPROM_M500_base), sizeof(cs));
#ifdef THERMAL_MODEL
thermal_model_save_settings();
#endif
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Settings Stored");
while(len--)
{
if(reinterpret_cast<uint8_t*>(addr)[len] != 0xff)
return false;
}
return true;
}
//! @brief Read M500 configuration
//! @retval true Succeeded. Stored settings retrieved or default settings retrieved in case EEPROM cs was empty.
//! @retval false Failed. Default settings has been retrieved, because of version mismatch
//! @retval true Succeeded. Stored settings retrieved or default settings retrieved in case EEPROM has been erased.
//! @retval false Failed. Default settings has been retrieved, because of older version or corrupted data.
bool Config_RetrieveSettings()
{
eeprom_read_block(reinterpret_cast<uint8_t*>(cs.version), reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), sizeof(cs.version));
bool previous_settings_retrieved = true;
char ver[4]=EEPROM_VERSION;
EEPROM_readData(reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), reinterpret_cast<uint8_t*>(cs.version), sizeof(cs.version), "cs.version"); //read stored version
// SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << cs.version << "]");
if (strncmp_P(cs.version, default_conf.version, sizeof(EEPROM_VERSION)) == 0) // version number match
if (strncmp(ver,cs.version,3) == 0) // version number match
{
// Initialize arc interpolation settings in eeprom if they are not already
eeprom_init_default_float(&EEPROM_M500_base->mm_per_arc_segment, pgm_read_float(&default_conf.mm_per_arc_segment));
eeprom_init_default_float(&EEPROM_M500_base->min_mm_per_arc_segment, pgm_read_float(&default_conf.min_mm_per_arc_segment));
eeprom_init_default_byte(&EEPROM_M500_base->n_arc_correction, pgm_read_byte(&default_conf.n_arc_correction));
eeprom_init_default_word(&EEPROM_M500_base->min_arc_segments, pgm_read_word(&default_conf.min_arc_segments));
eeprom_init_default_word(&EEPROM_M500_base->arc_segments_per_sec, pgm_read_word(&default_conf.arc_segments_per_sec));
// Initialize the travel_acceleration in eeprom if not already
eeprom_init_default_float(&EEPROM_M500_base->travel_acceleration, pgm_read_float(&default_conf.travel_acceleration));
EEPROM_readData(reinterpret_cast<uint8_t*>(EEPROM_M500_base), reinterpret_cast<uint8_t*>(&cs), sizeof(cs), "cs");
// Initialize the max_feedrate_silent and max_acceleration_mm_per_s2_silent in eeprom if not already
eeprom_init_default_block(&EEPROM_M500_base->max_feedrate_silent, sizeof(EEPROM_M500_base->max_feedrate_silent), default_conf.max_feedrate_silent);
eeprom_init_default_block(&EEPROM_M500_base->max_acceleration_mm_per_s2_silent, sizeof(EEPROM_M500_base->max_acceleration_mm_per_s2_silent), default_conf.max_acceleration_mm_per_s2_silent);
#ifdef TMC2130
eeprom_init_default_block(&EEPROM_M500_base->axis_ustep_resolution, sizeof(EEPROM_M500_base->axis_ustep_resolution), default_conf.axis_ustep_resolution);
#endif // TMC2130
// load the CS to RAM
eeprom_read_block(reinterpret_cast<uint8_t*>(&cs), reinterpret_cast<uint8_t*>(EEPROM_M500_base), sizeof(cs));
if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK;
if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK;
calculate_extruder_multipliers();
#ifdef TMC2130
for (uint8_t j = X_AXIS; j <= Y_AXIS; j++)
{
if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY)
cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY;
if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY)
cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY;
if (cs.max_acceleration_mm_per_s2_normal[j] > NORMAL_MAX_ACCEL_XY)
cs.max_acceleration_mm_per_s2_normal[j] = NORMAL_MAX_ACCEL_XY;
if (cs.max_acceleration_mm_per_s2_silent[j] > SILENT_MAX_ACCEL_XY)
cs.max_acceleration_mm_per_s2_silent[j] = SILENT_MAX_ACCEL_XY;
}
//if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values:
for (uint8_t i = 0; i < (sizeof(cs.max_feedrate_silent)/sizeof(cs.max_feedrate_silent[0])); ++i)
{
const uint32_t erased = 0xffffffff;
if (is_uninitialized(&(cs.max_feedrate_silent[i]), sizeof(float))) {
memcpy_P(&cs.max_feedrate_silent[i],&default_conf.max_feedrate_silent[i], sizeof(cs.max_feedrate_silent[i]));
}
if (erased == cs.max_acceleration_units_per_sq_second_silent[i]) {
memcpy_P(&cs.max_acceleration_units_per_sq_second_silent[i],&default_conf.max_acceleration_units_per_sq_second_silent[i],sizeof(cs.max_acceleration_units_per_sq_second_silent[i]));
}
}
tmc2130_set_res(X_AXIS, cs.axis_ustep_resolution[X_AXIS]);
tmc2130_set_res(Y_AXIS, cs.axis_ustep_resolution[Y_AXIS]);
tmc2130_set_res(Z_AXIS, cs.axis_ustep_resolution[Z_AXIS]);
tmc2130_set_res(E_AXIS, cs.axis_ustep_resolution[E_AXIS]);
#ifdef TMC2130
for (uint8_t j = X_AXIS; j <= Y_AXIS; j++)
{
if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY)
cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY;
if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY)
cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY;
if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY)
cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY;
if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY)
cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY;
}
if(cs.axis_ustep_resolution[X_AXIS] == 0xff){ cs.axis_ustep_resolution[X_AXIS] = TMC2130_USTEPS_XY; }
if(cs.axis_ustep_resolution[Y_AXIS] == 0xff){ cs.axis_ustep_resolution[Y_AXIS] = TMC2130_USTEPS_XY; }
if(cs.axis_ustep_resolution[Z_AXIS] == 0xff){ cs.axis_ustep_resolution[Z_AXIS] = TMC2130_USTEPS_Z; }
if(cs.axis_ustep_resolution[E_AXIS] == 0xff){ cs.axis_ustep_resolution[E_AXIS] = TMC2130_USTEPS_E; }
tmc2130_set_res(X_AXIS, cs.axis_ustep_resolution[X_AXIS]);
tmc2130_set_res(Y_AXIS, cs.axis_ustep_resolution[Y_AXIS]);
tmc2130_set_res(Z_AXIS, cs.axis_ustep_resolution[Z_AXIS]);
tmc2130_set_res(E_AXIS, cs.axis_ustep_resolution[E_AXIS]);
#endif //TMC2130
if(is_uninitialized(&cs.travel_acceleration, sizeof(cs.travel_acceleration)))
cs.travel_acceleration = cs.acceleration;
reset_acceleration_rates();
// Call updatePID (similar to when we have processed M301)
updatePID();
#ifdef THERMAL_MODEL
thermal_model_load_settings();
#endif
// Call updatePID (similar to when we have processed M301)
updatePID();
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Stored settings retrieved");
}
else
{
Config_ResetDefault();
//Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now.
//In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used.
if (eeprom_is_initialized_block(EEPROM_M500_base->version, sizeof(EEPROM_M500_base->version))) {
return false;
}
//Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now.
//In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used.
if (eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[0]))) != 0xFF ||
eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[1]))) != 0xFF ||
eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[2]))) != 0xFF)
{
previous_settings_retrieved = false;
}
}
return true;
#ifdef EEPROM_CHITCHAT
Config_PrintSettings();
#endif
return previous_settings_retrieved;
}
#endif
@ -268,20 +335,19 @@ void Config_ResetDefault()
{
memcpy_P(&cs,&default_conf, sizeof(cs));
// steps per sq second need to be updated to agree with the units per sq second
// steps per sq second need to be updated to agree with the units per sq second
reset_acceleration_rates();
#ifdef PIDTEMP
updatePID();
#ifdef PID_ADD_EXTRUSION_RATE
Kc = DEFAULT_Kc; //this is not stored by Config_StoreSettings
#endif//PID_ADD_EXTRUSION_RATE
#endif//PIDTEMP
#ifdef THERMAL_MODEL
thermal_model_reset_settings();
#endif
calculate_extruder_multipliers();
calculate_extruder_multipliers();
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded");
}

View File

@ -9,17 +9,17 @@
typedef struct
{
char version[4];
float axis_steps_per_mm[4];
float axis_steps_per_unit[4];
float max_feedrate_normal[4];
uint32_t max_acceleration_mm_per_s2_normal[4];
unsigned long max_acceleration_units_per_sq_second_normal[4];
float acceleration; //!< Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
float retract_acceleration; //!< mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX
float minimumfeedrate;
float mintravelfeedrate;
uint32_t min_segment_time_us; //!< (µs) M205 B
unsigned long minsegmenttime;
float max_jerk[4]; //!< Jerk is a maximum immediate velocity change.
float add_homing[3];
float zprobe_zoffset; //!< unused
float zprobe_zoffset;
float Kp;
float Ki;
float Kd;
@ -36,15 +36,9 @@ typedef struct
bool volumetric_enabled;
float filament_size[1]; //!< cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
float max_feedrate_silent[4]; //!< max speeds for silent mode
uint32_t max_acceleration_mm_per_s2_silent[4];
unsigned long max_acceleration_units_per_sq_second_silent[4];
unsigned char axis_ustep_resolution[4];
float travel_acceleration; //!< travel acceleration mm/s^2
// Arc Interpolation Settings, configurable via M214
float mm_per_arc_segment;
float min_mm_per_arc_segment;
uint8_t n_arc_correction; // If equal to zero, this is disabled
uint16_t min_arc_segments; // If equal to zero, this is disabled
uint16_t arc_segments_per_sec; // If equal to zero, this is disabled
} M500_conf;
extern M500_conf cs;
@ -65,4 +59,8 @@ FORCE_INLINE void Config_StoreSettings() {}
FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_PrintSettings(); }
#endif
inline uint8_t calibration_status() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); }
inline void calibration_status_store(uint8_t status) { eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); }
inline bool calibration_status_pinda() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA); }
#endif//CONFIG_STORE_H

View File

@ -10,6 +10,16 @@
#endif
#define BED_CHECK_INTERVAL 5000 //ms between checks in bang-bang control
#ifdef PIDTEMP
// this adds an experimental additional term to the heating power, proportional to the extrusion speed.
// if Kc is chosen well, the additional required power due to increased melting should be compensated.
#define PID_ADD_EXTRUSION_RATE
#ifdef PID_ADD_EXTRUSION_RATE
#define DEFAULT_Kc (1) //heating power=Kc*(e_speed)
#endif
#endif
//automatic temperature: The hot end target temperature is calculated by all the buffered lines of gcode.
//The maximum buffered steps/sec of the extruder motor are called "se".
//You enter the autotemp mode by a M109 S<mintemp> B<maxtemp> F<factor>
@ -54,7 +64,7 @@
/**
* Auto-report all at once with M155 S<seconds> C[bitmask] with single timer
*
*
* bit 0 = Auto-report temperatures
* bit 1 = Auto-report fans
* bit 2 = Auto-report position
@ -66,12 +76,6 @@
*/
#define AUTO_REPORT
// Keepalive period which is restarted with M79
#define M79_TIMEOUT 30 * 1000 // ms
// A timer which is restarted everytime a G-command is added to the command queue.
#define USB_TIMER_TIMEOUT 10 * 1000 // ms
//===========================================================================
//=============================Mechanical Settings===========================
//===========================================================================
@ -125,6 +129,34 @@
#endif //End auto min/max positions
//END AUTOSET LOCATIONS OF LIMIT SWITCHES -ZP
// A single Z stepper driver is usually used to drive 2 stepper motors.
// Uncomment this define to utilize a separate stepper driver for each Z axis motor.
// Only a few motherboards support this, like RAMPS, which have dual extruder support (the 2nd, often unused, extruder driver is used
// to control the 2nd Z axis stepper motor). The pins are currently only defined for a RAMPS motherboards.
// On a RAMPS (or other 5 driver) motherboard, using this feature will limit you to using 1 extruder.
//#define Z_DUAL_STEPPER_DRIVERS
#ifdef Z_DUAL_STEPPER_DRIVERS
#undef EXTRUDERS
#define EXTRUDERS 1
#endif
// Same again but for Y Axis.
//#define Y_DUAL_STEPPER_DRIVERS
// Define if the two Y drives need to rotate in opposite directions
#define INVERT_Y2_VS_Y_DIR 1
#ifdef Y_DUAL_STEPPER_DRIVERS
#undef EXTRUDERS
#define EXTRUDERS 1
#endif
#if defined (Z_DUAL_STEPPER_DRIVERS) && defined (Y_DUAL_STEPPER_DRIVERS)
#error "You cannot have dual drivers for both Y and Z"
#endif
//homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
#define X_HOME_RETRACT_MM 5
#define Y_HOME_RETRACT_MM 5
@ -201,27 +233,23 @@
* limit is exceeded.
*/
#define SDCARD_SORT_ALPHA //Alphabetical sorting of SD files menu
// SD Card Sorting options
#ifdef SDCARD_SORT_ALPHA
#define SD_SORT_TIME 0
#define SD_SORT_ALPHA 1
#define SD_SORT_NONE 2
#define INSERTSORT
// #define SHELLSORT
// #define SORTING_DUMP
// #define SORTING_SPEEDTEST
#define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256).
#define FOLDER_SORTING -1 // -1=above 0=none 1=below
#endif
#if defined(SDCARD_SORT_ALPHA)
#define HAS_FOLDER_SORTING (FOLDER_SORTING)
#endif
// Enabe this option to get a pretty message whenever the endstop gets hit (as in the position at which the endstop got triggered)
//#define VERBOSE_CHECK_HIT_ENDSTOPS
// Enable the option to stop SD printing when hitting and endstops, needs to be enabled from the LCD menu when this option is enabled.
//#define ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
@ -268,7 +296,9 @@
//#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging
#endif
// Arc interpretation settings : Moved to the variant files.
// Arc interpretation settings:
#define MM_PER_ARC_SEGMENT 1
#define N_ARC_CORRECTION 25
const unsigned int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement
@ -324,11 +354,6 @@ const unsigned int dropsegments=5; //everything with less than this number of st
// 2nd and 3rd byte (LSB first) contains a 16bit length of a command including its preceding comments.
#define CMDHDRSIZE 3
#define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10.f // (mm/s) Unload filament feedrate. This can be pretty fast.
#define FILAMENT_UNLOAD_FAST_RETRACT_FEEDRATE 86.67f // (mm/s) Unload fast retract feedrate.
#define FILAMENT_UNLOAD_SLOW_RETRACT_FEEDRATE 16.67f // (mm/s) Unload slow retract feedrate.
#define FILAMENT_UNLOAD_FAST_RETRACT_LENGTH 45.f // (mm) Unload fast retract length.
#define FILAMENT_UNLOAD_SLOW_RETRACT_LENGTH 35.f // (mm) Unload slow retract length.
// Firmware based and LCD controlled retract
// M207 and M208 can be used to define parameters for the retraction.
@ -364,7 +389,7 @@ const unsigned int dropsegments=5; //everything with less than this number of st
/**
* Enable M120/M121 G-code commands
*
*
*/
//#define M120_M121_ENABLED //Be careful enabling and using these G-code commands.
@ -380,6 +405,14 @@ const unsigned int dropsegments=5; //everything with less than this number of st
#define THERMISTORHEATER_0 TEMP_SENSOR_0
#define HEATER_0_USES_THERMISTOR
#endif
#if TEMP_SENSOR_1 > 0
#define THERMISTORHEATER_1 TEMP_SENSOR_1
#define HEATER_1_USES_THERMISTOR
#endif
#if TEMP_SENSOR_2 > 0
#define THERMISTORHEATER_2 TEMP_SENSOR_2
#define HEATER_2_USES_THERMISTOR
#endif
#if TEMP_SENSOR_BED > 0
#define THERMISTORBED TEMP_SENSOR_BED
#define BED_USES_THERMISTOR
@ -393,6 +426,12 @@ const unsigned int dropsegments=5; //everything with less than this number of st
#if TEMP_SENSOR_0 == -1
#define HEATER_0_USES_AD595
#endif
#if TEMP_SENSOR_1 == -1
#define HEATER_1_USES_AD595
#endif
#if TEMP_SENSOR_2 == -1
#define HEATER_2_USES_AD595
#endif
#if TEMP_SENSOR_BED == -1
#define BED_USES_AD595
#endif
@ -403,6 +442,14 @@ const unsigned int dropsegments=5; //everything with less than this number of st
#undef HEATER_0_MINTEMP
#undef HEATER_0_MAXTEMP
#endif
#if TEMP_SENSOR_1 == 0
#undef HEATER_1_MINTEMP
#undef HEATER_1_MAXTEMP
#endif
#if TEMP_SENSOR_2 == 0
#undef HEATER_2_MINTEMP
#undef HEATER_2_MAXTEMP
#endif
#if TEMP_SENSOR_BED == 0
#undef BED_MINTEMP
#undef BED_MAXTEMP

View File

@ -1,10 +0,0 @@
// Include the printer's variant configuration header
#pragma once
// This is set by the cmake build to be able to take control of
// the variant header without breaking existing build mechanisms.
#ifndef CMAKE_CONTROL
#include "Configuration_prusa.h"
#else
#include FW_VARIANT
#endif

View File

@ -3,7 +3,6 @@
#include "Configuration.h"
#include "language.h"
#include "cmdqueue.h"
#include "util.h"
#include <stdio.h>
#include <avr/pgmspace.h>
@ -45,7 +44,7 @@ void print_hex_word(daddr_t val)
print_hex_byte(val & 0xFF);
}
int parse_hex(const char* hex, uint8_t* data, int count)
int parse_hex(char* hex, uint8_t* data, int count)
{
int parsed = 0;
while (*hex)
@ -120,7 +119,7 @@ void write_mem(uint16_t address, uint16_t count, const uint8_t* data, const dcod
switch (type)
{
case dcode_mem_t::sram: *((uint8_t*)address) = data[i]; break;
case dcode_mem_t::eeprom: eeprom_write_byte_notify((uint8_t*)address, data[i]); break;
case dcode_mem_t::eeprom: eeprom_write_byte((uint8_t*)address, data[i]); break;
case dcode_mem_t::progmem: break;
case dcode_mem_t::xflash: break;
}
@ -162,19 +161,19 @@ void dcode_core(daddr_t addr_start, const daddr_t addr_end, const dcode_mem_t ty
### D3 - Read/Write EEPROM <a href="https://reprap.org/wiki/G-code#D3:_Read.2FWrite_EEPROM">D3: Read/Write EEPROM</a>
This command can be used without any additional parameters. It will read the entire eeprom.
#### Usage
D3 [ A | C | X ]
#### Parameters
- `A` - Address (x0000-x0fff)
- `C` - Count (1-4096)
- `X` - Data (hex)
#### Notes
- The hex address needs to be lowercase without the 0 before the x
- Count is decimal
- Count is decimal
- The hex data needs to be lowercase
*/
void dcode_3()
{
@ -191,14 +190,21 @@ void dcode_3()
#include <avr/wdt.h>
#include "bootapp.h"
#if 0
extern float current_temperature_pinda;
extern float axis_steps_per_unit[NUM_AXIS];
#define LOG(args...) printf(args)
#endif //0
#define LOG(args...)
/*!
*
### D-1 - Endless Loop <a href="https://reprap.org/wiki/G-code#G28:_Move_to_Origin_.28Home.29">D-1: Endless Loop</a>
D-1
*
*/
void dcode__1()
@ -213,9 +219,9 @@ void dcode__1()
/*!
### D0 - Reset <a href="https://reprap.org/wiki/G-code#D0:_Reset">D0: Reset</a>
#### Usage
D0 [ B ]
#### Parameters
- `B` - Bootloader
*/
@ -238,9 +244,9 @@ void dcode_0()
/*!
*
### D1 - Clear EEPROM and RESET <a href="https://reprap.org/wiki/G-code#D1:_Clear_EEPROM_and_RESET">D1: Clear EEPROM and RESET</a>
D1
*
*/
void dcode_1()
@ -248,7 +254,7 @@ void dcode_1()
LOG("D1 - Clear EEPROM and RESET\n");
cli();
for (int i = 0; i < 8192; i++)
eeprom_write_byte_notify((unsigned char*)i, (unsigned char)0xff);
eeprom_write_byte((unsigned char*)i, (unsigned char)0xff);
softReset();
}
#endif
@ -280,13 +286,13 @@ void dcode_2()
#ifdef DEBUG_DCODES
/*!
### D4 - Read/Write PIN <a href="https://reprap.org/wiki/G-code#D4:_Read.2FWrite_PIN">D4: Read/Write PIN</a>
To read the digital value of a pin you need only to define the pin number.
#### Usage
D4 [ P | F | V ]
#### Parameters
- `P` - Pin (0-255)
- `F` - Function in/out (0/1)
@ -328,19 +334,20 @@ void dcode_4()
### D5 - Read/Write FLASH <a href="https://reprap.org/wiki/G-code#D5:_Read.2FWrite_FLASH">D5: Read/Write Flash</a>
This command can be used without any additional parameters. It will read the 1kb FLASH.
#### Usage
D5 [ A | C | X | E ]
#### Parameters
- `A` - Address (x00000-x3ffff)
- `C` - Count (1-8192)
- `X` - Data (hex)
- `E` - Erase
#### Notes
- The hex address needs to be lowercase without the 0 before the x
- Count is decimal
- Count is decimal
- The hex data needs to be lowercase
*/
void dcode_5()
{
@ -449,9 +456,9 @@ void dcode_7()
/*!
### D8 - Read/Write PINDA <a href="https://reprap.org/wiki/G-code#D8:_Read.2FWrite_PINDA">D8: Read/Write PINDA</a>
#### Usage
D8 [ ? | ! | P | Z ]
#### Parameters
- `?` - Read PINDA temperature shift values
- `!` - Reset PINDA temperature shift values to default
@ -471,7 +478,7 @@ void dcode_8()
{
uint16_t offs = 0;
if (i > 0) offs = eeprom_read_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + (i - 1));
float foffs = ((float)offs) / cs.axis_steps_per_mm[Z_AXIS];
float foffs = ((float)offs) / cs.axis_steps_per_unit[Z_AXIS];
offs = 1000 * foffs;
printf_P(PSTR("temp_pinda=%dC temp_shift=%dum\n"), 35 + i * 5, offs);
}
@ -479,12 +486,12 @@ void dcode_8()
else if (strchr_pointer[1+1] == '!')
{
cal_status = 1;
eeprom_write_byte_notify((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, cal_status);
eeprom_write_word_notify(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 0, 8); //40C - 20um - 8usteps
eeprom_write_word_notify(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 1, 24); //45C - 60um - 24usteps
eeprom_write_word_notify(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 2, 48); //50C - 120um - 48usteps
eeprom_write_word_notify(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 3, 80); //55C - 200um - 80usteps
eeprom_write_word_notify(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 4, 120); //60C - 300um - 120usteps
eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, cal_status);
eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 0, 8); //40C - 20um - 8usteps
eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 1, 24); //45C - 60um - 24usteps
eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 2, 48); //50C - 120um - 48usteps
eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 3, 80); //55C - 200um - 80usteps
eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 4, 120); //60C - 300um - 120usteps
}
else
{
@ -502,11 +509,11 @@ void dcode_8()
/*!
### D9 - Read ADC <a href="https://reprap.org/wiki/G-code#D9:_Read.2FWrite_ADC">D9: Read ADC</a>
#### Usage
D9 [ I | V ]
#### Parameters
- `I` - ADC channel index
- `I` - ADC channel index
- `0` - Heater 0 temperature
- `1` - Heater 1 temperature
- `2` - Bed temperature
@ -531,20 +538,26 @@ const char* dcode_9_ADC_name(uint8_t i)
return 0;
}
#ifdef AMBIENT_THERMISTOR
extern int current_temperature_raw_ambient;
#endif //AMBIENT_THERMISTOR
#ifdef VOLT_PWR_PIN
extern int current_voltage_raw_pwr;
#endif //VOLT_PWR_PIN
#ifdef VOLT_BED_PIN
extern int current_voltage_raw_bed;
#endif //VOLT_BED_PIN
uint16_t dcode_9_ADC_val(uint8_t i)
{
switch (i)
{
#ifdef SHOW_TEMP_ADC_VALUES
case 0: return current_temperature_raw[0];
#endif //SHOW_TEMP_ADC_VALUES
case 1: return 0;
#ifdef SHOW_TEMP_ADC_VALUES
case 2: return current_temperature_bed_raw;
#endif //SHOW_TEMP_ADC_VALUES
#ifdef PINDA_THERMISTOR
case 3: return current_temperature_raw_pinda;
#endif //PINDA_THERMISTOR
#ifdef VOLT_PWR_PIN
case 4: return current_voltage_raw_pwr;
#endif //VOLT_PWR_PIN
@ -566,7 +579,6 @@ void dcode_9()
for (uint8_t i = 0; i < ADC_CHAN_CNT; i++)
printf_P(PSTR("\tADC%d=%4d\t(%S)\n"), i, dcode_9_ADC_val(i) >> 4, dcode_9_ADC_name(i));
}
#if 0
else
{
uint8_t index = 0xff;
@ -577,12 +589,11 @@ void dcode_9()
if (code_seen('V')) // value to be written as simulated
{
adc_sim_mask |= (1 << index);
adc_values[index] = ((uint16_t)code_value_short() << 4);
adc_values[index] = (((int)code_value()) << 4);
printf_P(PSTR("ADC%d=%4d\n"), index, adc_values[index] >> 4);
}
}
}
#endif
}
/*!
@ -591,7 +602,7 @@ void dcode_9()
void dcode_10()
{//Tell the printer that XYZ calibration went OK
LOG("D10 - XYZ calibration = OK\n");
calibration_status_set(CALIBRATION_STATUS_XYZ);
calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
}
/*!
@ -610,9 +621,9 @@ void dcode_12()
### D80 - Bed check <a href="https://reprap.org/wiki/G-code#D80:_Bed_check">D80: Bed check</a>
This command will log data to SD card file "mesh.txt".
#### Usage
D80 [ E | F | G | H | I | J ]
#### Parameters
- `E` - Dimension X (default 40)
- `F` - Dimention Y (default 40)
@ -650,9 +661,9 @@ void dcode_80()
### D81 - Bed analysis <a href="https://reprap.org/wiki/G-code#D81:_Bed_analysis">D80: Bed analysis</a>
This command will log data to SD card file "wldsd.txt".
#### Usage
D81 [ E | F | G | H | I | J ]
#### Parameters
- `E` - Dimension X (default 40)
- `F` - Dimention Y (default 40)
@ -676,9 +687,9 @@ void dcode_81()
if (code_seen("H")) { strchr_pointer+=1; points_y = code_value(); }
if (code_seen("I")) { strchr_pointer+=1; offset_x = code_value(); }
if (code_seen("J")) { strchr_pointer+=1; offset_y = code_value(); }
bed_analysis(dimension_x,dimension_y,points_x,points_y,offset_x,offset_y);
}
#endif //HEATBED_ANALYSIS
@ -705,11 +716,11 @@ extern void st_synchronize();
/*!
### D2130 - Trinamic stepper controller <a href="https://reprap.org/wiki/G-code#D2130:_Trinamic_stepper_controller">D2130: Trinamic stepper controller</a>
@todo Please review by owner of the code. RepRap Wiki Gcode needs to be updated after review of owner as well.
#### Usage
D2130 [ Axis | Command | Subcommand | Value ]
#### Parameters
- Axis
- `X` - X stepper driver
@ -738,21 +749,21 @@ extern void st_synchronize();
- `0, 180 --> 250` - Off
- `0.9 --> 1.25` - Valid values (recommended is 1.1)
- `@` - Home calibrate axis
Examples:
D2130E?wave
Print extruder microstep linearity compensation curve
D2130E!wave0
Disable extruder linearity compensation curve, (sine curve is used)
D2130E!wave220
(sin(x))^1.1 extruder microstep compensation curve used
Notes:
For more information see https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf
*
@ -815,7 +826,7 @@ void dcode_2130()
}
else if (strcmp(strchr_pointer + 7, "wave") == 0)
{
tmc2130_get_wave(axis, 0);
tmc2130_get_wave(axis, 0, stdout);
}
}
else if (strchr_pointer[1+5] == '!')
@ -836,9 +847,9 @@ void dcode_2130()
uint16_t res_new = tmc2130_mres2usteps(mres);
tmc2130_set_res(axis, res_new);
if (res_new > res)
cs.axis_steps_per_mm[axis] *= (res_new / res);
cs.axis_steps_per_unit[axis] *= (res_new / res);
else
cs.axis_steps_per_mm[axis] /= (res / res_new);
cs.axis_steps_per_unit[axis] /= (res / res_new);
}
}
else if (strncmp(strchr_pointer + 7, "wave", 4) == 0)
@ -858,19 +869,20 @@ void dcode_2130()
}
#endif //TMC2130
#if defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
#ifdef PAT9125
/*!
### D9125 - PAT9125 filament sensor <a href="https://reprap.org/wiki/G-code#D9:_Read.2FWrite_ADC">D9125: PAT9125 filament sensor</a>
#### Usage
D9125 [ ? | ! | R | X | Y | L ]
#### Parameters
- `?` - Print values
- `!` - Print values
- `R` - Resolution. Not active in code
- `X` - X values
- `Y` - Y values
- `L` - Activate filament sensor log
*/
void dcode_9125()
{
@ -904,8 +916,15 @@ void dcode_9125()
pat9125_y = (int)code_value();
LOG("pat9125_y=%d\n", pat9125_y);
}
#ifdef DEBUG_FSENSOR_LOG
if (code_seen('L'))
{
fsensor_log = (int)code_value();
LOG("fsensor_log=%d\n", fsensor_log);
}
#endif //DEBUG_FSENSOR_LOG
}
#endif //defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
#endif //PAT9125
#endif //DEBUG_DCODES
@ -977,7 +996,7 @@ void __attribute__((noinline)) serial_dump_and_reset(dump_crash_reason reason)
// sample SP/PC
sp = SP;
pc = GETPC();
GETPC(&pc);
// extend WDT long enough to allow writing the entire stream
wdt_enable(WDTO_8S);

View File

@ -53,9 +53,9 @@ extern void dcode_81(); //D81 - Bed analysis. This command will log data to SD c
extern void dcode_2130(); //D2130 - TMC2130
#endif //TMC2130
#if defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
#ifdef PAT9125
extern void dcode_9125(); //D9125 - PAT9125
#endif //defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
#endif //PAT9125
#endif //DCODES_H

View File

@ -1,509 +0,0 @@
#include <avr/pgmspace.h>
#include <stdio.h>
#include <util/atomic.h>
#include "Filament_sensor.h"
#include "Timer.h"
#include "eeprom.h"
#include "language.h"
#include "menu.h"
#include "messages.h"
#include "mmu2.h"
#include "planner.h"
#include "temperature.h"
#include "ultralcd.h"
#ifdef FILAMENT_SENSOR
FSensorBlockRunout::FSensorBlockRunout() {
fsensor.setRunoutEnabled(false); //suppress filament runouts while loading filament.
fsensor.setAutoLoadEnabled(false); //suppress filament autoloads while loading filament.
#if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
fsensor.setJamDetectionEnabled(false); //suppress filament jam detection while loading filament.
#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
// SERIAL_ECHOLNPGM("FSBlockRunout");
}
FSensorBlockRunout::~FSensorBlockRunout() {
fsensor.settings_init(); // restore filament runout state.
// SERIAL_ECHOLNPGM("FSUnBlockRunout");
}
# if FILAMENT_SENSOR_TYPE == FSENSOR_IR
IR_sensor fsensor;
# elif FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG
IR_sensor_analog fsensor;
# elif FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125
PAT9125_sensor fsensor;
# endif
#else // FILAMENT_SENSOR
FSensorBlockRunout::FSensorBlockRunout() { }
FSensorBlockRunout::~FSensorBlockRunout() { }
#endif // FILAMENT_SENSOR
void Filament_sensor::setEnabled(bool enabled) {
eeprom_update_byte_notify((uint8_t *)EEPROM_FSENSOR, enabled);
if (enabled) {
fsensor.init();
} else {
fsensor.deinit();
}
}
void Filament_sensor::setAutoLoadEnabled(bool state, bool updateEEPROM) {
autoLoadEnabled = state;
if (updateEEPROM) {
eeprom_update_byte_notify((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED, state);
}
}
void Filament_sensor::setRunoutEnabled(bool state, bool updateEEPROM) {
runoutEnabled = state;
if (updateEEPROM) {
eeprom_update_byte_notify((uint8_t *)EEPROM_FSENS_RUNOUT_ENABLED, state);
}
}
void Filament_sensor::setActionOnError(SensorActionOnError state, bool updateEEPROM) {
sensorActionOnError = state;
if (updateEEPROM) {
eeprom_update_byte_notify((uint8_t *)EEPROM_FSENSOR_ACTION_NA, (uint8_t)state);
}
}
void Filament_sensor::settings_init_common() {
bool enabled = eeprom_read_byte((uint8_t *)EEPROM_FSENSOR);
if ((state != State::disabled) != enabled) {
state = enabled ? State::initializing : State::disabled;
}
autoLoadEnabled = eeprom_read_byte((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED);
runoutEnabled = eeprom_read_byte((uint8_t *)EEPROM_FSENS_RUNOUT_ENABLED);
sensorActionOnError = (SensorActionOnError)eeprom_read_byte((uint8_t *)EEPROM_FSENSOR_ACTION_NA);
if (sensorActionOnError == SensorActionOnError::_Undef) {
sensorActionOnError = SensorActionOnError::_Continue;
}
}
bool Filament_sensor::checkFilamentEvents() {
if (state != State::ready)
return false;
if (eventBlankingTimer.running() && !eventBlankingTimer.expired(100)) { // event blanking for 100ms
return false;
}
bool newFilamentPresent = fsensor.getFilamentPresent();
if (oldFilamentPresent != newFilamentPresent) {
oldFilamentPresent = newFilamentPresent;
eventBlankingTimer.start();
if (newFilamentPresent) { // filament insertion
// puts_P(PSTR("filament inserted"));
triggerFilamentInserted();
postponedLoadEvent = true;
} else { // filament removal
// puts_P(PSTR("filament removed"));
triggerFilamentRemoved();
}
return true;
}
return false;
}
void Filament_sensor::triggerFilamentInserted() {
if (autoLoadEnabled
&& (eFilamentAction == FilamentAction::None)
&& !(
MMU2::mmu2.Enabled() // quick and dirty hack to prevent spurious runouts while the MMU is in charge
|| moves_planned() != 0
|| printJobOngoing()
|| (lcd_commands_type == LcdCommands::Layer1Cal)
|| eeprom_read_byte((uint8_t *)EEPROM_WIZARD_ACTIVE)
)
) {
menu_submenu(lcd_AutoLoadFilament, true);
}
}
void Filament_sensor::triggerFilamentRemoved() {
// SERIAL_ECHOLNPGM("triggerFilamentRemoved");
if (runoutEnabled
&& (eFilamentAction == FilamentAction::None)
&& (
moves_planned() != 0
|| printJobOngoing()
)
&& !(
saved_printing
|| MMU2::mmu2.Enabled() // quick and dirty hack to prevent spurious runouts just before the toolchange
|| (lcd_commands_type == LcdCommands::Layer1Cal)
|| eeprom_read_byte((uint8_t *)EEPROM_WIZARD_ACTIVE)
)
){
// SERIAL_ECHOPGM("runoutEnabled="); SERIAL_ECHOLN((int)runoutEnabled);
// SERIAL_ECHOPGM("eFilamentAction="); SERIAL_ECHOLN((int)eFilamentAction);
// SERIAL_ECHOPGM("saved_printing="); SERIAL_ECHOLN((int)saved_printing);
filRunout();
}
}
void Filament_sensor::filRunout() {
// SERIAL_ECHOLNPGM("filRunout");
sendHostNotification_P(MSG_FILAMENT_RUNOUT_DETECTED);
runoutEnabled = false;
autoLoadEnabled = false;
stop_and_save_print_to_ram(0, 0);
restore_print_from_ram_and_continue(0);
eeprom_increment_byte((uint8_t *)EEPROM_FERROR_COUNT);
eeprom_increment_word((uint16_t *)EEPROM_FERROR_COUNT_TOT);
enquecommand_front_P(MSG_M600);
}
void Filament_sensor::triggerError() {
state = State::error;
/// some message, idk
; //
}
#if (FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
void IR_sensor::init() {
if (state == State::error) {
fsensor.deinit(); // deinit first if there was an error.
}
// puts_P(PSTR("fsensor::init()"));
SET_INPUT(IR_SENSOR_PIN); // input mode
WRITE(IR_SENSOR_PIN, 1); // pullup
settings_init(); // also sets the state to State::initializing
}
void IR_sensor::deinit() {
// puts_P(PSTR("fsensor::deinit()"));
SET_INPUT(IR_SENSOR_PIN); // input mode
WRITE(IR_SENSOR_PIN, 0); // no pullup
state = State::disabled;
}
bool IR_sensor::update() {
switch (state) {
case State::initializing:
state = State::ready; // the IR sensor gets ready instantly as it's just a gpio read operation.
// initialize the current filament state so that we don't create a switching event right after the sensor is ready.
oldFilamentPresent = fsensor.getFilamentPresent();
[[fallthrough]];
case State::ready: {
postponedLoadEvent = false;
return checkFilamentEvents();
} break;
case State::disabled:
case State::error:
default:
return false;
}
return false;
}
#ifdef FSENSOR_PROBING
bool IR_sensor::probeOtherType() { return pat9125_probe(); }
#endif
void IR_sensor::settings_init() { Filament_sensor::settings_init_common(); }
#if (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
void IR_sensor_analog::init() {
IR_sensor::init();
IR_sensor::settings_init();
sensorRevision = (SensorRevision)eeprom_read_byte((uint8_t *)EEPROM_FSENSOR_PCB);
}
bool IR_sensor_analog::update() {
bool event = IR_sensor::update();
if (state == State::ready) {
if (getVoltReady()) {
clearVoltReady();
uint16_t volt = getVoltRaw();
// printf_P(PSTR("newVoltRaw:%u\n"), volt / OVERSAMPLENR);
// detect min-max, some long term sliding window for filtration may be added
// avoiding floating point operations, thus computing in raw
if (volt > maxVolt) {
maxVolt = volt;
} else if (volt < minVolt) {
minVolt = volt;
}
//! The trouble is, I can hold the filament in the hole in such a way, that it creates the exact voltage
//! to be detected as the new fsensor
//! We can either fake it by extending the detection window to a looooong time
//! or do some other countermeasures
//! what we want to detect:
//! if minvolt gets below ~0.3V, it means there is an old fsensor
//! if maxvolt gets above 4.6V, it means we either have an old fsensor or broken cables/fsensor
//! So I'm waiting for a situation, when minVolt gets to range <0, 1.5> and maxVolt gets into range <3.0, 5>
//! If and only if minVolt is in range <0.3, 1.5> and maxVolt is in range <3.0, 4.6>, I'm considering a situation with the new fsensor
if (minVolt >= IRsensor_Ldiode_TRESHOLD && minVolt <= IRsensor_Lmax_TRESHOLD && maxVolt >= IRsensor_Hmin_TRESHOLD &&
maxVolt <= IRsensor_Hopen_TRESHOLD) {
IR_ANALOG_Check(SensorRevision::_Old, SensorRevision::_Rev04);
}
//! If and only if minVolt is in range <0.0, 0.3> and maxVolt is in range <4.6, 5.0V>, I'm considering a situation with the old fsensor
//! Note, we are not relying on one voltage here - getting just +5V can mean an old fsensor or a broken new sensor - that's why
//! we need to have both voltages detected correctly to allow switching back to the old fsensor.
else if (minVolt < IRsensor_Ldiode_TRESHOLD && maxVolt > IRsensor_Hopen_TRESHOLD && maxVolt <= IRsensor_VMax_TRESHOLD) {
IR_ANALOG_Check(SensorRevision::_Rev04, SensorRevision::_Old);
}
if (!checkVoltage(volt)) {
triggerError();
}
}
}
; //
return event;
}
void IR_sensor_analog::voltUpdate(uint16_t raw) { // to be called from the ADC ISR when a cycle is finished
voltRaw = raw;
voltReady = true;
}
uint16_t IR_sensor_analog::getVoltRaw() {
uint16_t ret;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ret = voltRaw; }
return ret;
}
const char *IR_sensor_analog::getIRVersionText() {
switch (sensorRevision) {
case SensorRevision::_Old:
return _T(MSG_IR_03_OR_OLDER);
case SensorRevision::_Rev04:
return _T(MSG_IR_04_OR_NEWER);
default:
return _T(MSG_IR_UNKNOWN);
}
}
void IR_sensor_analog::setSensorRevision(SensorRevision rev, bool updateEEPROM) {
sensorRevision = rev;
if (updateEEPROM) {
eeprom_update_byte_notify((uint8_t *)EEPROM_FSENSOR_PCB, (uint8_t)rev);
}
}
bool IR_sensor_analog::checkVoltage(uint16_t raw) {
if (IRsensor_Lmax_TRESHOLD <= raw && raw <= IRsensor_Hmin_TRESHOLD) {
/// If the voltage is in forbidden range, the fsensor is ok, but the lever is mounted improperly.
/// Or the user is so creative so that he can hold a piece of fillament in the hole in such a genius way,
/// that the IR fsensor reading is within 1.5 and 3V ... this would have been highly unusual
/// and would have been considered more like a sabotage than normal printer operation
if (voltageErrorCnt++ > 4) {
puts_P(PSTR("fsensor in forbidden range 1.5-3V - check sensor"));
return false;
}
} else {
voltageErrorCnt = 0;
}
if (sensorRevision == SensorRevision::_Rev04) {
/// newer IR sensor cannot normally produce 4.6-5V, this is considered a failure/bad mount
if (IRsensor_Hopen_TRESHOLD <= raw && raw <= IRsensor_VMax_TRESHOLD) {
puts_P(PSTR("fsensor v0.4 in fault range 4.6-5V - unconnected"));
return false;
}
}
// otherwise the IR fsensor is considered working correctly
return true;
}
bool IR_sensor_analog::getVoltReady() const {
bool ret;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ ret = voltReady; }
return ret;
}
void IR_sensor_analog::clearVoltReady(){
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ voltReady = false; }
}
void IR_sensor_analog::IR_ANALOG_Check(SensorRevision isVersion, SensorRevision switchTo) {
bool bTemp = (!CHECK_ALL_HEATERS);
bTemp = bTemp && (menu_menu == lcd_status_screen);
bTemp = bTemp && ((sensorRevision == isVersion) || (sensorRevision == SensorRevision::_Undef));
bTemp = bTemp && (state == State::ready);
if (bTemp) {
nFSCheckCount++;
if (nFSCheckCount > FS_CHECK_COUNT) {
nFSCheckCount = 0; // not necessary
setSensorRevision(switchTo, true);
printf_IRSensorAnalogBoardChange();
switch (switchTo) {
case SensorRevision::_Old:
lcd_setstatuspgm(_T(MSG_IR_03_OR_OLDER));
break;
case SensorRevision::_Rev04:
lcd_setstatuspgm(_T(MSG_IR_04_OR_NEWER));
break;
default:
break;
}
}
} else {
nFSCheckCount = 0;
}
}
#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
#if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
void PAT9125_sensor::init() {
if (state == State::error) {
deinit(); // deinit first if there was an error.
}
// puts_P(PSTR("fsensor::init()"));
settings_init(); // also sets the state to State::initializing
calcChunkSteps(cs.axis_steps_per_mm[E_AXIS]); // for jam detection
if (!pat9125_init()) {
deinit();
triggerError();
; //
}
#ifdef IR_SENSOR_PIN
else if (!READ(IR_SENSOR_PIN)) {
; // MK3 fw on MK3S printer
}
#endif // IR_SENSOR_PIN
}
void PAT9125_sensor::deinit() {
// puts_P(PSTR("fsensor::deinit()"));
; //
state = State::disabled;
filter = 0;
}
bool PAT9125_sensor::update() {
switch (state) {
case State::initializing:
if (!updatePAT9125()) {
break; // still not stable. Stay in the initialization state.
}
oldFilamentPresent =
getFilamentPresent(); // initialize the current filament state so that we don't create a switching event right after the sensor is ready.
oldPos = pat9125_y;
state = State::ready;
break;
case State::ready: {
updatePAT9125();
postponedLoadEvent = false;
bool event = checkFilamentEvents();
; //
return event;
} break;
case State::disabled:
case State::error:
default:
return false;
}
return false;
}
#ifdef FSENSOR_PROBING
bool PAT9125_sensor::probeOtherType() {
SET_INPUT(IR_SENSOR_PIN); // input mode
WRITE(IR_SENSOR_PIN, 1); // pullup
_delay_us(100); // wait for the pullup to pull the line high (might be needed, not really sure. The internal pullups are quite weak and there might be a
// long wire attached).
bool fsensorDetected = !READ(IR_SENSOR_PIN);
WRITE(IR_SENSOR_PIN, 0); // no pullup
return fsensorDetected;
}
#endif
void PAT9125_sensor::setJamDetectionEnabled(bool state, bool updateEEPROM) {
jamDetection = state;
oldPos = pat9125_y;
resetStepCount();
jamErrCnt = 0;
if (updateEEPROM) {
eeprom_update_byte_notify((uint8_t *)EEPROM_FSENSOR_JAM_DETECTION, state);
}
}
void PAT9125_sensor::settings_init() {
// puts_P(PSTR("settings_init"));
Filament_sensor::settings_init_common();
setJamDetectionEnabled(eeprom_read_byte((uint8_t *)EEPROM_FSENSOR_JAM_DETECTION));
}
int16_t PAT9125_sensor::getStepCount() {
int16_t ret;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ret = stepCount; }
return ret;
}
void PAT9125_sensor::resetStepCount() {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { stepCount = 0; }
}
void PAT9125_sensor::filJam() {
runoutEnabled = false;
autoLoadEnabled = false;
jamDetection = false;
stop_and_save_print_to_ram(0, 0);
restore_print_from_ram_and_continue(0);
eeprom_increment_byte((uint8_t *)EEPROM_FERROR_COUNT);
eeprom_increment_word((uint16_t *)EEPROM_FERROR_COUNT_TOT);
enquecommand_front_P(MSG_M600);
}
bool PAT9125_sensor::updatePAT9125() {
if (jamDetection) {
int16_t _stepCount = getStepCount();
if (abs(_stepCount) >= chunkSteps) { // end of chunk. Check distance
resetStepCount();
if (!pat9125_update()) { // get up to date data. reinit on error.
init(); // try to reinit.
}
bool fsDir = (pat9125_y - oldPos) > 0;
bool stDir = _stepCount > 0;
if (fsDir != stDir) {
jamErrCnt++;
} else if (jamErrCnt) {
jamErrCnt--;
}
oldPos = pat9125_y;
}
if (jamErrCnt > 10) {
jamErrCnt = 0;
filJam();
}
}
if (pollingTimer.expired_cont(pollingPeriod)) {
pollingTimer.start();
if (!pat9125_update()) {
init(); // try to reinit.
}
bool present = (pat9125_s < 17) || (pat9125_s >= 17 && pat9125_b >= 50);
if (present != filterFilPresent) {
filter++;
} else if (filter) {
filter--;
}
if (filter >= filterCnt) {
filter = 0;
filterFilPresent = present;
}
}
return (filter == 0); // return stability
}
#endif // #if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)

View File

@ -1,212 +0,0 @@
#pragma once
#include <inttypes.h>
#include "cmdqueue.h"
#include "pins.h"
#include "fastio.h"
#include "adc.h"
#include "pat9125.h"
#define FSENSOR_IR 1
#define FSENSOR_IR_ANALOG 2
#define FSENSOR_PAT9125 3
/// Can be used to block printer's filament sensor handling - to avoid errorneous injecting of M600
/// while doing a toolchange with the MMU
/// In case of "no filament sensor" these methods default to an empty implementation
class FSensorBlockRunout {
public:
FSensorBlockRunout();
~FSensorBlockRunout();
};
/// Base class Filament sensor
///
/// Ideally, there could have been a nice class hierarchy of filament sensor types with common functionality
/// extracted into this base class.
/// But:
/// - virtual methods take more space
/// - we don't need to switch among different filament sensors at runtime
/// Therefore the class hierarchy carefully avoids using virtual methods and doesn't look too fancy.
#ifdef FILAMENT_SENSOR
class Filament_sensor {
public:
enum class State : uint8_t {
disabled = 0,
initializing,
ready,
error,
};
enum class SensorActionOnError : uint8_t {
_Continue = 0,
_Pause = 1,
_Undef = EEPROM_EMPTY_VALUE
};
static void setEnabled(bool enabled);
void setAutoLoadEnabled(bool state, bool updateEEPROM = false);
bool getAutoLoadEnabled() const { return autoLoadEnabled; }
void setRunoutEnabled(bool state, bool updateEEPROM = false);
bool getRunoutEnabled() const { return runoutEnabled; }
void setActionOnError(SensorActionOnError state, bool updateEEPROM = false);
SensorActionOnError getActionOnError() const { return sensorActionOnError; }
bool getFilamentLoadEvent() const { return postponedLoadEvent; }
bool isError() const { return state == State::error; }
bool isReady() const { return state == State::ready; }
bool isEnabled() const { return state != State::disabled; }
protected:
void settings_init_common();
bool checkFilamentEvents();
void triggerFilamentInserted();
void triggerFilamentRemoved();
void filRunout();
void triggerError();
State state;
bool autoLoadEnabled;
bool runoutEnabled;
bool oldFilamentPresent; //for creating filament presence switching events.
bool postponedLoadEvent; //this event lasts exactly one update cycle. It is long enough to be able to do polling for load event.
ShortTimer eventBlankingTimer;
SensorActionOnError sensorActionOnError;
};
#if (FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
class IR_sensor: public Filament_sensor {
public:
void init();
void deinit();
bool update();
bool getFilamentPresent() const { return !READ(IR_SENSOR_PIN); }
#ifdef FSENSOR_PROBING
static bool probeOtherType(); //checks if the wrong fsensor type is detected.
#endif
void settings_init();
};
#if (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
constexpr static uint16_t Voltage2Raw(float V) {
return (V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F;
}
constexpr static float Raw2Voltage(uint16_t raw) {
return VOLT_DIV_REF * (raw / (1023.F * OVERSAMPLENR));
}
class IR_sensor_analog: public IR_sensor {
public:
void init();
bool update();
void voltUpdate(uint16_t raw);
uint16_t __attribute__((noinline)) getVoltRaw();
enum class SensorRevision : uint8_t {
_Old = 0,
_Rev04 = 1,
_Undef = EEPROM_EMPTY_VALUE
};
SensorRevision getSensorRevision() const { return sensorRevision; }
const char* __attribute__((noinline)) getIRVersionText();
void setSensorRevision(SensorRevision rev, bool updateEEPROM = false);
constexpr static uint16_t IRsensor_Ldiode_TRESHOLD = Voltage2Raw(0.3F); // ~0.3V, raw value=982
constexpr static uint16_t IRsensor_Lmax_TRESHOLD = Voltage2Raw(1.5F); // ~1.5V (0.3*Vcc), raw value=4910
constexpr static uint16_t IRsensor_Hmin_TRESHOLD = Voltage2Raw(3.0F); // ~3.0V (0.6*Vcc), raw value=9821
constexpr static uint16_t IRsensor_Hopen_TRESHOLD = Voltage2Raw(4.6F); // ~4.6V (N.C. @ Ru~20-50k, Rd'=56k, Ru'=10k), raw value=15059
constexpr static uint16_t IRsensor_VMax_TRESHOLD = Voltage2Raw(5.F); // ~5V, raw value=16368
private:
SensorRevision sensorRevision;
bool voltReady; // set by the adc ISR, therefore avoid accessing the variable directly but use getVoltReady()
bool getVoltReady()const;
void clearVoltReady();
uint16_t voltRaw; // set by the adc ISR, therefore avoid accessing the variable directly but use getVoltRaw()
bool checkVoltage(uint16_t raw);
uint16_t minVolt = Voltage2Raw(6.F);
uint16_t maxVolt = 0;
uint16_t nFSCheckCount;
uint8_t voltageErrorCnt;
static constexpr uint16_t FS_CHECK_COUNT = 4;
/// Switching mechanism of the fsensor type.
/// Called from 2 spots which have a very similar behavior
/// 1: SensorRevision::_Old -> SensorRevision::_Rev04 and print _i("FS v0.4 or newer")
/// 2: SensorRevision::_Rev04 -> sensorRevision=SensorRevision::_Old and print _i("FS v0.3 or older")
void IR_ANALOG_Check(SensorRevision isVersion, SensorRevision switchTo);
};
#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
#if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
class PAT9125_sensor: public Filament_sensor {
public:
void init();
void deinit();
bool update();
bool getFilamentPresent() const { return filterFilPresent; }
#ifdef FSENSOR_PROBING
bool probeOtherType(); //checks if the wrong fsensor type is detected.
#endif
void setJamDetectionEnabled(bool state, bool updateEEPROM = false);
bool getJamDetectionEnabled() const { return jamDetection; }
void stStep(bool rev) { //from stepper isr
stepCount += rev ? -1 : 1;
}
void settings_init();
private:
static constexpr uint16_t pollingPeriod = 10; //[ms]
static constexpr uint8_t filterCnt = 5; //how many checks need to be done in order to determine the filament presence precisely.
ShortTimer pollingTimer;
uint8_t filter;
uint8_t filterFilPresent;
bool jamDetection;
int16_t oldPos;
int16_t stepCount;
int16_t chunkSteps;
uint8_t jamErrCnt;
constexpr void calcChunkSteps(float u) {
chunkSteps = (int16_t)(1.25 * u); //[mm]
}
int16_t getStepCount();
void resetStepCount();
void filJam();
bool updatePAT9125();
};
#endif //(FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
#if FILAMENT_SENSOR_TYPE == FSENSOR_IR
extern IR_sensor fsensor;
#elif FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG
extern IR_sensor_analog fsensor;
#elif FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125
extern PAT9125_sensor fsensor;
#endif
#endif //FILAMENT_SENSOR

View File

@ -1,74 +0,0 @@
{0x3E, {0x0F, 0xA8, 0xAF, 0x00, }, 'H'}, // index=0x80, utf8='🄷'
{0x00, {0x69, 0x96, 0x00, 0x00, }, '\xdf'}, // index=0x81, utf8='°'
{0x60, {0x25, 0x55, 0x58, 0x87, }, 'h'}, // index=0x82, utf8='🌡'
{0x04, {0x27, 0xF2, 0xE0, 0x00, }, '^'}, // index=0x83, utf8='⬏'
{0x34, {0x03, 0xCC, 0x19, 0x60, }, '\xf3'}, // index=0x84, utf8='🔃'
{0x3C, {0x0E, 0xF8, 0x8F, 0x00, }, '\xdb'}, // index=0x85, utf8='🗀'
{0x08, {0x02, 0x94, 0x92, 0x00, }, '>'}, // index=0x86, utf8='»'
{0x1C, {0x07, 0x9A, 0x87, 0x00, }, '\xe5'}, // index=0x87, utf8='🕑'
{0x24, {0x00, 0x85, 0x28, 0x52, }, '\x7e'}, // index=0x88, utf8='⏬'
{0x06, {0x00, 0x1B, 0xE4, 0x00, }, '\x7e'}, // index=0x89, utf8='✔'
{0x78, {0x12, 0x70, 0x78, 0x70, }, 'a'}, // index=0x8A, utf8='á'
{0xF8, {0x12, 0x78, 0x8F, 0x88, }, 'A'}, // index=0x8B, utf8='Á'
{0x78, {0x42, 0x70, 0x78, 0x70, }, 'a'}, // index=0x8C, utf8='à'
{0x78, {0x25, 0x70, 0x78, 0x70, }, 'a'}, // index=0x8D, utf8='â'
{0xF8, {0x50, 0x78, 0x8F, 0x88, }, '\xd1'}, // index=0x8E, utf8='Ä'
{0xF0, {0x25, 0x27, 0x07, 0x87, }, 'a'}, // index=0x8F, utf8='å'
{0xF0, {0x25, 0x27, 0x8F, 0x88, }, 'A'}, // index=0x90, utf8='Å'
{0x2C, {0x0D, 0x27, 0xAA, 0x50, }, '\xd1'}, // index=0x91, utf8='æ'
{0xBC, {0x07, 0x07, 0x87, 0x11, }, 'a'}, // index=0x92, utf8='ą'
{0xBE, {0x78, 0x8F, 0x88, 0x11, }, 'A'}, // index=0x93, utf8='Ą'
{0x78, {0x52, 0x70, 0x78, 0x70, }, 'a'}, // index=0x94, utf8='ă'
{0xF8, {0x52, 0x78, 0x8F, 0x88, }, 'A'}, // index=0x95, utf8='Ă'
{0x20, {0x12, 0x78, 0x88, 0x70, }, 'c'}, // index=0x96, utf8='ć'
{0x20, {0x52, 0x78, 0x88, 0x70, }, 'c'}, // index=0x97, utf8='č'
{0x48, {0x52, 0x78, 0x88, 0x87, }, 'C'}, // index=0x98, utf8='Č'
{0x03, {0x11, 0x17, 0x99, 0x70, }, 'd'}, // index=0x99, utf8='ď'
{0x18, {0x12, 0x78, 0xF8, 0x70, }, 'e'}, // index=0x9A, utf8='é'
{0x44, {0x12, 0xF8, 0xF8, 0xF0, }, 'E'}, // index=0x9B, utf8='É'
{0x18, {0x42, 0x78, 0xF8, 0x70, }, 'e'}, // index=0x9C, utf8='è'
{0x18, {0x25, 0x78, 0xF8, 0x70, }, 'e'}, // index=0x9D, utf8='ê'
{0x18, {0x52, 0x78, 0xF8, 0x70, }, 'e'}, // index=0x9E, utf8='ě'
{0x18, {0x50, 0x78, 0xF8, 0x70, }, 'e'}, // index=0x9F, utf8='ë'
{0x0C, {0x07, 0x8F, 0x87, 0x23, }, 'e'}, // index=0xA0, utf8='ę'
{0xA2, {0x0F, 0x8F, 0x8F, 0x11, }, 'E'}, // index=0xA1, utf8='Ę'
{0x00, {0x12, 0x06, 0x22, 0x70, }, 'i'}, // index=0xA2, utf8='í'
{0x00, {0x12, 0x07, 0x22, 0x27, }, 'I'}, // index=0xA3, utf8='Í'
{0x00, {0x25, 0x06, 0x22, 0x70, }, 'i'}, // index=0xA4, utf8='î'
{0x00, {0x25, 0x07, 0x22, 0x27, }, 'I'}, // index=0xA5, utf8='Î'
{0x00, {0x12, 0x06, 0x22, 0x27, }, 'l'}, // index=0xA6, utf8='ĺ'
{0x02, {0x62, 0x36, 0xA2, 0x70, }, 'l'}, // index=0xA7, utf8='ł'
{0x40, {0x45, 0x6C, 0x44, 0x70, }, 'L'}, // index=0xA8, utf8='Ł'
{0x03, {0x62, 0x22, 0x22, 0x70, }, 'l'}, // index=0xA9, utf8='ľ'
{0x43, {0x88, 0x88, 0x88, 0xF0, }, 'L'}, // index=0xAA, utf8='Ľ'
{0x78, {0x12, 0xBC, 0x88, 0x80, }, 'n'}, // index=0xAB, utf8='ń'
{0x78, {0x52, 0xBC, 0x88, 0x80, }, 'n'}, // index=0xAC, utf8='ň'
{0x38, {0x12, 0x78, 0x88, 0x70, }, 'o'}, // index=0xAD, utf8='ó'
{0x78, {0x12, 0x78, 0x88, 0x87, }, 'O'}, // index=0xAE, utf8='Ó'
{0x38, {0x42, 0x78, 0x88, 0x70, }, 'o'}, // index=0xAF, utf8='ò'
{0x38, {0x25, 0x78, 0x88, 0x70, }, 'o'}, // index=0xB0, utf8='ô'
{0x3A, {0x00, 0x79, 0xAC, 0x78, }, 'o'}, // index=0xB1, utf8='ø'
{0x3D, {0x07, 0x9A, 0xAC, 0x78, }, 'o'}, // index=0xB2, utf8='Ø'
{0x78, {0x50, 0x78, 0x88, 0x87, }, '\xef'}, // index=0xB3, utf8='Ö'
{0x39, {0x49, 0x78, 0x88, 0x70, }, 'o'}, // index=0xB4, utf8='ő'
{0x08, {0x52, 0xBC, 0x88, 0x80, }, 'r'}, // index=0xB5, utf8='ř'
{0x98, {0x52, 0xF8, 0x8F, 0x98, }, 'R'}, // index=0xB6, utf8='Ř'
{0x20, {0x12, 0x78, 0x70, 0xF0, }, 's'}, // index=0xB7, utf8='ś'
{0x48, {0x12, 0x78, 0x63, 0x87, }, 'S'}, // index=0xB8, utf8='Ś'
{0x20, {0x52, 0x78, 0x70, 0xF0, }, 's'}, // index=0xB9, utf8='š'
{0x48, {0x52, 0x78, 0x63, 0x87, }, 'S'}, // index=0xBA, utf8='Š'
{0x10, {0x07, 0x87, 0x0F, 0x24, }, 's'}, // index=0xBB, utf8='ș'
{0x12, {0x78, 0x63, 0x87, 0x24, }, 'S'}, // index=0xBC, utf8='Ș'
{0x60, {0x69, 0x9A, 0x98, 0x8B, }, '\xe2'}, // index=0xBD, utf8='ß'
{0x23, {0x04, 0xE4, 0x44, 0x30, }, 't'}, // index=0xBE, utf8='ť'
{0x10, {0x4E, 0x44, 0x43, 0x24, }, 't'}, // index=0xBF, utf8='ț'
{0x7C, {0x12, 0x88, 0x89, 0x60, }, 'u'}, // index=0xC0, utf8='ú'
{0x3C, {0x50, 0x88, 0x88, 0x70, }, 'U'}, // index=0xC1, utf8='Ü'
{0x78, {0x25, 0x28, 0x89, 0x60, }, 'u'}, // index=0xC2, utf8='ů'
{0x79, {0x49, 0x08, 0x89, 0x60, }, 'u'}, // index=0xC3, utf8='ű'
{0x3C, {0x12, 0x88, 0x70, 0x70, }, 'y'}, // index=0xC4, utf8='ý'
{0x0C, {0x12, 0x88, 0x52, 0x22, }, 'Y'}, // index=0xC5, utf8='Ý'
{0x44, {0x12, 0xF1, 0x24, 0xF0, }, 'z'}, // index=0xC6, utf8='ź'
{0x44, {0x52, 0xF1, 0x24, 0xF0, }, 'z'}, // index=0xC7, utf8='ž'
{0x8C, {0x52, 0xF0, 0x36, 0x8F, }, 'Z'}, // index=0xC8, utf8='Ž'
{0x44, {0x20, 0xF1, 0x24, 0xF0, }, 'z'}, // index=0xC9, utf8='ż'

View File

@ -21,7 +21,7 @@
#include "Configuration.h"
#include "pins.h"
#include "Timer.h"
#include "printer_state.h"
extern uint8_t mbl_z_probe_nr;
#ifndef AT90USB
#define HardwareSerial_h // trick to disable the standard HWserial
@ -63,13 +63,25 @@
#define MYSERIAL MSerial
#endif
#include "lcd.h"
#ifdef __cplusplus
extern "C" {
#endif
extern FILE _uartout;
#ifdef __cplusplus
}
#endif
#define uartout (&_uartout)
#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x))
#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y))
#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x)))
#define SERIAL_PROTOCOLRPGM(x) (serialprintPGM((x)))
#define SERIAL_PROTOCOLLN(x) (MYSERIAL.println(x))
#define SERIAL_PROTOCOLLNPGM(x) (serialprintlnPGM(PSTR(x)))
#define SERIAL_PROTOCOLLNRPGM(x) (serialprintlnPGM((x)))
#define SERIAL_PROTOCOLLN(x) (MYSERIAL.println(x)/*,MYSERIAL.write('\n')*/)
#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.println()/*write('\n')*/)
#define SERIAL_PROTOCOLLNRPGM(x) (serialprintPGM((x)),MYSERIAL.println()/*write('\n')*/)
extern const char errormagic[] PROGMEM;
@ -103,9 +115,6 @@ void serial_echopair_P(const char *s_P, unsigned long v);
// I'd rather skip a few CPU ticks than 5.5KB (!!) of FLASH
void serialprintPGM(const char *str);
//The "ln" variant of the function above.
void serialprintlnPGM(const char *str);
bool is_buffer_empty();
void process_commands();
void ramming();
@ -121,20 +130,35 @@ void manage_inactivity(bool ignore_stepper_queue=false);
#endif
#if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1
#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
#define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
#ifdef Y_DUAL_STEPPER_DRIVERS
#define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); }
#define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
#else
#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
#define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
#endif
#else
#define enable_y() ;
#define disable_y() ;
#endif
#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
#if defined(Z_AXIS_ALWAYS_ON)
#ifdef Z_DUAL_STEPPER_DRIVERS
#define poweron_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
#define poweroff_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
#else
#define poweron_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
#define poweroff_z() {}
#endif
#else
#ifdef Z_DUAL_STEPPER_DRIVERS
#define poweron_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
#define poweroff_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
#else
#define poweron_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
#define poweroff_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
#endif
#endif
#else
#define poweron_z() {}
@ -145,7 +169,6 @@ void manage_inactivity(bool ignore_stepper_queue=false);
#define enable_z() poweron_z()
#define disable_z() poweroff_z()
#else
extern bool bEnableForce_z; // Used by ultralcd stealth toggle
void init_force_z();
void check_force_z();
void enable_force_z();
@ -154,6 +177,21 @@ void manage_inactivity(bool ignore_stepper_queue=false);
#define disable_z() disable_force_z()
#endif // PSU_Delta
//#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1
//#ifdef Z_DUAL_STEPPER_DRIVERS
//#define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
//#else
//#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
//#endif
//#else
//#define enable_z() ;
//#define disable_z() ;
//#endif
#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1)
#define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON)
#define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON)
@ -162,6 +200,26 @@ void manage_inactivity(bool ignore_stepper_queue=false);
#define disable_e0() /* nothing */
#endif
#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
#define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON)
#define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON)
#else
#define enable_e1() /* nothing */
#define disable_e1() /* nothing */
#endif
#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
#define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON)
#define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON)
#else
#define enable_e2() /* nothing */
#define disable_e2() /* nothing */
#endif
#define FARM_FILAMENT_COLOR_NONE 99;
enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5};
#define X_AXIS_MASK 1
#define Y_AXIS_MASK 2
@ -175,14 +233,14 @@ void FlushSerialRequestResend();
void ClearToSend();
void update_currents();
void kill(const char *full_screen_message = NULL);
void get_coordinates();
void prepare_move();
void kill(const char *full_screen_message = NULL, unsigned char id = 0);
void finishAndDisableSteppers();
void UnconditionalStop(); // Stop heaters, motion and clear current print status
void ConditionalStop(); // Similar to UnconditionalStop, but doesn't disable heaters
void ThermalStop(bool allow_pause = false); // Emergency stop used by overtemp functions which allows
// recovery (with pause=true)
bool IsStopped(); // Returns true if the print has been stopped
void UnconditionalStop(); // Stop heaters, motion and clear current print status
void Stop(); // Emergency stop used by overtemp functions which allows recovery
bool IsStopped(); // Returns true if the print has been stopped
//put an ASCII command at the end of the current buffer, read from flash
#define enquecommand_P(cmd) enquecommand(cmd, true)
@ -190,92 +248,120 @@ bool IsStopped(); // Returns true if the print has bee
//put an ASCII command at the begin of the current buffer, read from flash
#define enquecommand_front_P(cmd) enquecommand_front(cmd, true)
void prepare_arc_move(char isclockwise);
void clamp_to_software_endstops(float target[3]);
void refresh_cmd_timeout(void);
// Timer counter, incremented by the 1ms Arduino timer.
// The standard Arduino timer() function returns this value atomically
// by disabling / enabling interrupts. This is costly, if the interrupts are known
// to be disabled.
#ifdef SYSTEM_TIMER_2
extern volatile unsigned long timer2_millis;
#else //SYSTEM_TIMER_2
extern volatile unsigned long timer0_millis;
#endif //SYSTEM_TIMER_2
// An unsynchronized equivalent to a standard Arduino _millis() function.
// To be used inside an interrupt routine.
FORCE_INLINE unsigned long millis_nc() {
#ifdef SYSTEM_TIMER_2
return timer2_millis;
#else //SYSTEM_TIMER_2
return timer0_millis;
#endif //SYSTEM_TIMER_2
}
#ifdef FAST_PWM_FAN
void setPwmFrequency(uint8_t pin, int val);
#endif
enum class HeatingStatus : uint8_t
{
NO_HEATING = 0,
EXTRUDER_HEATING = 1,
EXTRUDER_HEATING_COMPLETE = 2,
BED_HEATING = 3,
BED_HEATING_COMPLETE = 4,
};
extern HeatingStatus heating_status;
extern bool fans_check_enabled;
constexpr float homing_feedrate[] = HOMING_FEEDRATE;
extern float homing_feedrate[];
extern uint8_t axis_relative_modes;
extern float feedrate;
extern int feedmultiply;
extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
extern float extruder_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
extern float current_position[NUM_AXIS] ;
extern float destination[NUM_AXIS] ;
extern float min_pos[3];
extern float max_pos[3];
extern bool axis_known_position[3];
extern uint8_t fanSpeed; //!< Print fan speed, ranges from 0 to 255
extern int fanSpeed;
extern uint8_t newFanSpeed;
extern int8_t lcd_change_fil_state;
extern float default_retraction;
void get_coordinates();
void prepare_move(uint16_t start_segment_idx = 0);
void prepare_arc_move(bool isclockwise, uint16_t start_segment_idx = 0);
uint16_t restore_interrupted_gcode();
///@brief Helper function to reduce code size, cheaper to call function than to inline division
///@param feedrate_mm_min feedrate with unit mm per minute
///@returns feedrate with unit mm per second
float __attribute__((noinline)) get_feedrate_mm_s(const float feedrate_mm_min);
#ifdef TMC2130
void check_Z_crash(void);
void homeaxis(uint8_t axis, uint8_t cnt = 1, uint8_t* pstep = 0);
void homeaxis(int axis, uint8_t cnt = 1, uint8_t* pstep = 0);
#else
void homeaxis(uint8_t axis, uint8_t cnt = 1);
void homeaxis(int axis, uint8_t cnt = 1);
#endif //TMC2130
#ifdef FAN_SOFT_PWM
extern unsigned char fanSpeedSoftPwm;
#endif
#ifdef FWRETRACT
extern bool retracted[EXTRUDERS];
extern float retract_length_swap;
extern float retract_recover_length_swap;
#endif
extern ShortTimer usb_timer;
extern bool processing_tcode;
extern uint8_t host_keepalive_interval;
extern unsigned long starttime;
extern unsigned long stoptime;
extern int bowden_length[4];
extern bool is_usb_printing;
extern bool homing_flag;
extern uint32_t total_filament_used; // mm/100 or 10um
extern bool loading_flag;
extern unsigned int usb_printing_counter;
/// @brief Save print statistics to EEPROM
void save_statistics();
extern unsigned long kicktime;
extern unsigned long total_filament_used;
void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time);
extern unsigned int heating_status;
extern unsigned int status_number;
extern unsigned int heating_status_counter;
extern char snmm_filaments_used;
extern unsigned long PingTime;
extern unsigned long NcTime;
extern bool no_response;
extern uint8_t important_status;
extern uint8_t saved_filament_type;
extern bool fan_state[2];
extern int fan_edge_counter[2];
extern int fan_speed[2];
// Active extruder becomes a #define to make the whole firmware compilable.
// We may even remove the references to it wherever possible in the future
#define active_extruder 0
// Handling multiple extruders pins
extern uint8_t active_extruder;
//Long pause
extern unsigned long pause_time;
extern unsigned long start_pause_print;
extern unsigned long t_fan_rising_edge;
extern bool mesh_bed_leveling_flag;
extern bool did_pause_print;
extern bool mesh_bed_run_from_menu;
extern int8_t lcd_change_fil_state;
// save/restore printing
extern bool saved_printing;
extern uint32_t saved_sdpos;
extern uint8_t saved_printing_type;
#define PRINTING_TYPE_SD 0
#define PRINTING_TYPE_USB 1
#define PRINTING_TYPE_NONE 2
extern uint16_t saved_extruder_temperature; //!< Active extruder temperature
extern uint8_t saved_bed_temperature; //!< Bed temperature
extern bool saved_extruder_relative_mode;
extern uint8_t saved_fan_speed; //!< Print fan speed, ranges from 0 to 255
extern float saved_pos[NUM_AXIS];
extern uint16_t saved_feedrate2;
//save/restore printing in case that mmu is not responding
extern bool mmu_print_saved;
//estimated time to end of the print
extern uint8_t print_percent_done_normal;
@ -287,25 +373,13 @@ extern uint16_t print_time_to_change_silent;
#define PRINT_TIME_REMAINING_INIT 0xffff
extern uint16_t mcode_in_progress;
extern uint16_t gcode_in_progress;
extern LongTimer safetyTimer;
#define PRINT_PERCENT_DONE_INIT 0xff
// Returns true if there is a print running. It does not matter if
// the print is paused, that still counts as a "running" print.
bool printJobOngoing();
// Make debug_printer_states available everywhere
#ifdef DEBUG_PRINTER_STATES
void debug_printer_states();
#endif //DEBUG_PRINTER_STATES
// Printing is paused according to SD or host indicators
bool printingIsPaused();
bool printer_active();
bool printer_recovering();
#define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CustomMsg::TempCal) || saved_printing || (lcd_commands_type == LcdCommands::Layer1Cal) || mmu_print_saved || homing_flag || mesh_bed_leveling_flag)
//! Beware - mcode_in_progress is set as soon as the command gets really processed,
//! which is not the same as posting the M600 command into the command queue
@ -314,26 +388,11 @@ bool printer_recovering();
//! Instead, the fsensor uses another state variable :( , which is set to true, when the M600 command is enqued
//! and is reset to false when the fsensor returns into its filament runout finished handler
//! I'd normally change this macro, but who knows what would happen in the MMU :)
bool check_fsensor();
//! Condition where Babystepping is allowed:
//! 1) Not allowed during Homing (printer busy)
//! 2) Not allowed during Mesh Bed Leveling (printer busy)
//! 3) Not allowed when a print job is paused
//! 4) Allowed if:
//! - First Layer Calibration is running (the event when heaters are turned off is used to dismiss the menu)
//! - A print job is running
//! - If the printer is idle with not planned moves
bool babystep_allowed();
//! Same as babystep_allowed() but additionally adds a requirement
//! where the Z-axis position must be less than 2.0mm (only allowed
//! during the first couple of layers)
bool babystep_allowed_strict();
#define CHECK_FSENSOR ((IS_SD_PRINTING || is_usb_printing) && (mcode_in_progress != 600) && !saved_printing && e_active())
extern void calculate_extruder_multipliers();
// Similar to the default Arduino delay function,
// Similar to the default Arduino delay function,
// but it keeps the background tasks running.
extern void delay_keep_alive(unsigned int ms);
@ -349,6 +408,7 @@ void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_
void bed_check(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y);
#endif //HEATBED_ANALYSIS
float temp_comp_interpolation(float temperature);
void show_fw_version_warnings();
uint8_t check_printer_version();
#ifdef PINDA_THERMISTOR
@ -358,33 +418,27 @@ float temp_compensation_pinda_thermistor_offset(float temperature_pinda);
void serialecho_temperatures();
bool check_commands();
void uvlo_();
void uvlo_tiny();
void recover_print(uint8_t automatic);
void setup_uvlo_interrupt();
#if defined(TACH_1) && TACH_1 >-1
void setup_fan_interrupt();
#endif
extern bool recover_machine_state_after_power_panic();
extern void restore_print_from_eeprom(bool mbl_was_active);
extern void position_menu();
extern void print_world_coordinates();
extern void print_physical_coordinates();
extern void print_mesh_bed_leveling_table();
void save_print_file_state();
void restore_print_file_state();
void save_planner_global_state();
void refresh_print_state_in_ram();
/// Updates the feedrate multiplier when a print is saved such that
/// it is not overwritten when the print is later resumed
void refresh_saved_feedrate_multiplier_in_ram();
void clear_print_state_in_ram();
extern void stop_and_save_print_to_ram(float z_move, float e_move);
void restore_file_from_sd();
void restore_extruder_temperature_from_ram();
extern void restore_print_from_ram_and_continue(float e_move);
extern void cancel_saved_printing();
// Define some coordinates outside the clamp limits (making them invalid past the parsing stage) so
// that they can be used later for various logical checks
#define X_COORD_INVALID (X_MIN_POS-1)
#define SAVED_START_POSITION_UNSET X_COORD_INVALID
extern float saved_start_position[NUM_AXIS];
extern uint16_t saved_segment_idx;
extern bool isPartialBackupAvailable;
//estimated time to end of the print
extern uint8_t calc_percent_done();
@ -396,7 +450,7 @@ extern uint8_t calc_percent_done();
/*enum MarlinBusyState {
NOT_BUSY, // Not in a handler
IN_HANDLER, // Processing a GCode
IN_PROCESS, // Known to be blocking command input
IN_PROCESS, // Known to be blocking command input (as in G29)
PAUSED_FOR_USER, // Blocking pending any input
PAUSED_FOR_INPUT // Blocking pending text input (concept)
};*/
@ -409,7 +463,6 @@ extern uint8_t calc_percent_done();
#define KEEPALIVE_STATE(n) do { busy_state = n;} while (0)
extern void host_keepalive();
extern void host_autoreport();
//extern MarlinBusyState busy_state;
extern int8_t busy_state;
@ -420,7 +473,6 @@ extern int8_t busy_state;
#define FORCE_HIGH_POWER_END force_high_power_mode(false)
void force_high_power_mode(bool start_high_power_section);
void change_power_mode_live(uint8_t mode);
#endif //TMC2130
@ -431,22 +483,25 @@ void gcode_M114();
#if (defined(FANCHECK) && (((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1)))))
void gcode_M123();
#endif //FANCHECK and TACH_0 and TACH_1
void gcode_M701(float fastLoadLength, uint8_t mmuSlotIndex);
void gcode_M701();
#define UVLO !(PINE & (1<<4))
void proc_commands();
void M600_load_filament(const char* filament_name);
void M600_load_filament_movements(const char* filament_name);
void M600_wait_for_user();
bool M600_check_state_and_repeat(const char* filament_name);
void M600_load_filament();
void M600_load_filament_movements();
void M600_wait_for_user(float HotendTempBckp);
void M600_check_state(float nozzle_temp);
void load_filament_final_feed();
void marlin_wait_for_click();
float raise_z(float delta);
void raise_z_above(float target);
void raise_z_above(float target, bool plan=true);
extern "C" void softReset();
void stack_error();
void pullup_error(bool fromTempISR);
extern uint32_t IP_address;
#endif

View File

@ -15,7 +15,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
@ -26,11 +26,11 @@
uint8_t selectedSerialPort = 0;
#ifndef AT90USB
// this next line disables the entire HardwareSerial.cpp,
// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a UART
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
#ifdef HAS_UART
#if UART_PRESENT(SERIAL_PORT)
ring_buffer rx_buffer = { { 0 }, 0, 0 };
#endif
@ -75,7 +75,7 @@ ISR(M_USARTx_RX_vect)
#endif //DEBUG_DUMP_TO_2ND_SERIAL
}
}
#ifndef SNMM
ISR(USART1_RX_vect)
{
// Test for a framing error.
@ -97,6 +97,7 @@ ISR(USART1_RX_vect)
}
}
#endif
#endif
// Public Methods //////////////////////////////////////////////////////////////
@ -129,8 +130,10 @@ void MarlinSerial::begin(long baud)
sbi(M_UCSRxB, M_RXENx);
sbi(M_UCSRxB, M_TXENx);
sbi(M_UCSRxB, M_RXCIEx);
#ifndef SNMM
if (selectedSerialPort == 1) { //set up also the second serial port
if (selectedSerialPort == 1) { //set up also the second serial port
if (useU2X) {
UCSR1A = 1 << U2X1;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
@ -142,11 +145,12 @@ void MarlinSerial::begin(long baud)
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
UBRR1H = baud_setting >> 8;
UBRR1L = baud_setting;
sbi(UCSR1B, RXEN1);
sbi(UCSR1B, TXEN1);
sbi(UCSR1B, RXCIE1);
sbi(UCSR1B, RXCIE1);
}
#endif
}
void MarlinSerial::end()
@ -155,9 +159,11 @@ void MarlinSerial::end()
cbi(M_UCSRxB, M_TXENx);
cbi(M_UCSRxB, M_RXCIEx);
#ifndef SNMM
cbi(UCSR1B, RXEN1);
cbi(UCSR1B, TXEN1);
cbi(UCSR1B, RXCIE1);
#endif
}
@ -250,7 +256,7 @@ void MarlinSerial::print(double n, int digits)
void MarlinSerial::println(void)
{
// print('\r');
print('\n');
print('\n');
}
/*void MarlinSerial::println(const String &s)
@ -311,13 +317,13 @@ void MarlinSerial::println(double n, int digits)
void MarlinSerial::printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
uint8_t i = 0;
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0) {
print('0');
return;
}
}
while (n > 0) {
buf[i++] = n % base;
@ -330,8 +336,8 @@ void MarlinSerial::printNumber(unsigned long n, uint8_t base)
'A' + buf[i - 1] - 10));
}
void MarlinSerial::printFloat(double number, uint8_t digits)
{
void MarlinSerial::printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
@ -343,7 +349,7 @@ void MarlinSerial::printFloat(double number, uint8_t digits)
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
@ -353,7 +359,7 @@ void MarlinSerial::printFloat(double number, uint8_t digits)
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
print('.');
print('.');
// Extract digits from the remainder one at a time
while (digits-- > 0)
@ -361,8 +367,8 @@ void MarlinSerial::printFloat(double number, uint8_t digits)
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
remainder -= toPrint;
}
}
// Preinstantiate Objects //////////////////////////////////////////////////////

View File

@ -23,35 +23,33 @@
#define MarlinSerial_h
#include "Marlin.h"
#if !defined(SERIAL_PORT)
#if !defined(SERIAL_PORT)
#define SERIAL_PORT 0
#endif
// The presence of the UBRRH register is used to detect a UART.
#if ((SERIAL_PORT == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
(SERIAL_PORT == 1 && defined(UBRR1H)) || \
(SERIAL_PORT == 2 && defined(UBRR2H)) || \
(SERIAL_PORT == 3 && defined(UBRR3H)))
#define HAS_UART
#endif
#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
(port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
(port == 3 && defined(UBRR3H)))
// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
// requires two levels of indirection to expand macro values properly)
#define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix)
#if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary
#define SERIAL_REGNAME(registerbase,number,suffix) _REGNAME_SHORT(registerbase, suffix)
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##suffix
#else
#define SERIAL_REGNAME(registerbase,number,suffix) _REGNAME(registerbase, number, suffix)
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
#endif
// Registers used by MarlinSerial class (these are expanded
// Registers used by MarlinSerial class (these are expanded
// depending on selected serial port
#define M_UCSRxA SERIAL_REGNAME(UCSR,SERIAL_PORT,A) // defines M_UCSRxA to be UCSRnA where n is the serial port number
#define M_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B)
#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,)
#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,)
#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,)
#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,)
#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,)
#define M_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B)
#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,)
#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,)
#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,)
#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,)
#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,)
#define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H)
#define M_UBRRxL SERIAL_REGNAME(UBRR,SERIAL_PORT,L)
#define M_RXCx SERIAL_REGNAME(RXC,SERIAL_PORT,)
@ -84,7 +82,7 @@ struct ring_buffer
int tail;
};
#ifdef HAS_UART
#if UART_PRESENT(SERIAL_PORT)
extern ring_buffer rx_buffer;
#endif
@ -97,7 +95,7 @@ class MarlinSerial //: public Stream
static int peek(void);
static int read(void);
static void flush(void);
static /*FORCE_INLINE*/ int available(void)
{
return (unsigned int)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE;
@ -124,7 +122,7 @@ class MarlinSerial //: public Stream
UDR1 = c;
}
}
static void checkRx(void)
{
if (selectedSerialPort == 0) {
@ -177,15 +175,15 @@ class MarlinSerial //: public Stream
}
}
}
private:
static void printNumber(unsigned long, uint8_t);
static void printFloat(double, uint8_t);
public:
static /*FORCE_INLINE*/ void write(const char *str)
{
while (*str)
@ -205,7 +203,7 @@ class MarlinSerial //: public Stream
write(s[i]);
}
}*/
static FORCE_INLINE void print(const char *str)
{
write(str);

9340
Firmware/Marlin_main.cpp Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,496 +0,0 @@
#include "Prusa_farm.h"
#include "macros.h"
#include "Marlin.h"
#include "cmdqueue.h"
#include "temperature.h"
#include "cardreader.h"
#include "util.h"
#include "ultralcd.h"
#include "Filament_sensor.h"
#include "language.h"
#include "lcd.h"
#include "stopwatch.h"
#ifdef PRUSA_FARM
uint8_t farm_mode = 0;
static ShortTimer NcTime;
static uint8_t farm_timer = 8;
static uint8_t status_number = 0;
static bool no_response = false;
#ifdef PRUSA_M28
#define CHUNK_SIZE 64 // bytes
#define SAFETY_MARGIN 1
bool prusa_sd_card_upload = false;
char chunk[CHUNK_SIZE+SAFETY_MARGIN];
#endif
static void prusa_statistics_err(char c);
static void prusa_stat_printerstatus(uint8_t _status);
static void prusa_stat_farm_number();
static void prusa_stat_diameter();
static void prusa_stat_temperatures();
static void prusa_stat_printinfo();
static void lcd_send_status();
#ifdef FARM_CONNECT_MESSAGE
static void proc_commands();
static void lcd_connect_printer();
#endif //FARM_CONNECT_MESSAGE
#ifdef PRUSA_M28
static void trace();
#endif
static void prusa_statistics_err(char c) {
SERIAL_ECHOPGM("{[ERR:");
SERIAL_ECHO(c);
SERIAL_ECHO(']');
prusa_stat_farm_number();
}
static void prusa_statistics_case0(uint8_t statnr) {
SERIAL_ECHO('{');
prusa_stat_printerstatus(statnr);
prusa_stat_farm_number();
prusa_stat_printinfo();
}
static void prusa_stat_printerstatus(uint8_t _status) {
SERIAL_ECHOPGM("[PRN:");
SERIAL_ECHO(_status);
SERIAL_ECHO(']');
}
static void prusa_stat_farm_number() {
SERIAL_ECHOPGM("[PFN:0]");
}
static void prusa_stat_diameter() {
SERIAL_ECHOPGM("[DIA:");
SERIAL_ECHO(eeprom_read_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM));
SERIAL_ECHO(']');
}
static void prusa_stat_temperatures() {
SERIAL_ECHOPGM("[ST0:");
SERIAL_ECHO(target_temperature[0]);
SERIAL_ECHOPGM("][STB:");
SERIAL_ECHO(target_temperature_bed);
SERIAL_ECHOPGM("][AT0:");
SERIAL_ECHO(current_temperature[0]);
SERIAL_ECHOPGM("][ATB:");
SERIAL_ECHO(current_temperature_bed);
SERIAL_ECHO(']');
}
static void prusa_stat_printinfo() {
SERIAL_ECHOPGM("[TFU:");
SERIAL_ECHO(total_filament_used);
SERIAL_ECHOPGM("][PCD:");
SERIAL_ECHO((int)card.percentDone());
SERIAL_ECHOPGM("][FEM:");
SERIAL_ECHO(feedmultiply);
SERIAL_ECHOPGM("][FNM:");
SERIAL_ECHO(card.longFilename[0] ? card.longFilename : card.filename);
SERIAL_ECHOPGM("][TIM:");
if (print_job_timer.isRunning()) {
SERIAL_ECHO(print_job_timer.duration());
}
else {
SERIAL_ECHO(0);
}
SERIAL_ECHOPGM("][FWR:");
SERIAL_ECHORPGM(FW_VERSION_STR_P());
SERIAL_ECHO(']');
prusa_stat_diameter();
}
static void lcd_send_status() {
if (farm_mode && no_response && (NcTime.expired(NC_TIME * 1000))) {
//send important status messages periodicaly
prusa_statistics(8);
NcTime.start();
#ifdef FARM_CONNECT_MESSAGE
lcd_connect_printer();
#endif //FARM_CONNECT_MESSAGE
}
}
#ifdef FARM_CONNECT_MESSAGE
static void proc_commands() {
if (buflen) {
process_commands();
if (!cmdbuffer_front_already_processed)
cmdqueue_pop_front();
cmdbuffer_front_already_processed = false;
}
}
static void lcd_connect_printer() {
lcd_update_enable(false);
lcd_clear();
int i = 0;
int t = 0;
lcd_puts_at_P(0, 0, PSTR("Connect printer to"));
lcd_puts_at_P(0, 1, PSTR("monitoring or hold"));
lcd_puts_at_P(0, 2, PSTR("the knob to continue"));
while (no_response) {
i++;
t++;
delay_keep_alive(100);
proc_commands();
if (t == 10) {
prusa_statistics(8);
t = 0;
}
if (READ(BTN_ENC)) { //if button is not pressed
i = 0;
lcd_puts_at_P(0, 3, PSTR(" "));
}
if (i != 0)
lcd_putc_at((i * 20) / (NC_BUTTON_LONG_PRESS * 10), 3, LCD_STR_SOLID_BLOCK[0]);
if (i == NC_BUTTON_LONG_PRESS * 10)
no_response = false;
}
lcd_update_enable(true);
lcd_update(2);
}
#endif //FARM_CONNECT_MESSAGE
#ifdef PRUSA_M28
static void trace() {
Sound_MakeCustom(25,440,true);
}
void serial_read_stream() {
disable_heater();
lcd_clear();
lcd_puts_P(PSTR(" Upload in progress"));
// first wait for how many bytes we will receive
uint32_t bytesToReceive;
// receive the four bytes
char bytesToReceiveBuffer[4];
for (int i=0; i<4; i++) {
int data;
while ((data = MYSERIAL.read()) == -1) {};
bytesToReceiveBuffer[i] = data;
}
// make it a uint32
memcpy(&bytesToReceive, &bytesToReceiveBuffer, 4);
// we're ready, notify the sender
MYSERIAL.write('+');
// lock in the routine
uint32_t receivedBytes = 0;
while (prusa_sd_card_upload) {
int i;
for (i=0; i<CHUNK_SIZE; i++) {
int data;
// check if we're not done
if (receivedBytes == bytesToReceive) {
break;
}
// read the next byte
while ((data = MYSERIAL.read()) == -1) {};
receivedBytes++;
// save it to the chunk
chunk[i] = data;
}
// write the chunk to SD
card.write_command_no_newline(&chunk[0]);
// notify the sender we're ready for more data
MYSERIAL.write('+');
// for safety
manage_heater();
// check if we're done
if(receivedBytes == bytesToReceive) {
trace(); // beep
card.closefile();
prusa_sd_card_upload = false;
SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED);
}
}
}
#endif //PRUSA_M28
void prusa_statistics(uint8_t _message) {
const uint8_t _fil_nr = 0;
if (!farm_mode)
return;
switch (_message) {
case 0: // default message
if (busy_state == PAUSED_FOR_USER) {
prusa_statistics_case0(15);
}
else if (printingIsPaused()) {
prusa_statistics_case0(14);
}
else if (IS_SD_PRINTING || (eFilamentAction != FilamentAction::None)) {
prusa_statistics_case0(4);
}
else {
SERIAL_ECHO('{');
prusa_stat_printerstatus(1);
prusa_stat_farm_number();
prusa_stat_diameter();
status_number = 1;
}
break;
case 1: // 1 heating
SERIAL_ECHO('{');
prusa_stat_printerstatus(2);
prusa_stat_farm_number();
status_number = 2;
farm_timer = 1;
break;
case 2: // heating done
SERIAL_ECHO('{');
prusa_stat_printerstatus(3);
prusa_stat_farm_number();
SERIAL_ECHOLN('}');
status_number = 3;
farm_timer = 1;
if (IS_SD_PRINTING || (eFilamentAction != FilamentAction::None)) {
SERIAL_ECHO('{');
prusa_stat_printerstatus(4);
prusa_stat_farm_number();
status_number = 4;
}
else {
SERIAL_ECHO('{');
prusa_stat_printerstatus(3);
prusa_stat_farm_number();
status_number = 3;
}
farm_timer = 1;
break;
case 3: // filament change
// must do a return here to prevent doing SERIAL_ECHOLN("}") at the very end of this function
// saved a considerable amount of FLASH
return;
break;
case 4: // print succesfull
SERIAL_ECHOPGM("{[RES:1][FIL:");
MYSERIAL.print(int(_fil_nr));
SERIAL_ECHO(']');
prusa_stat_printerstatus(status_number);
prusa_stat_farm_number();
farm_timer = 2;
break;
case 5: // print not succesfull
SERIAL_ECHOPGM("{[RES:0][FIL:");
MYSERIAL.print(int(_fil_nr));
SERIAL_ECHO(']');
prusa_stat_printerstatus(status_number);
prusa_stat_farm_number();
farm_timer = 2;
break;
case 6: // print done
SERIAL_ECHOPGM("{[PRN:8]");
prusa_stat_farm_number();
status_number = 8;
farm_timer = 2;
break;
case 7: // print done - stopped
SERIAL_ECHOPGM("{[PRN:9]");
prusa_stat_farm_number();
status_number = 9;
farm_timer = 2;
break;
case 8: // printer started
SERIAL_ECHOPGM("{[PRN:0]");
prusa_stat_farm_number();
status_number = 0;
farm_timer = 2;
break;
case 20: // echo farm no
SERIAL_ECHO('{');
prusa_stat_printerstatus(status_number);
prusa_stat_farm_number();
farm_timer = 4;
break;
case 21: // temperatures
SERIAL_ECHO('{');
prusa_stat_temperatures();
prusa_stat_farm_number();
prusa_stat_printerstatus(status_number);
break;
case 22: // waiting for filament change
SERIAL_ECHOPGM("{[PRN:5]");
prusa_stat_farm_number();
status_number = 5;
break;
case 90: // Error - Thermal Runaway
prusa_statistics_err('1');
break;
case 91: // Error - Thermal Runaway Preheat
prusa_statistics_err('2');
break;
case 92: // Error - Min temp
prusa_statistics_err('3');
break;
case 93: // Error - Max temp
prusa_statistics_err('4');
break;
case 99: // heartbeat
SERIAL_ECHOPGM("{[PRN:99]");
prusa_stat_temperatures();
prusa_stat_farm_number();
break;
}
SERIAL_ECHOLN('}');
}
void prusa_statistics_update_from_status_screen() {
if (farm_mode) {
farm_timer--;
if (farm_timer < 1) {
farm_timer = 10;
prusa_statistics(0);
}
switch (farm_timer) {
case 8:
prusa_statistics(21);
if(eFilamentAction != FilamentAction::None)
prusa_statistics(22);
break;
case 5:
if (IS_SD_PRINTING)
prusa_statistics(20);
break;
}
}
}
void prusa_statistics_update_from_lcd_update() {
lcd_send_status();
}
void farm_mode_init() {
farm_mode = eeprom_init_default_byte((uint8_t*)EEPROM_FARM_MODE, 0);
if (farm_mode) {
no_response = true; //we need confirmation by recieving PRUSA thx
prusa_statistics(8);
#ifdef HAS_SECOND_SERIAL_PORT
selectedSerialPort = 1;
#endif //HAS_SECOND_SERIAL_PORT
MYSERIAL.begin(BAUDRATE);
#ifdef FILAMENT_SENSOR
//to be converted to Filament_sensor.h...
//disabled filament autoload (PFW360)
fsensor.setAutoLoadEnabled(false);
#endif //FILAMENT_SENSOR
// ~ FanCheck -> on
eeprom_update_byte_notify((uint8_t*)EEPROM_FAN_CHECK_ENABLED, true);
}
}
bool farm_prusa_code_seen() {
if (!farm_mode)
return false;
if (code_seen_P(PSTR("PRN"))) { // PRUSA PRN
printf_P(_N("%u"), status_number);
}
else if (code_seen_P(PSTR("thx"))) { // PRUSA thx
no_response = false;
}
#ifdef PRUSA_M28
else if (code_seen_P(PSTR("M28"))) { // PRUSA M28
trace();
prusa_sd_card_upload = true;
card.openFileWrite(strchr_pointer+4);
}
#endif //PRUSA_M28
else if (code_seen_P(PSTR("fv"))) { // PRUSA fv
// get file version
#ifdef SDSUPPORT
card.openFileReadFilteredGcode(strchr_pointer + 3, true);
while (true) {
uint16_t readByte = card.getFilteredGcodeChar();
MYSERIAL.write(readByte);
if (readByte == '\n') {
break;
}
}
card.closefile();
#endif // SDSUPPORT
}
else {
return false;
}
return true;
}
void farm_gcode_g98() {
farm_mode = 1;
eeprom_update_byte_notify((unsigned char *)EEPROM_FARM_MODE, farm_mode);
SilentModeMenu = SILENT_MODE_OFF;
eeprom_update_byte_notify((unsigned char *)EEPROM_SILENT, SilentModeMenu);
fCheckModeInit(); // alternatively invoke printer reset
}
void farm_gcode_g99() {
farm_disable();
lcd_update(2);
fCheckModeInit(); // alternatively invoke printer reset
}
void farm_disable() {
farm_mode = false;
eeprom_update_byte_notify((uint8_t*)EEPROM_FARM_MODE, farm_mode);
}
#else //PRUSA_FARM
void prusa_statistics(_UNUSED uint8_t message) {
}
void prusa_statistics_update_from_status_screen() {
}
void prusa_statistics_update_from_lcd_update() {
}
void farm_mode_init() {
}
bool farm_prusa_code_seen() {
return false;
}
void farm_gcode_g98() {
}
void farm_gcode_g99() {
}
void farm_disable() {
}
#endif //PRUSA_FARM

View File

@ -1,32 +0,0 @@
#pragma once
#include <inttypes.h>
#include "config.h"
#define FARM_PREHEAT_HOTEND_TEMP 250
#define FARM_PREHEAT_HPB_TEMP 80
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
#define NC_TIME 10 //time in s for periodic important status messages sending which needs reponse from monitoring
#define NC_BUTTON_LONG_PRESS 15 //time in s
//#define FARM_CONNECT_MESSAGE
#ifdef PRUSA_FARM
extern uint8_t farm_mode;
#else
#define farm_mode 0
#endif
#ifdef PRUSA_M28
extern bool prusa_sd_card_upload;
extern void serial_read_stream();
#endif
extern void prusa_statistics(uint8_t _message);
extern void prusa_statistics_update_from_status_screen();
extern void prusa_statistics_update_from_lcd_update();
extern void farm_mode_init();
extern bool farm_prusa_code_seen();
extern void farm_gcode_g98();
extern void farm_gcode_g99();
extern void farm_disable();

View File

@ -205,14 +205,14 @@ uint32_t Sd2Card::cardSize() {
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectHigh() {
WRITE(SDSS, 1);
digitalWrite(chipSelectPin_, HIGH);
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectLow() {
#ifndef SOFTWARE_SPI
spiInit(spiRate_);
#endif // SOFTWARE_SPI
WRITE(SDSS, 0);
digitalWrite(chipSelectPin_, LOW);
}
//------------------------------------------------------------------------------
/** Erase a range of blocks.
@ -283,25 +283,26 @@ bool Sd2Card::eraseSingleBlockEnable() {
* the value zero, false, is returned for failure. The reason for failure
* can be determined by calling errorCode() and errorData().
*/
bool Sd2Card::init(uint8_t sckRateID) {
bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
errorCode_ = type_ = 0;
chipSelectPin_ = chipSelectPin;
// 16-bit init start time allows over a minute
uint16_t t0 = (uint16_t)_millis();
uint32_t arg;
// set pin modes
pinMode(chipSelectPin_, OUTPUT);
chipSelectHigh();
SET_OUTPUT(SDSS);
SET_INPUT(MISO);
SET_OUTPUT(MOSI);
SET_OUTPUT(SCK);
pinMode(SPI_MISO_PIN, INPUT);
pinMode(SPI_MOSI_PIN, OUTPUT);
pinMode(SPI_SCK_PIN, OUTPUT);
#ifndef SOFTWARE_SPI
// SS must be in output mode even it is not chip select
SET_OUTPUT(SS);
pinMode(SS_PIN, OUTPUT);
// set SS high - may be chip select for another SPI device
#if SET_SPI_SS_HIGH
WRITE(SS, 1);
digitalWrite(SS_PIN, HIGH);
#endif // SET_SPI_SS_HIGH
// set SCK rate for initialization commands
spiRate_ = SPI_SD_INIT_RATE;
@ -311,16 +312,13 @@ bool Sd2Card::init(uint8_t sckRateID) {
// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
WRITE(MISO, 1); // temporarily enable the MISO line pullup
// command to go idle in SPI mode
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
if (((uint16_t)_millis() - t0) > SD_INIT_TIMEOUT) {
WRITE(MISO, 0); // disable the MISO line pullup
error(SD_CARD_ERROR_CMD0);
goto fail;
}
}
WRITE(MISO, 0); // disable the MISO line pullup
// send 0xFF until 0xFF received to give card some clock cycles
t0 = (uint16_t)_millis();
@ -767,7 +765,7 @@ uint8_t Sd2Card::waitStartBlock(void) {
return false;
}
// Toshiba FlashAir support, copied from
// Toshiba FlashAir support, copied from
// https://flashair-developers.com/en/documents/tutorials/arduino/
// However, the official website was closed in September 2019.
// There is an archived website (written in Japanese).
@ -783,7 +781,7 @@ uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) {
error(SD_CARD_ERROR_CMD48);
goto fail;
}
// wait for start block token.
if (!waitStartBlock()) {
goto fail;
@ -793,7 +791,7 @@ uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) {
for (i = 0; i < count; ++i) {
dst[i] = spiRec();
}
// skip dummy bytes and 16-bit crc.
for (; i < 514; ++i) {
spiRec();
@ -815,19 +813,19 @@ uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) {
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func,
uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func,
uint32_t addr, uint16_t count, uint8_t* dst) {
uint32_t offset = addr & 0x1FF;
if (offset + count > 512) count = 512 - offset;
if (count == 0) return true;
uint32_t arg =
(((uint32_t)mio & 0x1) << 31) |
uint32_t arg =
(((uint32_t)mio & 0x1) << 31) |
(mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
((addr & 0x1FFFF) << 9) |
((count - 1) & 0x1FF);
return readExt(arg, dst, count);
}

View File

@ -28,6 +28,7 @@
* \brief Sd2Card class for V2 SD/SDHC cards
*/
#include "SdFatConfig.h"
#include "Sd2PinMap.h"
#include "SdInfo.h"
//------------------------------------------------------------------------------
// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
@ -132,7 +133,22 @@ uint8_t const SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
// SPI pin definitions - do not edit here - change in SdFatConfig.h
//
#ifdef SOFTWARE_SPI
#ifndef SOFTWARE_SPI
// hardware pin defs
/** The default chip select pin for the SD card is SS. */
uint8_t const SD_CHIP_SELECT_PIN = SS_PIN;
// The following three pins must not be redefined for hardware SPI.
/** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = MOSI_PIN;
/** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = MISO_PIN;
/** SPI Clock pin */
uint8_t const SPI_SCK_PIN = SCK_PIN;
#else // SOFTWARE_SPI
/** SPI chip select pin */
uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
/** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN;
/** SPI Master In Slave Out pin */
@ -160,21 +176,22 @@ class Sd2Card {
/**
* \return error code for last error. See Sd2Card.h for a list of error codes.
*/
uint8_t errorCode() const {return errorCode_;}
int errorCode() const {return errorCode_;}
/** \return error data for last error. */
uint8_t errorData() const {return status_;}
int errorData() const {return status_;}
/**
* Initialize an SD flash memory card with default clock rate and chip
* select pin. See sd2Card::init(uint8_t sckRateID).
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
*
* \return true for success or false for failure.
*/
bool init(uint8_t sckRateID = SPI_FULL_SPEED);
bool init(uint8_t sckRateID = SPI_FULL_SPEED,
uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
bool readBlock(uint32_t block, uint8_t* dst);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
@ -215,6 +232,7 @@ class Sd2Card {
private:
//----------------------------------------------------------------------------
uint8_t chipSelectPin_;
uint8_t errorCode_;
uint8_t spiRate_;
uint8_t status_;
@ -243,4 +261,4 @@ class Sd2Card {
#endif // Sd2Card_h
#endif
#endif

364
Firmware/Sd2PinMap.h Normal file
View File

@ -0,0 +1,364 @@
/* Arduino SdFat Library
* Copyright (C) 2010 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
// Warning this file was generated by a program.
#include "Marlin.h"
#ifdef SDSUPPORT
#ifndef Sd2PinMap_h
#define Sd2PinMap_h
#include <avr/io.h>
//------------------------------------------------------------------------------
/** struct for mapping digital pins */
struct pin_map_t {
volatile uint8_t* ddr;
volatile uint8_t* pin;
volatile uint8_t* port;
uint8_t bit;
};
//------------------------------------------------------------------------------
#if defined(__AVR_ATmega1280__)\
|| defined(__AVR_ATmega2560__)
// Mega
#undef MOSI_PIN
#undef MISO_PIN
// SPI port
uint8_t const SS_PIN = 53; // B0
uint8_t const MOSI_PIN = 51; // B2
uint8_t const MISO_PIN = 50; // B3
uint8_t const SCK_PIN = 52; // B1
static const pin_map_t digitalPinMap[] = {
{&DDRE, &PINE, &PORTE, 0}, // E0 0
{&DDRE, &PINE, &PORTE, 1}, // E1 1
{&DDRE, &PINE, &PORTE, 4}, // E4 2
{&DDRE, &PINE, &PORTE, 5}, // E5 3
{&DDRG, &PING, &PORTG, 5}, // G5 4
{&DDRE, &PINE, &PORTE, 3}, // E3 5
{&DDRH, &PINH, &PORTH, 3}, // H3 6
{&DDRH, &PINH, &PORTH, 4}, // H4 7
{&DDRH, &PINH, &PORTH, 5}, // H5 8
{&DDRH, &PINH, &PORTH, 6}, // H6 9
{&DDRB, &PINB, &PORTB, 4}, // B4 10
{&DDRB, &PINB, &PORTB, 5}, // B5 11
{&DDRB, &PINB, &PORTB, 6}, // B6 12
{&DDRB, &PINB, &PORTB, 7}, // B7 13
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
{&DDRH, &PINH, &PORTH, 1}, // H1 16
{&DDRH, &PINH, &PORTH, 0}, // H0 17
{&DDRD, &PIND, &PORTD, 3}, // D3 18
{&DDRD, &PIND, &PORTD, 2}, // D2 19
{&DDRD, &PIND, &PORTD, 1}, // D1 20
{&DDRD, &PIND, &PORTD, 0}, // D0 21
{&DDRA, &PINA, &PORTA, 0}, // A0 22
{&DDRA, &PINA, &PORTA, 1}, // A1 23
{&DDRA, &PINA, &PORTA, 2}, // A2 24
{&DDRA, &PINA, &PORTA, 3}, // A3 25
{&DDRA, &PINA, &PORTA, 4}, // A4 26
{&DDRA, &PINA, &PORTA, 5}, // A5 27
{&DDRA, &PINA, &PORTA, 6}, // A6 28
{&DDRA, &PINA, &PORTA, 7}, // A7 29
{&DDRC, &PINC, &PORTC, 7}, // C7 30
{&DDRC, &PINC, &PORTC, 6}, // C6 31
{&DDRC, &PINC, &PORTC, 5}, // C5 32
{&DDRC, &PINC, &PORTC, 4}, // C4 33
{&DDRC, &PINC, &PORTC, 3}, // C3 34
{&DDRC, &PINC, &PORTC, 2}, // C2 35
{&DDRC, &PINC, &PORTC, 1}, // C1 36
{&DDRC, &PINC, &PORTC, 0}, // C0 37
{&DDRD, &PIND, &PORTD, 7}, // D7 38
{&DDRG, &PING, &PORTG, 2}, // G2 39
{&DDRG, &PING, &PORTG, 1}, // G1 40
{&DDRG, &PING, &PORTG, 0}, // G0 41
{&DDRL, &PINL, &PORTL, 7}, // L7 42
{&DDRL, &PINL, &PORTL, 6}, // L6 43
{&DDRL, &PINL, &PORTL, 5}, // L5 44
{&DDRL, &PINL, &PORTL, 4}, // L4 45
{&DDRL, &PINL, &PORTL, 3}, // L3 46
{&DDRL, &PINL, &PORTL, 2}, // L2 47
{&DDRL, &PINL, &PORTL, 1}, // L1 48
{&DDRL, &PINL, &PORTL, 0}, // L0 49
{&DDRB, &PINB, &PORTB, 3}, // B3 50
{&DDRB, &PINB, &PORTB, 2}, // B2 51
{&DDRB, &PINB, &PORTB, 1}, // B1 52
{&DDRB, &PINB, &PORTB, 0}, // B0 53
{&DDRF, &PINF, &PORTF, 0}, // F0 54
{&DDRF, &PINF, &PORTF, 1}, // F1 55
{&DDRF, &PINF, &PORTF, 2}, // F2 56
{&DDRF, &PINF, &PORTF, 3}, // F3 57
{&DDRF, &PINF, &PORTF, 4}, // F4 58
{&DDRF, &PINF, &PORTF, 5}, // F5 59
{&DDRF, &PINF, &PORTF, 6}, // F6 60
{&DDRF, &PINF, &PORTF, 7}, // F7 61
{&DDRK, &PINK, &PORTK, 0}, // K0 62
{&DDRK, &PINK, &PORTK, 1}, // K1 63
{&DDRK, &PINK, &PORTK, 2}, // K2 64
{&DDRK, &PINK, &PORTK, 3}, // K3 65
{&DDRK, &PINK, &PORTK, 4}, // K4 66
{&DDRK, &PINK, &PORTK, 5}, // K5 67
{&DDRK, &PINK, &PORTK, 6}, // K6 68
{&DDRK, &PINK, &PORTK, 7} // K7 69
};
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega644P__)\
|| defined(__AVR_ATmega644__)\
|| defined(__AVR_ATmega1284P__)
// Sanguino
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 17; // C1
uint8_t const SCL_PIN = 18; // C2
// SPI port
uint8_t const SS_PIN = 4; // B4
uint8_t const MOSI_PIN = 5; // B5
uint8_t const MISO_PIN = 6; // B6
uint8_t const SCK_PIN = 7; // B7
static const pin_map_t digitalPinMap[] = {
{&DDRB, &PINB, &PORTB, 0}, // B0 0
{&DDRB, &PINB, &PORTB, 1}, // B1 1
{&DDRB, &PINB, &PORTB, 2}, // B2 2
{&DDRB, &PINB, &PORTB, 3}, // B3 3
{&DDRB, &PINB, &PORTB, 4}, // B4 4
{&DDRB, &PINB, &PORTB, 5}, // B5 5
{&DDRB, &PINB, &PORTB, 6}, // B6 6
{&DDRB, &PINB, &PORTB, 7}, // B7 7
{&DDRD, &PIND, &PORTD, 0}, // D0 8
{&DDRD, &PIND, &PORTD, 1}, // D1 9
{&DDRD, &PIND, &PORTD, 2}, // D2 10
{&DDRD, &PIND, &PORTD, 3}, // D3 11
{&DDRD, &PIND, &PORTD, 4}, // D4 12
{&DDRD, &PIND, &PORTD, 5}, // D5 13
{&DDRD, &PIND, &PORTD, 6}, // D6 14
{&DDRD, &PIND, &PORTD, 7}, // D7 15
{&DDRC, &PINC, &PORTC, 0}, // C0 16
{&DDRC, &PINC, &PORTC, 1}, // C1 17
{&DDRC, &PINC, &PORTC, 2}, // C2 18
{&DDRC, &PINC, &PORTC, 3}, // C3 19
{&DDRC, &PINC, &PORTC, 4}, // C4 20
{&DDRC, &PINC, &PORTC, 5}, // C5 21
{&DDRC, &PINC, &PORTC, 6}, // C6 22
{&DDRC, &PINC, &PORTC, 7}, // C7 23
{&DDRA, &PINA, &PORTA, 7}, // A7 24
{&DDRA, &PINA, &PORTA, 6}, // A6 25
{&DDRA, &PINA, &PORTA, 5}, // A5 26
{&DDRA, &PINA, &PORTA, 4}, // A4 27
{&DDRA, &PINA, &PORTA, 3}, // A3 28
{&DDRA, &PINA, &PORTA, 2}, // A2 29
{&DDRA, &PINA, &PORTA, 1}, // A1 30
{&DDRA, &PINA, &PORTA, 0} // A0 31
};
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega32U4__)
// Teensy 2.0
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 6; // D1
uint8_t const SCL_PIN = 5; // D0
// SPI port
uint8_t const SS_PIN = 0; // B0
uint8_t const MOSI_PIN = 2; // B2
uint8_t const MISO_PIN = 3; // B3
uint8_t const SCK_PIN = 1; // B1
static const pin_map_t digitalPinMap[] = {
{&DDRB, &PINB, &PORTB, 0}, // B0 0
{&DDRB, &PINB, &PORTB, 1}, // B1 1
{&DDRB, &PINB, &PORTB, 2}, // B2 2
{&DDRB, &PINB, &PORTB, 3}, // B3 3
{&DDRB, &PINB, &PORTB, 7}, // B7 4
{&DDRD, &PIND, &PORTD, 0}, // D0 5
{&DDRD, &PIND, &PORTD, 1}, // D1 6
{&DDRD, &PIND, &PORTD, 2}, // D2 7
{&DDRD, &PIND, &PORTD, 3}, // D3 8
{&DDRC, &PINC, &PORTC, 6}, // C6 9
{&DDRC, &PINC, &PORTC, 7}, // C7 10
{&DDRD, &PIND, &PORTD, 6}, // D6 11
{&DDRD, &PIND, &PORTD, 7}, // D7 12
{&DDRB, &PINB, &PORTB, 4}, // B4 13
{&DDRB, &PINB, &PORTB, 5}, // B5 14
{&DDRB, &PINB, &PORTB, 6}, // B6 15
{&DDRF, &PINF, &PORTF, 7}, // F7 16
{&DDRF, &PINF, &PORTF, 6}, // F6 17
{&DDRF, &PINF, &PORTF, 5}, // F5 18
{&DDRF, &PINF, &PORTF, 4}, // F4 19
{&DDRF, &PINF, &PORTF, 1}, // F1 20
{&DDRF, &PINF, &PORTF, 0}, // F0 21
{&DDRD, &PIND, &PORTD, 4}, // D4 22
{&DDRD, &PIND, &PORTD, 5}, // D5 23
{&DDRE, &PINE, &PORTE, 6} // E6 24
};
//------------------------------------------------------------------------------
#elif defined(__AVR_AT90USB646__)\
|| defined(__AVR_AT90USB1286__)
// Teensy++ 1.0 & 2.0
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 1; // D1
uint8_t const SCL_PIN = 0; // D0
// SPI port
uint8_t const SS_PIN = 20; // B0
uint8_t const MOSI_PIN = 22; // B2
uint8_t const MISO_PIN = 23; // B3
uint8_t const SCK_PIN = 21; // B1
static const pin_map_t digitalPinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRE, &PINE, &PORTE, 0}, // E0 8
{&DDRE, &PINE, &PORTE, 1}, // E1 9
{&DDRC, &PINC, &PORTC, 0}, // C0 10
{&DDRC, &PINC, &PORTC, 1}, // C1 11
{&DDRC, &PINC, &PORTC, 2}, // C2 12
{&DDRC, &PINC, &PORTC, 3}, // C3 13
{&DDRC, &PINC, &PORTC, 4}, // C4 14
{&DDRC, &PINC, &PORTC, 5}, // C5 15
{&DDRC, &PINC, &PORTC, 6}, // C6 16
{&DDRC, &PINC, &PORTC, 7}, // C7 17
{&DDRE, &PINE, &PORTE, 6}, // E6 18
{&DDRE, &PINE, &PORTE, 7}, // E7 19
{&DDRB, &PINB, &PORTB, 0}, // B0 20
{&DDRB, &PINB, &PORTB, 1}, // B1 21
{&DDRB, &PINB, &PORTB, 2}, // B2 22
{&DDRB, &PINB, &PORTB, 3}, // B3 23
{&DDRB, &PINB, &PORTB, 4}, // B4 24
{&DDRB, &PINB, &PORTB, 5}, // B5 25
{&DDRB, &PINB, &PORTB, 6}, // B6 26
{&DDRB, &PINB, &PORTB, 7}, // B7 27
{&DDRA, &PINA, &PORTA, 0}, // A0 28
{&DDRA, &PINA, &PORTA, 1}, // A1 29
{&DDRA, &PINA, &PORTA, 2}, // A2 30
{&DDRA, &PINA, &PORTA, 3}, // A3 31
{&DDRA, &PINA, &PORTA, 4}, // A4 32
{&DDRA, &PINA, &PORTA, 5}, // A5 33
{&DDRA, &PINA, &PORTA, 6}, // A6 34
{&DDRA, &PINA, &PORTA, 7}, // A7 35
{&DDRE, &PINE, &PORTE, 4}, // E4 36
{&DDRE, &PINE, &PORTE, 5}, // E5 37
{&DDRF, &PINF, &PORTF, 0}, // F0 38
{&DDRF, &PINF, &PORTF, 1}, // F1 39
{&DDRF, &PINF, &PORTF, 2}, // F2 40
{&DDRF, &PINF, &PORTF, 3}, // F3 41
{&DDRF, &PINF, &PORTF, 4}, // F4 42
{&DDRF, &PINF, &PORTF, 5}, // F5 43
{&DDRF, &PINF, &PORTF, 6}, // F6 44
{&DDRF, &PINF, &PORTF, 7} // F7 45
};
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega168__)\
||defined(__AVR_ATmega168P__)\
||defined(__AVR_ATmega328P__)
// 168 and 328 Arduinos
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 18; // C4
uint8_t const SCL_PIN = 19; // C5
// SPI port
uint8_t const SS_PIN = 10; // B2
uint8_t const MOSI_PIN = 11; // B3
uint8_t const MISO_PIN = 12; // B4
uint8_t const SCK_PIN = 13; // B5
static const pin_map_t digitalPinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRB, &PINB, &PORTB, 0}, // B0 8
{&DDRB, &PINB, &PORTB, 1}, // B1 9
{&DDRB, &PINB, &PORTB, 2}, // B2 10
{&DDRB, &PINB, &PORTB, 3}, // B3 11
{&DDRB, &PINB, &PORTB, 4}, // B4 12
{&DDRB, &PINB, &PORTB, 5}, // B5 13
{&DDRC, &PINC, &PORTC, 0}, // C0 14
{&DDRC, &PINC, &PORTC, 1}, // C1 15
{&DDRC, &PINC, &PORTC, 2}, // C2 16
{&DDRC, &PINC, &PORTC, 3}, // C3 17
{&DDRC, &PINC, &PORTC, 4}, // C4 18
{&DDRC, &PINC, &PORTC, 5} // C5 19
};
#else // defined(__AVR_ATmega1280__)
#error unknown chip
#endif // defined(__AVR_ATmega1280__)
//------------------------------------------------------------------------------
static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
uint8_t badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant")));
static inline __attribute__((always_inline))
bool getPinMode(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
} else {
return badPinNumber();
}
}
static inline __attribute__((always_inline))
void setPinMode(uint8_t pin, uint8_t mode) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
if (mode) {
*digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
} else {
*digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
}
} else {
badPinNumber();
}
}
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
} else {
return badPinNumber();
}
}
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, uint8_t value) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
if (value) {
*digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
} else {
*digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
}
} else {
badPinNumber();
}
}
#endif // Sd2PinMap_h
#endif

View File

@ -1015,7 +1015,7 @@ void SdBaseFile::printFatTime( uint16_t fatTime) {
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::printName() {
char name[FILENAME_LENGTH];
char name[13];
if (!getFilename(name)) return false;
MYSERIAL.print(name);
return true;
@ -1115,7 +1115,7 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
int16_t n;
// if not a directory file or miss-positioned return an error
if (!isDir() || (0X1F & curPosition_)) return -1;
//If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly.
if (longFilename != NULL)
{

View File

@ -281,7 +281,7 @@ class SdBaseFile {
static void printFatDate(uint16_t fatDate);
static void printFatTime( uint16_t fatTime);
bool printName();
protected:
protected:
int16_t read();
int16_t read(void* buf, uint16_t nbyte);
public:

View File

@ -468,29 +468,29 @@ uint32_t const FAT32MASK = 0X0FFFFFFF;
* \brief FAT short directory entry
*
* Short means short 8.3 name, not the entry size.
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word):
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*
*
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
*
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* 16-bit word, bit 15 is the MSB of the 16-bit word).
*
*
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
*
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
*
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
*
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
struct directoryEntry {
@ -548,7 +548,7 @@ struct directoryEntry {
*
* directoryVFATEntries are found in the same list as normal directoryEntry.
* But have the attribute field set to DIR_ATT_LONG_NAME.
*
*
* Long filenames are saved in multiple directoryVFATEntries.
* Each entry containing 13 UTF-16 characters.
*/

View File

@ -45,7 +45,7 @@ int SdFatUtil::FreeRam() {
#endif // __arm
void SdFatUtil::set_stack_guard()
{
{
uint32_t *stack_guard;
stack_guard = (uint32_t*)(&__bss_end + STACK_GUARD_MARGIN);

View File

@ -87,7 +87,7 @@ int16_t SdFile::readFilteredGcode(){
// It may seem unreasonable to copy the variable into a local one and copy it back at the end of this method,
// but there is an important point of view: the compiler is unsure whether it can optimize the reads/writes
// to gfReadPtr within this method, because it is a class member variable.
// to gfReadPtr within this method, because it is a class member variable.
// The compiler cannot see, if omitting read/write won't have any incorrect side-effects to the rest of the whole FW.
// So this trick explicitly states, that rdPtr is a local variable limited to the scope of this method,
// therefore the compiler can omit read/write to it (keep it in registers!) as it sees fit.
@ -96,7 +96,7 @@ int16_t SdFile::readFilteredGcode(){
// the same applies to gfXBegin, codesize dropped another 100B!
const uint8_t *blockBuffBegin = gfBlockBuffBegin();
uint8_t consecutiveCommentLines = 0;
while( *rdPtr == ';' ){
for(;;){
@ -104,8 +104,8 @@ int16_t SdFile::readFilteredGcode(){
//while( *(++gfReadPtr) != '\n' ); // skip until a newline is found - suboptimal code!
// Wondering, why this "nice while cycle" is done in such a weird way using a separate find_endl() function?
// Have a look at the ASM code GCC produced!
// At first - a separate find_endl() makes the compiler understand,
// At first - a separate find_endl() makes the compiler understand,
// that I don't need to store gfReadPtr every time, I'm only interested in the final address where the '\n' was found
// - the cycle can run on CPU registers only without touching memory besides reading the character being compared.
// Not only makes the code run considerably faster, but is also 40B shorter!
@ -118,7 +118,7 @@ int16_t SdFile::readFilteredGcode(){
// 11c62: sbci r19, 0xFF ; 255
// 11c64: ld r22, Z
// 11c66: cpi r22, 0x0A ; 10
// 11c68: brne .-12 ; 0x11c5e <get_command()+0x524>
// 11c68: brne .-12 ; 0x11c5e <get_command()+0x524>
// Still, even that was suboptimal as the compiler seems not to understand the usage of ld r22, Z+ (the plus is important)
// aka automatic increment of the Z register (R30:R31 pair)
@ -153,7 +153,7 @@ emit_char:
{
gfUpdateCurrentPosition( rdPtr - start + 1 );
int16_t rv = *rdPtr++;
if( curPosition_ >= fileSize_ ){
// past the end of file
goto eof_or_fail;
@ -200,7 +200,7 @@ bool SdFile::gfComputeNextFileBlock() {
// SHR by 9 means skip the last byte and shift just 3 bytes by 1
// -> should be 8 instructions... and not the horrible loop shifting 4 bytes at once
// still need to get some work on this
gfBlock = vol_->rootDirStart() + (curPosition_ >> 9);
gfBlock = vol_->rootDirStart() + (curPosition_ >> 9);
} else {
uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
if (gfOffset == 0 && blockOfCluster == 0) {

View File

@ -35,19 +35,19 @@
*/
class SdFile : public SdBaseFile/*, public Print*/ {
// GCode filtering vars and methods - due to optimization reasons not wrapped in a separate class
// beware - this read ptr is manipulated inside just 2 methods - readFilteredGcode and gfReset
// If you even want to call gfReset from readFilteredGcode, you must make sure
// to update gfReadPtr inside readFilteredGcode from a local copy (see explanation of this trick in readFilteredGcode)
const uint8_t *gfReadPtr;
uint32_t gfBlock; // remember the current file block to be kept in cache - due to reuse of the memory, the block may fall out a must be read back
uint16_t gfOffset;
const uint8_t *gfBlockBuffBegin()const;
void gfReset();
bool gfEnsureBlock();
bool gfComputeNextFileBlock();
void gfUpdateCurrentPosition(uint16_t inc);
@ -59,7 +59,7 @@ public:
#else
void write(uint8_t b);
#endif
bool openFilteredGcode(SdBaseFile* dirFile, const char* path);
int16_t readFilteredGcode();
bool seekSetFilteredGcode(uint32_t pos);

344
Firmware/Servo.cpp Normal file
View File

@ -0,0 +1,344 @@
/*
Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
The servos are pulsed in the background using the value most recently written using the write() method
Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
The methods are:
Servo - Class for manipulating servo motors connected to Arduino pins.
attach(pin ) - Attaches a servo motor to an i/o pin.
attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
default min is 544, max is 2400
write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds)
writeMicroseconds() - Sets the servo pulse width in microseconds
read() - Gets the last written servo pulse width as an angle between 0 and 180.
readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
attached() - Returns true if there is a servo attached.
detach() - Stops an attached servos from pulsing its i/o pin.
*/
#include "Configuration.h"
#ifdef NUM_SERVOS
#include <avr/interrupt.h>
#include <Arduino.h>
#include "Servo.h"
#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
//#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
static servo_t servos[MAX_SERVOS]; // static array of servo structures
static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
uint8_t ServoCount = 0; // the total number of attached servos
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
/************ static functions common to all instances ***********************/
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
{
if( Channel[timer] < 0 )
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
else{
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
}
Channel[timer]++; // increment to the next channel
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
*OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
}
else {
// finished all channels so wait for the refresh period to expire before starting over
if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
else
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
// Interrupt handlers for Arduino
#if defined(_useTimer1)
SIGNAL (TIMER1_COMPA_vect)
{
handle_interrupts(_timer1, &TCNT1, &OCR1A);
}
#endif
#if defined(_useTimer3)
SIGNAL (TIMER3_COMPA_vect)
{
handle_interrupts(_timer3, &TCNT3, &OCR3A);
}
#endif
#if defined(_useTimer4)
SIGNAL (TIMER4_COMPA_vect)
{
handle_interrupts(_timer4, &TCNT4, &OCR4A);
}
#endif
#if defined(_useTimer5)
SIGNAL (TIMER5_COMPA_vect)
{
handle_interrupts(_timer5, &TCNT5, &OCR5A);
}
#endif
#elif defined WIRING
// Interrupt handlers for Wiring
#if defined(_useTimer1)
void Timer1Service()
{
handle_interrupts(_timer1, &TCNT1, &OCR1A);
}
#endif
#if defined(_useTimer3)
void Timer3Service()
{
handle_interrupts(_timer3, &TCNT3, &OCR3A);
}
#endif
#endif
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if(timer == _timer1) {
TCCR1A = 0; // normal counting mode
TCCR1B = _BV(CS11); // set prescaler of 8
TCNT1 = 0; // clear the timer count
#if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
TIFR |= _BV(OCF1A); // clear any pending interrupts;
TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
#else
// here if not ATmega8 or ATmega128
TIFR1 |= _BV(OCF1A); // clear any pending interrupts;
TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
#endif
#if defined(WIRING)
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
#endif
}
#endif
#if defined (_useTimer3)
if(timer == _timer3) {
TCCR3A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8
TCNT3 = 0; // clear the timer count
#if defined(__AVR_ATmega128__)
TIFR |= _BV(OCF3A); // clear any pending interrupts;
ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt
#else
TIFR3 = _BV(OCF3A); // clear any pending interrupts;
TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
#endif
#if defined(WIRING)
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
#endif
}
#endif
#if defined (_useTimer4)
if(timer == _timer4) {
TCCR4A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8
TCNT4 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
}
#endif
#if defined (_useTimer5)
if(timer == _timer5) {
TCCR5A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8
TCNT5 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt
}
#endif
}
static void finISR(timer16_Sequence_t timer)
{
//disable use of the given timer
#if defined WIRING // Wiring
if(timer == _timer1) {
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
#else
TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
#endif
timerDetach(TIMER1OUTCOMPAREA_INT);
}
else if(timer == _timer3) {
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
#else
ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
#endif
timerDetach(TIMER3OUTCOMPAREA_INT);
}
#else
//For arduino - in future: call here to a currently undefined function to reset the timer
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if( ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009
}
else
this->servoIndex = INVALID_SERVO ; // too many servos
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
if(this->servoIndex < MAX_SERVOS ) {
#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
if (pin > 0) this->pin = pin; else pin = this->pin;
#endif
pinMode( pin, OUTPUT) ; // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false)
initISR(timer);
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex ;
}
void Servo::detach()
{
servos[this->servoIndex].Pin.isActive = false;
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
if(value < MIN_PULSE_WIDTH)
{ // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if(value < 0) value = 0;
if(value > 180) value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
this->writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if( value < SERVO_MIN() ) // ensure pulse width is valid
value = SERVO_MIN();
else if( value > SERVO_MAX() )
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
uint8_t oldSREG = SREG;
cli();
servos[channel].ticks = value;
SREG = oldSREG;
}
}
int Servo::read() // return the value as degrees
{
return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if( this->servoIndex != INVALID_SERVO )
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive ;
}
#endif

135
Firmware/Servo.h Normal file
View File

@ -0,0 +1,135 @@
/*
Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
The servos are pulsed in the background using the value most recently written using the write() method
Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
The sequence used to seize timers is defined in timers.h
The methods are:
Servo - Class for manipulating servo motors connected to Arduino pins.
attach(pin ) - Attaches a servo motor to an i/o pin.
attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
default min is 544, max is 2400
write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds)
writeMicroseconds() - Sets the servo pulse width in microseconds
read() - Gets the last written servo pulse width as an angle between 0 and 180.
readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
attached() - Returns true if there is a servo attached.
detach() - Stops an attached servos from pulsing its i/o pin.
*/
#ifndef Servo_h
#define Servo_h
#include <inttypes.h>
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*
*/
// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
//#define _useTimer1
#define _useTimer3
#define _useTimer4
//typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t ;
typedef enum { _timer5, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t ;
#elif defined(__AVR_ATmega32U4__)
//#define _useTimer1
#define _useTimer3
//typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;
typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
//#define _useTimer1
//typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;
typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284P__) ||defined(__AVR_ATmega2561__)
#define _useTimer3
//#define _useTimer1
//typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ;
typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
#else // everything else
//#define _useTimer1
//typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;
typedef enum { _Nbr_16timers } timer16_Sequence_t ;
#endif
#define Servo_VERSION 2 // software version of this library
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
#define REFRESH_INTERVAL 20000 // minimum time to refresh servos in microseconds
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
#define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
#define INVALID_SERVO 255 // flag indicating an invalid servo index
typedef struct {
uint8_t nbr :6 ; // a pin number from 0 to 63
uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false
} ServoPin_t ;
typedef struct {
ServoPin_t Pin;
unsigned int ticks;
} servo_t;
class Servo
{
public:
Servo();
uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure
uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.
void detach();
void write(int value); // if value is < 200 it is treated as an angle, otherwise as pulse width in microseconds
void writeMicroseconds(int value); // Write pulse width in microseconds
int read(); // returns current pulse width as an angle between 0 and 180 degrees
int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
bool attached(); // return true if this servo is attached, otherwise false
#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
int pin; // store the hardware pin of the servo
#endif
private:
uint8_t servoIndex; // index into the channel data for this servo
int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH
int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH
};
#endif

View File

@ -1,67 +0,0 @@
#include "SpoolJoin.h"
#include "Marlin.h"
#include "eeprom.h"
#include "messages.h"
#include "language.h"
namespace SpoolJoin {
SpoolJoin spooljoin;
SpoolJoin::SpoolJoin()
: currentMMUSlot(0)
{
}
void SpoolJoin::initSpoolJoinStatus()
{
// Useful information to see during bootup
SERIAL_ECHOPGM("SpoolJoin is ");
uint8_t status = eeprom_init_default_byte((uint8_t*)EEPROM_SPOOL_JOIN, (uint8_t)EEPROM::Disabled);
if (status == (uint8_t)EEPROM::Enabled)
{
SERIAL_ECHOLNRPGM(_O(MSG_ON));
} else {
SERIAL_ECHOLNRPGM(_O(MSG_OFF));
}
}
void SpoolJoin::toggleSpoolJoin()
{
if (eeprom_read_byte((uint8_t*)EEPROM_SPOOL_JOIN) == (uint8_t)EEPROM::Disabled)
{
eeprom_update_byte_notify((uint8_t*)EEPROM_SPOOL_JOIN, (uint8_t)EEPROM::Enabled);
} else {
eeprom_update_byte_notify((uint8_t*)EEPROM_SPOOL_JOIN, (uint8_t)EEPROM::Disabled);
}
}
bool SpoolJoin::isSpoolJoinEnabled()
{
if(eeprom_read_byte((uint8_t*)EEPROM_SPOOL_JOIN) == (uint8_t)EEPROM::Enabled) {
return true;
} else {
return false;
}
}
void SpoolJoin::setSlot(uint8_t slot)
{
currentMMUSlot = slot;
}
uint8_t SpoolJoin::nextSlot()
{
SERIAL_ECHOPGM("SpoolJoin: ");
SERIAL_ECHO((int)currentMMUSlot);
if (currentMMUSlot >= MMU_FILAMENT_COUNT-1) currentMMUSlot = 0;
else currentMMUSlot++;
SERIAL_ECHOPGM(" -> ");
SERIAL_ECHOLN((int)currentMMUSlot);
return currentMMUSlot;
}
}

View File

@ -1,46 +0,0 @@
/// @file
#pragma once
#include <stdint.h>
// See documentation here: https://help.prusa3d.com/article/spooljoin-mmu2s_134252
namespace SpoolJoin {
class SpoolJoin {
public:
SpoolJoin();
enum class EEPROM : uint8_t {
Unknown, ///< SpoolJoin is unknown while printer is booting up
Enabled, ///< SpoolJoin is enabled in EEPROM
Disabled, ///< SpoolJoin is disabled in EEPROM
Empty = 0xFF ///< EEPROM has not been set before and all bits are 1 (0xFF) - either a new printer or user erased the memory
};
/// @brief Called when EEPROM is ready to be read
void initSpoolJoinStatus();
/// @brief Toggle SpoolJoin
static void toggleSpoolJoin();
/// @brief Check if SpoolJoin is enabled
/// @returns true if enabled, false if disabled
bool isSpoolJoinEnabled();
/// @brief Update the saved MMU slot number so SpoolJoin can determine the next slot to use
/// @param slot number of the slot to set
void setSlot(uint8_t slot);
/// @brief Fetch the next slot number should count from 0 to 4.
/// When filament slot 4 is depleted, the next slot should be 0.
/// @returns the next slot, ranges from 0 to 4
uint8_t nextSlot();
private:
/// @brief Currently used slot, ranges from 0 to 4
uint8_t currentMMUSlot;
};
extern SpoolJoin spooljoin;
} // namespace SpoolJoin

View File

@ -1,71 +0,0 @@
#include "Tcodes.h"
#include "SpoolJoin.h"
#include "Marlin.h"
#include "language.h"
#include "messages.h"
#include "mmu2.h"
#include "ultralcd.h"
#include <avr/pgmspace.h>
#include <stdint.h>
#include <stdio.h>
static const char duplicate_Tcode_ignored[] PROGMEM = "Duplicate T-code ignored.";
inline bool IsInvalidTCode(char *const s, uint8_t i) {
return ((s[i] < '0' || s[i] > '4') && s[i] != '?' && s[i] != 'x' && s[i] != 'c');
}
inline void TCodeInvalid() {
SERIAL_ECHOLNPGM("Invalid T code.");
}
void TCodes(char *const strchr_pointer, const uint8_t codeValue) {
uint8_t index = 1;
for ( /*nothing*/ ; strchr_pointer[index] == ' ' || strchr_pointer[index] == '\t'; index++)
;
strchr_pointer[index] = tolower(strchr_pointer[index]);
if (IsInvalidTCode(strchr_pointer, index)){
TCodeInvalid();
} else if (strchr_pointer[index] == 'x' || strchr_pointer[index] == '?'){
// load to extruder gears; if mmu is not present do nothing
if (MMU2::mmu2.Enabled()) {
MMU2::mmu2.tool_change(strchr_pointer[index], choose_menu_P(_T(MSG_SELECT_FILAMENT), MSG_FILAMENT));
}
} else if (strchr_pointer[index] == 'c'){
// load from extruder gears to nozzle (nozzle should be preheated)
if (MMU2::mmu2.Enabled()) {
MMU2::mmu2.tool_change(strchr_pointer[index], MMU2::mmu2.get_current_tool());
}
} else { // Process T0 ... T4
if (MMU2::mmu2.Enabled()) {
if (codeValue == MMU2::mmu2.get_current_tool()){
// don't execute the same T-code twice in a row
puts_P(duplicate_Tcode_ignored);
} else {
#if defined(MMU_HAS_CUTTER) && defined(MMU_ALWAYS_CUT)
if (EEPROM_MMU_CUTTER_ENABLED_always == eeprom_read_byte((uint8_t *)EEPROM_MMU_CUTTER_ENABLED)) {
MMU2::mmu2.cut_filament(codeValue);
}
#endif // defined(MMU_HAS_CUTTER) && defined(MMU_ALWAYS_CUT)
MMU2::mmu2.tool_change(codeValue);
}
} else {
SERIAL_ECHO_START;
if (codeValue >= EXTRUDERS) {
SERIAL_ECHO('T');
SERIAL_ECHOLN(codeValue + '0');
SERIAL_ECHOLNRPGM(_n("Invalid extruder")); ////MSG_INVALID_EXTRUDER
} else {
// @@TODO if (code_seen('F')) {
// next_feedrate = code_value();
// if (next_feedrate > 0.0) {
// feedrate = next_feedrate;
// }
// }
SERIAL_ECHORPGM(_n("Active Extruder: 0")); ////MSG_ACTIVE_EXTRUDER
}
}
}
}

View File

@ -1,5 +0,0 @@
/// @file
#pragma once
#include <stdint.h>
void TCodes(char * const strchr_pointer, const uint8_t codeValue);

View File

@ -6,6 +6,17 @@
#include "Timer.h"
#include "system_timer.h"
/**
* @brief construct Timer
*
* It is guaranteed, that construction is equivalent with zeroing all members.
* This property can be exploited in menu_data.
*/
template<typename T>
Timer<T>::Timer() : m_isRunning(false), m_started()
{
}
/**
* @brief Start timer
*/
@ -53,24 +64,5 @@ bool Timer<T>::expired(T msPeriod)
return expired;
}
/**
* @brief Ticks since the timer was started
*
* This function returns 0 if the timer is not started. Otherwise, it returns
* the time in milliseconds since the timer was started.
* This function is expected to handle wrap around of time register well.
* The maximum elapsed time is dictated by the template type
*/
template<typename T>
T Timer<T>::elapsed() {
return m_isRunning ? (_millis() - m_started) : 0;
}
template<typename T>
bool Timer<T>::expired_cont(T msPeriod)
{
return !m_isRunning || expired(msPeriod);
}
template class Timer<unsigned long>;
template class Timer<unsigned short>;

View File

@ -17,16 +17,11 @@ template <class T>
class Timer
{
public:
inline constexpr Timer()
: m_isRunning(false)
, m_started(0) {};
Timer();
void start();
void stop(){m_isRunning = false;}
bool running()const {return m_isRunning;}
bool expired(T msPeriod); // returns true only once after expiration, then stops running
T elapsed(); // returns the time in milliseconds since the timer was started or 0 otherwise
bool expired_cont(T msPeriod); // return true when continuosly when expired / not running
bool expired(T msPeriod);
protected:
T started()const {return m_started;}
private:

95
Firmware/adc.c Normal file
View File

@ -0,0 +1,95 @@
//adc.c
#include "adc.h"
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "pins.h"
uint8_t adc_state;
uint8_t adc_count;
uint16_t adc_values[ADC_CHAN_CNT];
uint16_t adc_sim_mask;
#ifdef ADC_CALLBACK
extern void ADC_CALLBACK(void);
#endif //ADC_CALLBACK
void adc_init(void)
{
puts_P(PSTR("adc_init"));
adc_sim_mask = 0x00;
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
ADMUX |= (1 << REFS0);
ADCSRA |= (1 << ADEN);
// ADCSRA |= (1 << ADIF) | (1 << ADSC);
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff);
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8);
adc_reset();
// adc_sim_mask = 0b0101;
// adc_sim_mask = 0b100101;
// adc_values[0] = 1023 * 16;
// adc_values[2] = 1023 * 16;
// adc_values[5] = 1002 * 16;
}
void adc_reset(void)
{
adc_state = 0;
adc_count = 0;
uint8_t i; for (i = 0; i < ADC_CHAN_CNT; i++)
if ((adc_sim_mask & (1 << i)) == 0)
adc_values[i] = 0;
}
void adc_setmux(uint8_t ch)
{
ch &= 0x0f;
if (ch & 0x08) ADCSRB |= (1 << MUX5);
else ADCSRB &= ~(1 << MUX5);
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
}
uint8_t adc_chan(uint8_t index)
{
uint8_t chan = 0;
uint16_t mask = 1;
while (mask)
{
if ((mask & ADC_CHAN_MSK) && (index-- == 0)) break;
mask <<= 1;
chan++;
}
return chan;
}
void adc_cycle(void)
{
if (adc_state & 0x80)
{
uint8_t index = adc_state & 0x0f;
if ((adc_sim_mask & (1 << index)) == 0)
adc_values[index] += ADC;
if (++index >= ADC_CHAN_CNT)
{
index = 0;
adc_count++;
if (adc_count >= ADC_OVRSAMPL)
{
#ifdef ADC_CALLBACK
ADC_CALLBACK();
#endif //ADC_CALLBACK
adc_reset();
}
}
adc_setmux(adc_chan(index));
adc_state = index;
}
else
{
ADCSRA |= (1 << ADSC); //start conversion
adc_state |= 0x80;
}
}

View File

@ -1,81 +0,0 @@
#include "adc.h"
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "pins.h"
static uint8_t adc_count; //used for oversampling
static uint8_t adc_channel_idx; //bitmask index
volatile uint8_t adc_channel; //regular index
volatile uint16_t adc_values[ADC_CHAN_CNT];
static void adc_reset();
static void adc_setmux(uint8_t ch);
void adc_init()
{
puts_P(PSTR("adc_init"));
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff); //disable digital inputs PORTF
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8); //disable digital inputs PORTK
ADMUX |= (1 << REFS0); //use AVCC as reference
//enable ADC, set prescaler/128, enable interrupt
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADIF) | (1 << ADIE);
}
static void adc_reset()
{
static const uint8_t first_channel_idx = 0;
static_assert((1 << first_channel_idx) & ADC_CHAN_MSK);
ADCSRA &= ~(1 << ADSC); //stop conversion just in case
adc_count = 0;
adc_channel = 0;
adc_channel_idx = first_channel_idx;
adc_setmux(adc_channel_idx);
memset((void*)adc_values, 0, sizeof(adc_values));
}
static void adc_setmux(uint8_t ch)
{
ch &= 0x0f;
if (ch & 0x08) ADCSRB |= (1 << MUX5);
else ADCSRB &= ~(1 << MUX5);
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
}
void adc_start_cycle() {
adc_reset();
ADCSRA |= (1 << ADSC); //start conversion
}
#ifdef ADC_CALLBACK
extern void ADC_CALLBACK();
#endif //ADC_CALLBACK
ISR(ADC_vect)
{
adc_values[adc_channel] += ADC;
if (++adc_count == ADC_OVRSAMPL)
{
// go to the next channel
if (++adc_channel == ADC_CHAN_CNT) {
#ifdef ADC_CALLBACK
ADC_CALLBACK();
#endif
return; // do not start the next measurement since there are no channels remaining
}
// find the next channel
while (++adc_channel_idx) {
if (ADC_CHAN_MSK & (1 << adc_channel_idx)) {
adc_setmux(adc_channel_idx);
adc_count = 0;
break;
}
}
}
ADCSRA |= (1 << ADSC); //start conversion
}

View File

@ -1,8 +1,15 @@
#pragma once
//adc.h
#ifndef _ADC_H
#define _ADC_H
#include <inttypes.h>
#include "config.h"
#if defined(__cplusplus)
extern "C" {
#endif //defined(__cplusplus)
/*
http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
*/
@ -15,11 +22,24 @@ http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
# error "ADC_CHAN_MSK oes not match ADC_CHAN_CNT"
#endif
#define VOLT_DIV_REF 5 //[V]
extern uint8_t adc_state;
extern uint8_t adc_count;
extern uint16_t adc_values[ADC_CHAN_CNT];
extern uint16_t adc_sim_mask;
extern volatile uint8_t adc_channel;
extern volatile uint16_t adc_values[ADC_CHAN_CNT];
extern void adc_init();
extern void adc_start_cycle(); //should be called from an atomic context only
static inline bool adc_cycle_done() { return adc_channel >= ADC_CHAN_CNT; }
extern void adc_init(void);
extern void adc_reset(void);
extern void adc_setmux(uint8_t ch);
extern uint8_t adc_chan(uint8_t index);
extern void adc_cycle(void);
#if defined(__cplusplus)
}
#endif //defined(__cplusplus)
#endif //_ADC_H

View File

@ -1,21 +1,24 @@
#pragma once
#include <stdint.h>
#include "macros.h"
#ifdef __AVR_ATmega2560__
// return the current PC (on AVRs with 22bit PC)
FORCE_INLINE __uint24 GETPC(void)
static inline void GETPC(uint32_t* v)
{
__uint24 ret;
asm (
uint8_t a, b, c;
asm
(
"rcall .\n"
"pop %A0\n"
"pop %B0\n"
"pop %C0\n"
: "=&r" (ret)
"pop %2\n"
"pop %1\n"
"pop %0\n"
: "=r" (a), "=r" (b), "=r" (c)
);
return ret;
((uint8_t*)v)[0] = a;
((uint8_t*)v)[1] = b;
((uint8_t*)v)[2] = c;
((uint8_t*)v)[3] = 0;
}
#endif

View File

@ -1,12 +1,12 @@
//backlight.cpp
#include <Arduino.h>
#include <avr/eeprom.h>
#include "backlight.h"
#include "eeprom.h"
#include "fastio.h"
#include "macros.h"
#include <avr/eeprom.h>
#include <Arduino.h>
#include "eeprom.h"
#include "pins.h"
#include "system_timer.h"
#include "fastio.h"
#include "Timer.h"
#ifdef LCD_BL_PIN
@ -14,10 +14,10 @@
#define BL_FLASH_DELAY_MS 25
bool backlightSupport = 0; //only if it's true will any of the settings be visible to the user
uint8_t backlightLevel_HIGH = 0;
uint8_t backlightLevel_LOW = 0;
int16_t backlightLevel_HIGH = 0;
int16_t backlightLevel_LOW = 0;
uint8_t backlightMode = BACKLIGHT_MODE_BRIGHT;
int16_t backlightTimer_period = LCD_BACKLIGHT_TIMEOUT;
int16_t backlightTimer_period = 10;
LongTimer backlightTimer;
static void backlightTimer_reset() //used for resetting the timer and waking the display. Triggered on user interactions.
@ -32,7 +32,7 @@ void force_bl_on(bool section_start)
if (section_start)
{
backlightMode = BACKLIGHT_MODE_BRIGHT;
if (backlightLevel_HIGH < LCD_BACKLIGHT_FORCE_ON) backlightLevel_HIGH = LCD_BACKLIGHT_FORCE_ON;
if (backlightLevel_HIGH < 30) backlightLevel_HIGH = 30;
}
else
{
@ -45,7 +45,7 @@ void force_bl_on(bool section_start)
void backlight_wake(const uint8_t flashNo)
{
if (!backlightSupport) return;
if (flashNo)
{
uint8_t backlightMode_bck = backlightMode;
@ -62,16 +62,16 @@ void backlight_wake(const uint8_t flashNo)
void backlight_save() //saves all backlight data to eeprom.
{
eeprom_update_byte_notify((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH, backlightLevel_HIGH);
eeprom_update_byte_notify((uint8_t *)EEPROM_BACKLIGHT_LEVEL_LOW, backlightLevel_LOW);
eeprom_update_byte_notify((uint8_t *)EEPROM_BACKLIGHT_MODE, backlightMode);
eeprom_update_word_notify((uint16_t *)EEPROM_BACKLIGHT_TIMEOUT, backlightTimer_period);
eeprom_update_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH, (uint8_t)backlightLevel_HIGH);
eeprom_update_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_LOW, (uint8_t)backlightLevel_LOW);
eeprom_update_byte((uint8_t *)EEPROM_BACKLIGHT_MODE, backlightMode);
eeprom_update_word((uint16_t *)EEPROM_BACKLIGHT_TIMEOUT, backlightTimer_period);
}
void backlight_update()
{
if (!backlightSupport) return;
if (backlightMode == BACKLIGHT_MODE_AUTO)
{
if (backlightTimer.expired((uint32_t)backlightTimer_period * 1000ul)) analogWrite(LCD_BL_PIN, backlightLevel_LOW);
@ -91,12 +91,20 @@ void backlight_init()
backlightSupport = !READ(LCD_BL_PIN);
if (!backlightSupport) return;
//initialize backlight
backlightMode = eeprom_init_default_byte((uint8_t *)EEPROM_BACKLIGHT_MODE, BACKLIGHT_MODE_AUTO);
backlightLevel_HIGH = eeprom_init_default_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH, LCD_BACKLIGHT_LEVEL_HIGH);
backlightLevel_LOW = eeprom_init_default_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_LOW, LCD_BACKLIGHT_LEVEL_LOW);
backlightTimer_period = eeprom_init_default_word((uint16_t *)EEPROM_BACKLIGHT_TIMEOUT, LCD_BACKLIGHT_TIMEOUT); // in seconds
//initialize backlight
backlightMode = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_MODE);
if (backlightMode == 0xFF) //set default values
{
backlightMode = BACKLIGHT_MODE_AUTO;
backlightLevel_HIGH = 130;
backlightLevel_LOW = 50;
backlightTimer_period = 10; //in seconds
backlight_save();
}
backlightLevel_HIGH = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH);
backlightLevel_LOW = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_LOW);
backlightTimer_period = eeprom_read_word((uint16_t *)EEPROM_BACKLIGHT_TIMEOUT);
SET_OUTPUT(LCD_BL_PIN);
backlightTimer_reset();
}

View File

@ -3,6 +3,8 @@
#define _BACKLIGHT_H
#include <inttypes.h>
#include "Marlin.h"
#include "pins.h"
enum Backlight_Mode
{
@ -11,8 +13,8 @@ enum Backlight_Mode
BACKLIGHT_MODE_AUTO = 2,
};
extern uint8_t backlightLevel_HIGH;
extern uint8_t backlightLevel_LOW;
extern int16_t backlightLevel_HIGH;
extern int16_t backlightLevel_LOW;
extern uint8_t backlightMode;
extern bool backlightSupport;
extern int16_t backlightTimer_period;

View File

@ -6,17 +6,19 @@
#include <stdio.h>
extern FILE _uartout;
#define uartout (&_uartout)
extern void softReset();
void bootapp_print_vars(void)
{
printf_P(PSTR("boot_src_addr =0x%08lx\n"), boot_src_addr);
printf_P(PSTR("boot_dst_addr =0x%08lx\n"), boot_dst_addr);
printf_P(PSTR("boot_copy_size =0x%04x\n"), boot_copy_size);
printf_P(PSTR("boot_reserved =0x%02x\n"), boot_reserved);
printf_P(PSTR("boot_app_flags =0x%02x\n"), boot_app_flags);
printf_P(PSTR("boot_app_magic =0x%08lx\n"), boot_app_magic);
fprintf_P(uartout, PSTR("boot_src_addr =0x%08lx\n"), boot_src_addr);
fprintf_P(uartout, PSTR("boot_dst_addr =0x%08lx\n"), boot_dst_addr);
fprintf_P(uartout, PSTR("boot_copy_size =0x%04x\n"), boot_copy_size);
fprintf_P(uartout, PSTR("boot_reserved =0x%02x\n"), boot_reserved);
fprintf_P(uartout, PSTR("boot_app_flags =0x%02x\n"), boot_app_flags);
fprintf_P(uartout, PSTR("boot_app_magic =0x%08lx\n"), boot_app_magic);
}
@ -24,11 +26,12 @@ void bootapp_ram2flash(uint16_t rptr, uint16_t fptr, uint16_t size)
{
cli();
boot_app_magic = BOOT_APP_MAGIC;
boot_app_flags |= BOOT_APP_FLG_COPY | BOOT_APP_FLG_ERASE;
boot_app_flags |= BOOT_APP_FLG_COPY;
boot_app_flags |= BOOT_APP_FLG_ERASE;
boot_copy_size = (uint16_t)size;
boot_src_addr = (uint32_t)rptr;
boot_dst_addr = (uint32_t)fptr;
// bootapp_print_vars();
bootapp_print_vars();
softReset();
}
@ -37,8 +40,7 @@ void bootapp_reboot_user0(uint8_t reserved)
cli();
boot_app_magic = BOOT_APP_MAGIC;
boot_app_flags = BOOT_APP_FLG_USER0;
boot_copy_size = 0;
boot_reserved = reserved;
// bootapp_print_vars();
bootapp_print_vars();
softReset();
}

View File

@ -17,10 +17,11 @@
#define BOOT_APP_FLG_ERASE 0x01
#define BOOT_APP_FLG_COPY 0x02
#define BOOT_APP_FLG_FLASH 0x04
#define BOOT_APP_FLG_RUN 0x08
#define BOOT_APP_FLG_USER0 0x80
#define BOOT_APP_MAGIC 0x55aa55aaUL
#define BOOT_APP_MAGIC 0x55aa55aa
#if defined(__cplusplus)

View File

@ -2,13 +2,11 @@
#include "cmdqueue.h"
#include "cardreader.h"
#include "ultralcd.h"
#include "conv2str.h"
#include "menu.h"
#include "stepper.h"
#include "temperature.h"
#include "language.h"
#include "Prusa_farm.h"
#include "power_panic.h"
#include "stopwatch.h"
#ifdef SDSUPPORT
@ -24,31 +22,33 @@ CardReader::CardReader()
filesize = 0;
sdpos = 0;
sdprinting = false;
mounted = false;
cardOK = false;
saving = false;
logging = false;
autostart_atmillis=0;
workDirDepth = 0;
file_subcall_ctr=0;
memset(workDirParents, 0, sizeof(workDirParents));
presort_flag = false;
autostart_stilltocheck=true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
lastnr=0;
//power to SD reader
#if SDPOWER > -1
SET_OUTPUT(SDPOWER);
SET_OUTPUT(SDPOWER);
WRITE(SDPOWER,HIGH);
#endif //SDPOWER
autostart_atmillis.start(); // reset timer
autostart_atmillis=_millis()+5000;
}
char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
{
char *pos=buffer;
for (uint8_t i = 0; i < 11; i++)
for (uint8_t i = 0; i < 11; i++)
{
if (p.name[i] == ' ')continue;
if (i == 8)
if (i == 8)
{
*pos++='.';
}
@ -74,7 +74,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
_incrementer() {recursionCnt++;}
~_incrementer() {recursionCnt--;}
} recursionCntIncrementer;
dir_t p;
uint8_t cnt = 0;
// Read the next entry from a directory
@ -103,10 +103,10 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
// Serial.print(path);
// Get a new directory object using the full path
// and dive recursively into it.
if (lsParams.LFN)
printf_P(PSTR("DIR_ENTER: %s \"%s\"\n"), path, longFilename[0] ? longFilename : lfilename);
SdFile dir;
if (!dir.open(parent, lfilename, O_READ)) {
//SERIAL_ECHO_START();
@ -115,7 +115,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
}
lsDive(path, dir, NULL, lsAction, lsParams);
// close() is done automatically by destructor of SdFile
if (lsParams.LFN)
puts_P(PSTR("DIR_EXIT"));
}
@ -126,15 +126,15 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
case LS_Count:
nrFiles++;
break;
case LS_SerialPrint:
createFilename(filename, p);
SERIAL_PROTOCOL(prepend);
SERIAL_PROTOCOL(filename);
MYSERIAL.write(' ');
SERIAL_PROTOCOL(p.fileSize);
if (lsParams.timestamp)
{
crmodDate = p.lastWriteDate;
@ -145,14 +145,14 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
}
printf_P(PSTR(" %#lx"), ((uint32_t)crmodDate << 16) | crmodTime);
}
if (lsParams.LFN)
printf_P(PSTR(" \"%s\""), LONGEST_FILENAME);
SERIAL_PROTOCOLLN();
manage_heater();
break;
case LS_GetFilename:
//SERIAL_ECHOPGM("File: ");
createFilename(filename, p);
@ -198,19 +198,26 @@ void CardReader::ls(ls_param params)
}
void CardReader::mount(bool doPresort/* = true*/)
void CardReader::initsd(bool doPresort/* = true*/)
{
mounted = false;
cardOK = false;
if(root.isOpen())
root.close();
#ifdef SDSLOW
if (!card.init(SPI_HALF_SPEED)
if (!card.init(SPI_HALF_SPEED,SDSS)
#if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
&& !card.init(SPI_HALF_SPEED,LCD_SDSS)
#endif
)
#else
if (!card.init(SPI_FULL_SPEED)
if (!card.init(SPI_FULL_SPEED,SDSS)
#if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
&& !card.init(SPI_FULL_SPEED,LCD_SDSS)
#endif
)
#endif
{
//if (!card.init(SPI_HALF_SPEED,SDSS))
SERIAL_ECHO_START;
SERIAL_ECHOLNRPGM(_n("SD init fail"));////MSG_SD_INIT_FAIL
}
@ -219,28 +226,40 @@ void CardReader::mount(bool doPresort/* = true*/)
SERIAL_ERROR_START;
SERIAL_ERRORLNRPGM(_n("volume.init failed"));////MSG_SD_VOL_INIT_FAIL
}
else if (!root.openRoot(&volume))
else if (!root.openRoot(&volume))
{
SERIAL_ERROR_START;
SERIAL_ERRORLNRPGM(_n("openRoot failed"));////MSG_SD_OPENROOT_FAIL
}
else
else
{
mounted = true;
cardOK = true;
SERIAL_ECHO_START;
SERIAL_ECHOLNRPGM(_n("SD card ok"));////MSG_SD_CARD_OK
}
workDir=root;
curDir=&root;
workDirDepth = 0;
if (mounted)
#ifdef SDCARD_SORT_ALPHA
if (doPresort)
presort();
#endif
/*
if(!workDir.openRoot(&volume))
{
cdroot(doPresort);
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
}
*/
}
void __attribute__((noinline)) CardReader::cdroot(bool doPresort)
void CardReader::setroot(bool doPresort)
{
workDir=root;
workDirDepth = 0;
curDir=&workDir;
#ifdef SDCARD_SORT_ALPHA
if (doPresort)
@ -252,17 +271,17 @@ void __attribute__((noinline)) CardReader::cdroot(bool doPresort)
void CardReader::release()
{
sdprinting = false;
mounted = false;
cardOK = false;
SERIAL_ECHO_START;
SERIAL_ECHOLNRPGM(_n("SD card released"));////MSG_SD_CARD_RELEASED
}
void CardReader::startFileprint()
{
if(mounted)
if(cardOK)
{
sdprinting = true;
SetPrinterState(PrinterState::IsSDPrinting); //set printer state to hide LCD menu
Stopped = false;
#ifdef SDCARD_SORT_ALPHA
//flush_presort();
#endif
@ -276,11 +295,11 @@ void CardReader::openLogFile(const char* name)
}
void CardReader::getDirName(char* name, uint8_t level)
{
{
workDirParents[level].getFilename(name);
}
uint8_t CardReader::getWorkDirDepth() {
uint16_t CardReader::getWorkDirDepth() {
return workDirDepth;
}
@ -291,10 +310,10 @@ void CardReader::getAbsFilename(char *t)
for(uint8_t i=0;i<workDirDepth;i++)
{
workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
while(*t!=0 && cnt< MAXPATHNAMELENGTH)
while(*t!=0 && cnt< MAXPATHNAMELENGTH)
{t++;cnt++;} //crawl counter forward.
}
if(cnt < MAXPATHNAMELENGTH - FILENAME_LENGTH)
if(cnt<MAXPATHNAMELENGTH-13)
file.getFilename(t);
else
t[0]=0;
@ -334,7 +353,7 @@ bool CardReader::diveSubfolder (const char *&fileName)
const char *dirname_start, *dirname_end;
if (fileName[0] == '/') // absolute path
{
cdroot(false);
setroot(false);
dirname_start = fileName + 1;
while (*dirname_start)
{
@ -384,27 +403,27 @@ static const char ofSDPrinting[] PROGMEM = "SD-PRINTING";
static const char ofWritingToFile[] PROGMEM = "Writing to file: ";
void CardReader::openFileReadFilteredGcode(const char* name, bool replace_current/* = false*/){
if(!mounted)
if(!cardOK)
return;
if(file.isOpen()){ //replacing current file by new file, or subfile call
if(!replace_current){
if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1){
// SERIAL_ERROR_START;
// SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
// SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
kill(ofKill);
kill(ofKill, 1);
return;
}
SERIAL_ECHO_START;
SERIAL_ECHORPGM(ofSubroutineCallTgt);
SERIAL_ECHO(name);
SERIAL_ECHORPGM(ofParent);
//store current filename and position
getAbsFilename(filenames[file_subcall_ctr]);
SERIAL_ECHO(filenames[file_subcall_ctr]);
SERIAL_ECHORPGM(ofPos);
SERIAL_ECHOLN(sdpos);
@ -423,11 +442,11 @@ void CardReader::openFileReadFilteredGcode(const char* name, bool replace_curren
SERIAL_ECHOLN(name);
}
sdprinting = false;
const char *fname=name;
if (!diveSubfolder(fname))
return;
if (file.openFilteredGcode(curDir, fname)) {
getfilename(0, fname);
filesize = file.fileSize();
@ -436,7 +455,7 @@ void CardReader::openFileReadFilteredGcode(const char* name, bool replace_curren
SERIAL_PROTOCOLRPGM(ofSize);////MSG_SD_SIZE
SERIAL_PROTOCOLLN(filesize);
sdpos = 0;
SERIAL_PROTOCOLLNRPGM(ofFileSelected);////MSG_SD_FILE_SELECTED
lcd_setstatuspgm(ofFileSelected);
scrollstuff = 0;
@ -449,7 +468,7 @@ void CardReader::openFileReadFilteredGcode(const char* name, bool replace_curren
void CardReader::openFileWrite(const char* name)
{
if(!mounted)
if(!cardOK)
return;
if(file.isOpen()){ //replacing current file by new file, or subfile call
#if 0
@ -460,18 +479,18 @@ void CardReader::openFileWrite(const char* name)
// SERIAL_ERROR_START;
// SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
// SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
kill(ofKill);
kill(ofKill, 1);
return;
}
SERIAL_ECHO_START;
SERIAL_ECHORPGM(ofSubroutineCallTgt);
SERIAL_ECHO(name);
SERIAL_ECHORPGM(ofParent);
//store current filename and position
getAbsFilename(filenames[file_subcall_ctr]);
SERIAL_ECHO(filenames[file_subcall_ctr]);
SERIAL_ECHORPGM(ofPos);
SERIAL_ECHOLN(sdpos);
@ -488,11 +507,11 @@ void CardReader::openFileWrite(const char* name)
SERIAL_ECHOLN(name);
}
sdprinting = false;
const char *fname=name;
if (!diveSubfolder(fname))
return;
//write
if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)){
SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL);
@ -504,7 +523,7 @@ void CardReader::openFileWrite(const char* name)
SERIAL_PROTOCOLRPGM(ofWritingToFile);////MSG_SD_WRITE_TO_FILE
printAbsFilenameFast();
SERIAL_PROTOCOLLN();
SERIAL_PROTOCOLLNRPGM(ofFileSelected);////MSG_SD_FILE_SELECTED
lcd_setstatuspgm(ofFileSelected);
scrollstuff = 0;
@ -513,7 +532,7 @@ void CardReader::openFileWrite(const char* name)
void CardReader::removeFile(const char* name)
{
if(!mounted) return;
if(!cardOK) return;
file.close();
sdprinting = false;
@ -521,7 +540,7 @@ void CardReader::removeFile(const char* name)
if (!diveSubfolder(fname))
return;
if (file.remove(curDir, fname))
if (file.remove(curDir, fname))
{
SERIAL_PROTOCOLPGM("File deleted:");
SERIAL_PROTOCOLLN(fname);
@ -536,7 +555,7 @@ void CardReader::removeFile(const char* name)
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLN('.');
}
}
uint32_t CardReader::getFileSize()
@ -546,9 +565,9 @@ uint32_t CardReader::getFileSize()
void CardReader::getStatus(bool arg_P)
{
if (printingIsPaused())
if (isPrintPaused)
{
if (saved_printing && (saved_printing_type == PowerPanic::PRINT_TYPE_SD))
if (saved_printing && (saved_printing_type == PRINTING_TYPE_SD))
SERIAL_PROTOCOLLNPGM("SD print paused");
else
SERIAL_PROTOCOLLNPGM("Print saved");
@ -562,15 +581,15 @@ void CardReader::getStatus(bool arg_P)
}
else
SERIAL_PROTOCOLLN(LONGEST_FILENAME);
SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE
SERIAL_PROTOCOL(sdpos);
SERIAL_PROTOCOL('/');
SERIAL_PROTOCOLLN(filesize);
uint16_t time = print_job_timer.duration() / 60;
SERIAL_PROTOCOL((int)(time / 60));
uint16_t time = ( _millis() - starttime ) / 60000U;
SERIAL_PROTOCOL(itostr2(time/60));
SERIAL_PROTOCOL(':');
SERIAL_PROTOCOLLN((int)(time % 60));
SERIAL_PROTOCOLLN(itostr2(time%60));
}
else
SERIAL_PROTOCOLLNPGM("Not SD printing");
@ -603,24 +622,21 @@ void CardReader::write_command_no_newline(char *buf)
void CardReader::checkautostart(bool force)
{
// The SD start is delayed because otherwise the serial cannot answer
// fast enough to make contact with the host software.
static bool autostart_stilltocheck = true;
if(!force)
{
if(!autostart_stilltocheck)
return;
if(autostart_atmillis.expired(5000))
if(autostart_atmillis<_millis())
return;
}
autostart_stilltocheck = false;
if(!mounted)
autostart_stilltocheck=false;
if(!cardOK)
{
mount();
if(!mounted) //fail
initsd();
if(!cardOK) //fail
return;
}
char autoname[30];
sprintf_P(autoname, PSTR("auto%i.g"), lastnr);
for(int8_t i=0;i<(int8_t)strlen(autoname);i++)
@ -628,9 +644,9 @@ void CardReader::checkautostart(bool force)
dir_t p;
root.rewind();
bool found=false;
while (root.readDir(p, NULL) > 0)
while (root.readDir(p, NULL) > 0)
{
for(int8_t i=0;i<(int8_t)strlen((char*)p.name);i++)
p.name[i]=tolower(p.name[i]);
@ -640,10 +656,12 @@ void CardReader::checkautostart(bool force)
if(p.name[9]!='~') //skip safety copies
if(strncmp((char*)p.name,autoname,5)==0)
{
char cmd[30];
// M23: Select SD file
enquecommandf_P(MSG_M23, autoname);
sprintf_P(cmd, PSTR("M23 %s"), autoname);
enquecommand(cmd);
// M24: Start/resume SD print
enquecommand_P(MSG_M24);
enquecommand_P(PSTR("M24"));
found=true;
}
}
@ -657,17 +675,17 @@ void CardReader::closefile(bool store_location)
{
file.sync();
file.close();
saving = false;
saving = false;
logging = false;
if(store_location)
{
//future: store printer state, filename and position for continuing a stopped print
// so one can unplug the printer and continue printing the next day.
}
}
void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/)
@ -676,14 +694,14 @@ void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/)
nrFiles=nr;
curDir->rewind();
lsDive("",*curDir,match, LS_GetFilename);
}
void CardReader::getfilename_simple(uint16_t entry, const char * const match/*=NULL*/)
void CardReader::getfilename_simple(uint32_t position, const char * const match/*=NULL*/)
{
curDir = &workDir;
nrFiles = 0;
curDir->seekSet((uint32_t)entry << 5);
curDir->seekSet(position);
lsDive("", *curDir, match, LS_GetFilename);
}
@ -709,10 +727,10 @@ bool CardReader::chdir(const char * relpath, bool doPresort)
{
SdFile newfile;
SdFile *parent=&root;
if(workDir.isOpen())
parent=&workDir;
if(!newfile.open(*parent,relpath, O_READ) || ((workDirDepth + 1) >= MAX_DIR_DEPTH))
{
SERIAL_ECHO_START;
@ -726,7 +744,7 @@ bool CardReader::chdir(const char * relpath, bool doPresort)
puts(relpath);
if (workDirDepth < MAX_DIR_DEPTH) {
for (uint8_t d = ++workDirDepth; d--;)
for (int d = ++workDirDepth; d--;)
workDirParents[d+1] = workDirParents[d];
workDirParents[0]=*parent;
}
@ -748,7 +766,7 @@ void CardReader::updir()
{
--workDirDepth;
workDir = workDirParents[0];
for (uint8_t d = 0; d < workDirDepth; d++)
for (unsigned int d = 0; d < workDirDepth; d++)
{
workDirParents[d] = workDirParents[d+1];
}
@ -765,17 +783,9 @@ void CardReader::updir()
*/
void CardReader::getfilename_sorted(const uint16_t nr, uint8_t sdSort) {
if (nr < sort_count)
getfilename_simple(sort_entries[(sdSort == SD_SORT_ALPHA) ? (sort_count - nr - 1) : nr]);
getfilename_simple(sort_positions[(sdSort == SD_SORT_ALPHA) ? (sort_count - nr - 1) : nr]);
else
getfilename_afterMaxSorting(nr);
}
void CardReader::getfilename_afterMaxSorting(uint16_t entry, const char * const match/*=NULL*/)
{
curDir = &workDir;
nrFiles = entry - sort_count + 1;
curDir->seekSet(lastSortedFilePosition << 5);
lsDive("", *curDir, match, LS_GetFilename);
getfilename(nr);
}
/**
@ -787,120 +797,133 @@ void CardReader::getfilename_afterMaxSorting(uint16_t entry, const char * const
* - Most RAM: Buffer the directory and return filenames from RAM
*/
void CardReader::presort() {
// Throw away old sort index
flush_presort();
if (IS_SD_INSERTED == false) return; //sorting is not used in farm mode
if (farm_mode || IS_SD_INSERTED == false) return; //sorting is not used in farm mode
uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
if (sdSort == SD_SORT_NONE) return; //sd sort is turned off
KEEPALIVE_STATE(IN_HANDLER);
// Throw away old sort index
flush_presort();
// If there are files, sort up to the limit
uint16_t fileCnt = getnrfilenames();
if (fileCnt > 0) {
// Never sort more than the max allowed
// If you use folders to organize, 20 may be enough
if (fileCnt > SDSORT_LIMIT) {
if ((sdSort != SD_SORT_NONE) && !farm_mode) {
lcd_show_fullscreen_message_and_wait_P(_T(MSG_FILE_CNT));
}
lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=6
fileCnt = SDSORT_LIMIT;
}
sort_count = fileCnt;
// By default re-read the names from SD for every compare
// retaining only two filenames at a time. This is very
// slow but is safest and uses minimal RAM.
char name1[LONG_FILENAME_LENGTH];
uint16_t crmod_time_bckp;
uint16_t crmod_date_bckp;
// Init sort order.
for (uint16_t i = 0; i < fileCnt; i++) {
if (!IS_SD_INSERTED) return;
manage_heater();
if (i == 0)
getfilename(0);
else
getfilename_next(position);
sort_entries[i] = position >> 5;
}
#if HAS_FOLDER_SORTING
uint16_t dirCnt = 0;
#endif
if ((fileCnt > 1) && (sdSort != SD_SORT_NONE) && !farm_mode) {
if (fileCnt > 1) {
// Init sort order.
uint8_t sort_order[fileCnt];
for (uint16_t i = 0; i < fileCnt; i++) {
if (!IS_SD_INSERTED) return;
manage_heater();
if (i == 0)
getfilename(0);
else
getfilename_next(position);
sort_order[i] = i;
sort_positions[i] = position;
#if HAS_FOLDER_SORTING
if (filenameIsDir) dirCnt++;
#endif
}
#ifdef SORTING_SPEEDTEST
LongTimer sortingSpeedtestTimer;
sortingSpeedtestTimer.start();
#endif //SORTING_SPEEDTEST
lastSortedFilePosition = position >> 5;
// By default re-read the names from SD for every compare
// retaining only two filenames at a time. This is very
// slow but is safest and uses minimal RAM.
char name1[LONG_FILENAME_LENGTH];
uint16_t crmod_time_bckp;
uint16_t crmod_date_bckp;
#ifdef INSERTSORT
#ifdef QUICKSORT
quicksort(0, fileCnt - 1);
#elif defined(SHELLSORT)
#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2)
#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp > crmodTime)) || (crmod_date_bckp > crmodDate))
#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp < crmodTime)) || (crmod_date_bckp < crmodDate))
#if HAS_FOLDER_SORTING
#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1))
#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
#endif
uint16_t counter = 0;
menu_progressbar_init(fileCnt * fileCnt / 2, _T(MSG_SORTING_FILES));
for (uint16_t i = 1; i < fileCnt; ++i){
// if (!IS_SD_INSERTED) return;
menu_progressbar_update(counter);
counter += i;
/// pop the position
const uint16_t o1 = sort_entries[i];
getfilename_simple(o1);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
#endif
/// find proper place
uint16_t j = i;
for (; j > 0; --j){
if (!IS_SD_INSERTED) return;
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++){
printf_P(PSTR("%2u "), sort_entries[z]);
}
MYSERIAL.println();
#endif
manage_heater();
const uint16_t o2 = sort_entries[j - 1];
getfilename_simple(o2);
char *name2 = LONGEST_FILENAME; // use the string in-place
// Sort the current pair according to settings.
if (
#if HAS_FOLDER_SORTING
(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_DIR(FOLDER_SORTING))
#else
(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_NODIR())
#endif
)
{
break;
} else {
#ifdef SORTING_DUMP
puts_P(PSTR("shift"));
#endif
sort_entries[j] = o2;
}
}
/// place the position
sort_entries[j] = o1;
}
for (uint8_t runs = 0; runs < 2; runs++)
{
//run=0: sorts all files and moves folders to the beginning
//run=1: assumes all folders are at the beginning of the list and sorts them
uint16_t sortCountFiles = 0;
if (runs == 0)
{
sortCountFiles = fileCnt;
}
#if HAS_FOLDER_SORTING
else
{
sortCountFiles = dirCnt;
}
#endif
uint16_t counter = 0;
uint16_t total = 0;
for (uint16_t i = sortCountFiles/2; i > 0; i /= 2) total += sortCountFiles - i; //total runs for progress bar
menu_progressbar_init(total, (runs == 0)?_i("Sorting files"):_i("Sorting folders"));
for (uint16_t gap = sortCountFiles/2; gap > 0; gap /= 2)
{
for (uint16_t i = gap; i < sortCountFiles; i++)
{
if (!IS_SD_INSERTED) return;
menu_progressbar_update(counter);
counter++;
manage_heater();
uint8_t orderBckp = sort_order[i];
getfilename_simple(sort_positions[orderBckp]);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
#endif
uint16_t j = i;
getfilename_simple(sort_positions[sort_order[j - gap]]);
char *name2 = LONGEST_FILENAME; // use the string in-place
#if HAS_FOLDER_SORTING
while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_DIR(FOLDER_SORTING):_SORT_CMP_DIR(FOLDER_SORTING)))
#else
while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_NODIR():_SORT_CMP_NODIR()))
#endif
{
sort_order[j] = sort_order[j - gap];
j -= gap;
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < sortCountFiles; z++)
{
printf_P(PSTR("%2u "), sort_order[z]);
}
printf_P(PSTR("i%2d j%2d gap%2d orderBckp%2d\n"), i, j, gap, orderBckp);
#endif
if (j < gap) break;
getfilename_simple(sort_positions[sort_order[j - gap]]);
name2 = LONGEST_FILENAME; // use the string in-place
}
sort_order[j] = orderBckp;
}
}
}
#else //Bubble Sort
@ -913,7 +936,7 @@ void CardReader::presort() {
#endif
uint16_t counter = 0;
menu_progressbar_init(0.5*(fileCnt - 1)*(fileCnt), _T(MSG_SORTING_FILES));
menu_progressbar_init(0.5*(fileCnt - 1)*(fileCnt), _i("Sorting files"));
for (uint16_t i = fileCnt; --i;) {
if (!IS_SD_INSERTED) return;
@ -927,22 +950,22 @@ void CardReader::presort() {
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++)
{
printf_P(PSTR("%2u "), sort_entries[z]);
printf_P(PSTR("%2u "), sort_order[z]);
}
MYSERIAL.println();
#endif
manage_heater();
const uint16_t o1 = sort_entries[j], o2 = sort_entries[j + 1];
const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
counter++;
getfilename_simple(o1);
getfilename_simple(sort_positions[o1]);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
#endif
getfilename_simple(o2);
getfilename_simple(sort_positions[o2]);
char *name2 = LONGEST_FILENAME; // use the string in-place
// Sort the current pair according to settings.
@ -957,9 +980,9 @@ void CardReader::presort() {
#ifdef SORTING_DUMP
puts_P(PSTR("swap"));
#endif
sort_entries[j] = o2;
sort_entries[j + 1] = o1;
sort_order[j] = o2;
sort_order[j + 1] = o1;
didSwap = true;
}
}
@ -967,26 +990,52 @@ void CardReader::presort() {
} //end of bubble sort loop
#endif
#ifdef SORTING_SPEEDTEST
printf_P(PSTR("sortingSpeedtestTimer:%lu\n"), sortingSpeedtestTimer.elapsed());
#endif //SORTING_SPEEDTEST
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++)
printf_P(PSTR("%2u "), sort_entries[z]);
printf_P(PSTR("%2u "), sort_order[z]);
SERIAL_PROTOCOLLN();
#endif
uint8_t sort_order_reverse_index[fileCnt];
for (uint8_t i = 0; i < fileCnt; i++)
sort_order_reverse_index[sort_order[i]] = i;
for (uint8_t i = 0; i < fileCnt; i++)
{
if (sort_order_reverse_index[i] != i)
{
uint32_t el = sort_positions[i];
uint8_t idx = sort_order_reverse_index[i];
while (idx != i)
{
uint32_t el1 = sort_positions[idx];
uint8_t idx1 = sort_order_reverse_index[idx];
sort_order_reverse_index[idx] = idx;
sort_positions[idx] = el;
idx = idx1;
el = el1;
}
sort_order_reverse_index[idx] = idx;
sort_positions[idx] = el;
}
}
menu_progressbar_finish();
}
else {
getfilename(0);
sort_positions[0] = position;
}
sort_count = fileCnt;
}
lcd_update(2);
KEEPALIVE_STATE(NOT_BUSY);
}
void CardReader::flush_presort() {
sort_count = 0;
lastSortedFilePosition = 0;
if (sort_count > 0) {
sort_count = 0;
}
}
#endif // SDCARD_SORT_ALPHA
@ -996,10 +1045,9 @@ void CardReader::flush_presort() {
void CardReader::printingHasFinished()
{
st_synchronize();
file.close();
if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure.
{
file.close();
file_subcall_ctr--;
openFileReadFilteredGcode(filenames[file_subcall_ctr],true);
setIndex(filespos[file_subcall_ctr]);
@ -1007,8 +1055,9 @@ void CardReader::printingHasFinished()
}
else
{
quickStop();
file.close();
sdprinting = false;
SetPrinterState(PrinterState::SDPrintingFinished); //set printer state to show LCD menu after finished SD print
if(SD_FINISHED_STEPPERRELEASE)
{
finishAndDisableSteppers();
@ -1027,17 +1076,4 @@ bool CardReader::ToshibaFlashAir_GetIP(uint8_t *ip)
return card.readExtMemory(1, 1, 0x400+0x150, 4, ip);
}
//Used for Reprint action
bool CardReader::FileExists(const char* filename)
{
bool exists = false;
if (file.open(curDir, filename, O_READ))
{
exists = true;
file.close();
}
return exists;
}
#endif //SDSUPPORT

View File

@ -12,7 +12,7 @@ class CardReader
{
public:
CardReader();
enum LsAction : uint8_t
{
LS_SerialPrint,
@ -26,14 +26,14 @@ public:
inline ls_param():LFN(0), timestamp(0) { }
inline ls_param(bool LFN, bool timestamp):LFN(LFN), timestamp(timestamp) { }
} __attribute__((packed));
void mount(bool doPresort = true);
void initsd(bool doPresort = true);
void write_command(char *buf);
void write_command_no_newline(char *buf);
//files auto[0-9].g on the sd card are performed in a row
//this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset
void checkautostart(bool x);
void checkautostart(bool x);
void openFileWrite(const char* name);
void openFileReadFilteredGcode(const char* name, bool replace_current = false);
void openLogFile(const char* name);
@ -46,24 +46,28 @@ public:
void printingHasFinished();
void getfilename(uint16_t nr, const char* const match=NULL);
void getfilename_simple(uint16_t entry, const char * const match = NULL);
void getfilename_simple(uint32_t position, const char * const match = NULL);
void getfilename_next(uint32_t position, const char * const match = NULL);
uint16_t getnrfilenames();
void getAbsFilename(char *t);
void printAbsFilenameFast();
void getDirName(char* name, uint8_t level);
uint8_t getWorkDirDepth();
uint16_t getWorkDirDepth();
void ls(ls_param params);
bool chdir(const char * relpath, bool doPresort);
void updir();
void cdroot(bool doPresort);
void setroot(bool doPresort);
#ifdef SDCARD_SORT_ALPHA
void presort();
#ifdef SDSORT_QUICKSORT
void swap(uint8_t left, uint8_t right);
void quicksort(uint8_t left, uint8_t right);
#endif //SDSORT_QUICKSORT
void getfilename_sorted(const uint16_t nr, uint8_t sdSort);
void getfilename_afterMaxSorting(uint16_t entry, const char * const match = NULL);
#endif
FORCE_INLINE bool isFileOpen() { return file.isOpen(); }
@ -83,15 +87,12 @@ public:
void ToshibaFlashAir_enable(bool enable) { card.setFlashAirCompatible(enable); }
bool ToshibaFlashAir_GetIP(uint8_t *ip);
//Reprint
bool FileExists(const char* filename);
public:
bool saving;
bool logging;
bool sdprinting;
bool mounted;
char filename[FILENAME_LENGTH];
bool sdprinting ;
bool cardOK ;
char filename[13];
// There are scenarios when simple modification time is not enough (on MS Windows)
// Therefore these timestamps hold the most recent one of creation/modification date/times
uint16_t crmodTime, crmodDate;
@ -101,17 +102,16 @@ public:
int lastnr; //last number of the autostart;
#ifdef SDCARD_SORT_ALPHA
bool presort_flag;
#endif // SDCARD_SORT_ALPHA
char dir_names[MAX_DIR_DEPTH][9];
#endif // SDCARD_SORT_ALPHA
private:
SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH];
uint8_t workDirDepth;
uint16_t workDirDepth;
// Sort files and folders alphabetically.
#ifdef SDCARD_SORT_ALPHA
uint16_t sort_count; // Count of sorted items in the current directory
uint16_t sort_entries[SDSORT_LIMIT];
uint16_t lastSortedFilePosition;
uint32_t sort_positions[SDSORT_LIMIT];
#endif // SDCARD_SORT_ALPHA
@ -130,10 +130,13 @@ private:
char filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
uint32_t filesize;
//int16_t n;
ShortTimer autostart_atmillis;
unsigned long autostart_atmillis;
uint32_t sdpos ;
uint16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
char* diveDirName;
bool diveSubfolder (const char *&fileName);
void lsDive(const char *prepend, SdFile parent, const char * const match=NULL, LsAction lsAction = LS_GetFilename, ls_param lsParams = ls_param());
@ -146,7 +149,7 @@ extern CardReader card;
#define IS_SD_PRINTING (card.sdprinting)
#if (SDCARDDETECT > -1)
# ifdef SDCARDDETECTINVERTED
# ifdef SDCARDDETECTINVERTED
# define IS_SD_INSERTED (READ(SDCARDDETECT)!=0)
# else
# define IS_SD_INSERTED (READ(SDCARDDETECT)==0)

View File

@ -1,14 +1,8 @@
#include <stdarg.h>
#include <util/atomic.h>
#include "cmdqueue.h"
#include "cardreader.h"
#include "ultralcd.h"
#include "Prusa_farm.h"
#include "meatpack.h"
#include "messages.h"
#include "language.h"
#include "stopwatch.h"
#include "power_panic.h"
extern bool Stopped;
// Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT.
char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
@ -29,11 +23,16 @@ bool cmdbuffer_front_already_processed = false;
bool cmdqueue_serial_disabled = false;
int serial_count = 0; //index of character read from serial line
bool comment_mode = false;
boolean comment_mode = false;
char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
ShortTimer serialTimeoutTimer;
unsigned long TimeSent = _millis();
unsigned long TimeNow = _millis();
long gcode_N = 0;
long gcode_LastN = 0;
long Stopped_gcode_LastN = 0;
uint32_t sdpos_atomic = 0;
@ -98,7 +97,7 @@ void cmdqueue_reset()
{
while (buflen)
{
// printf_P(PSTR("dumping: \"%s\" of type %u\n"), cmdbuffer+bufindr+CMDHDRSIZE, CMDBUFFER_CURRENT_TYPE);
// printf_P(PSTR("dumping: \"%s\" of type %hu\n"), cmdbuffer+bufindr+CMDHDRSIZE, CMDBUFFER_CURRENT_TYPE);
ClearToSend();
cmdqueue_pop_front();
}
@ -108,7 +107,7 @@ void cmdqueue_reset()
//commands are removed from command queue after process_command() function is finished
//reseting command queue and enqueing new commands during some (usually long running) command processing would cause that new commands are immediately removed from queue (or damaged)
//this will ensure that all new commands which are enqueued after cmdqueue reset, will be always executed
cmdbuffer_front_already_processed = true;
cmdbuffer_front_already_processed = true;
}
// How long a string could be pushed to the front of the command queue?
@ -159,7 +158,7 @@ static bool cmdqueue_could_enqueue_front(size_t len_asked)
// len_asked does not contain the zero terminator size.
// This function may update bufindw, therefore for the power panic to work, this function must be called
// with the interrupts disabled!
static bool __attribute__((noinline)) cmdqueue_could_enqueue_back(size_t len_asked)
static bool cmdqueue_could_enqueue_back(size_t len_asked, bool atomic_update = false)
{
// MAX_CMD_SIZE has to accommodate the zero terminator.
if (len_asked >= MAX_CMD_SIZE)
@ -169,29 +168,61 @@ static bool __attribute__((noinline)) cmdqueue_could_enqueue_back(size_t len_ask
// Full buffer.
return false;
// If there is some data stored starting at bufindw, len_asked is certainly smaller than
// the allocated data buffer. Try to reserve a new buffer and to move the already received
// serial data.
// How much memory to reserve for the commands pushed to the front?
// End of the queue, when pushing to the end.
size_t endw = bufindw + len_asked + (1 + CMDHDRSIZE);
if (bufindw < bufindr)
// Simple case. There is a contiguous space between the write buffer and the read buffer.
return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
// Otherwise the free space is split between the start and end.
if (// Could one fit to the end, including the reserve?
endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
// Could one fit to the end, and the reserve to the start?
(endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
return true;
// Could one fit both to the start?
if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
// Mark the rest of the buffer as used.
memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
// and point to the start.
// Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { bufindw = 0; }
return true;
if (serial_count > 0) {
// If there is some data stored starting at bufindw, len_asked is certainly smaller than
// the allocated data buffer. Try to reserve a new buffer and to move the already received
// serial data.
// How much memory to reserve for the commands pushed to the front?
// End of the queue, when pushing to the end.
size_t endw = bufindw + len_asked + (1 + CMDHDRSIZE);
if (bufindw < bufindr)
// Simple case. There is a contiguous space between the write buffer and the read buffer.
return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
// Otherwise the free space is split between the start and end.
if (// Could one fit to the end, including the reserve?
endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
// Could one fit to the end, and the reserve to the start?
(endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
return true;
// Could one fit both to the start?
if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
// Mark the rest of the buffer as used.
memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
// and point to the start.
// Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
if (atomic_update)
cli();
bufindw = 0;
if (atomic_update)
sei();
return true;
}
} else {
// How much memory to reserve for the commands pushed to the front?
// End of the queue, when pushing to the end.
size_t endw = bufindw + len_asked + (1 + CMDHDRSIZE);
if (bufindw < bufindr)
// Simple case. There is a contiguous space between the write buffer and the read buffer.
return endw + CMDBUFFER_RESERVE_FRONT <= bufindr;
// Otherwise the free space is split between the start and end.
if (// Could one fit to the end, including the reserve?
endw + CMDBUFFER_RESERVE_FRONT <= sizeof(cmdbuffer) ||
// Could one fit to the end, and the reserve to the start?
(endw <= sizeof(cmdbuffer) && CMDBUFFER_RESERVE_FRONT <= bufindr))
return true;
// Could one fit both to the start?
if (len_asked + (1 + CMDHDRSIZE) + CMDBUFFER_RESERVE_FRONT <= bufindr) {
// Mark the rest of the buffer as used.
memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
// and point to the start.
// Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
if (atomic_update)
cli();
bufindw = 0;
if (atomic_update)
sei();
return true;
}
}
return false;
}
@ -254,22 +285,6 @@ void cmdqueue_dump_to_serial()
}
#endif /* CMDBUFFER_DEBUG */
static const char bufferFull[] PROGMEM = "\" failed: Buffer full!";
static const char enqueingFront[] PROGMEM = "Enqueing to the front: \"";
void enquecommandf_P(const char *fmt, ...)
{
// MAX_CMD_SIZE is 96, but for formatting
// string we usually don't need more than 30 bytes
char cmd_buffer[30];
va_list ap;
va_start(ap, fmt);
vsnprintf_P(cmd_buffer, sizeof(cmd_buffer), fmt, ap);
va_end(ap);
enquecommand(cmd_buffer, false);
}
//adds an command to the main command buffer
//thats really done in a non-safe way.
//needs overworking someday
@ -305,7 +320,7 @@ void enquecommand(const char *cmd, bool from_progmem)
SERIAL_PROTOCOLRPGM(cmd);
else
SERIAL_ECHO(cmd);
SERIAL_ECHOLNRPGM(bufferFull);
SERIAL_ECHOLNPGM("\" failed: Buffer full!");
#ifdef CMDBUFFER_DEBUG
cmdqueue_dump_to_serial();
#endif /* CMDBUFFER_DEBUG */
@ -329,7 +344,7 @@ void enquecommand_front(const char *cmd, bool from_progmem)
strcpy(cmdbuffer + bufindr + CMDHDRSIZE, cmd);
++ buflen;
SERIAL_ECHO_START;
SERIAL_ECHORPGM(enqueingFront);
SERIAL_ECHOPGM("Enqueing to the front: \"");
SERIAL_ECHO(cmdbuffer + bufindr + CMDHDRSIZE);
SERIAL_ECHOLNPGM("\"");
#ifdef CMDBUFFER_DEBUG
@ -337,12 +352,12 @@ void enquecommand_front(const char *cmd, bool from_progmem)
#endif /* CMDBUFFER_DEBUG */
} else {
SERIAL_ERROR_START;
SERIAL_ECHORPGM(enqueingFront);
SERIAL_ECHOPGM("Enqueing to the front: \"");
if (from_progmem)
SERIAL_PROTOCOLRPGM(cmd);
else
SERIAL_ECHO(cmd);
SERIAL_ECHOLNRPGM(bufferFull);
SERIAL_ECHOLNPGM("\" failed: Buffer full!");
#ifdef CMDBUFFER_DEBUG
cmdqueue_dump_to_serial();
#endif /* CMDBUFFER_DEBUG */
@ -354,12 +369,22 @@ void enquecommand_front(const char *cmd, bool from_progmem)
void repeatcommand_front()
{
cmdbuffer_front_already_processed = true;
}
void proc_commands() {
if (buflen)
{
process_commands();
if (!cmdbuffer_front_already_processed)
cmdqueue_pop_front();
cmdbuffer_front_already_processed = false;
}
}
void get_command()
{
// Test and reserve space for the new command string.
if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1))
if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1, true))
return;
if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size
@ -368,24 +393,17 @@ void get_command()
}
// start of serial line processing loop
while (((MYSERIAL.available() > 0 && !saved_printing) || (MYSERIAL.available() > 0 && printingIsPaused())) && !cmdqueue_serial_disabled) { //is print is saved (crash detection or filament detection), dont process data from serial line
#ifdef ENABLE_MEATPACK
// MeatPack Changes
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const int rec = MYSERIAL.read();
if (rec < 0) continue;
mp_handle_rx_char((uint8_t)rec);
char c_res[2] = {0, 0};
const uint8_t char_count = mp_get_result_char(c_res);
// Note -- Paired bracket in preproc switch below
for (uint8_t i = 0; i < char_count; ++i) { char serial_char = c_res[i];
#else
while (((MYSERIAL.available() > 0 && !saved_printing) || (MYSERIAL.available() > 0 && isPrintPaused)) && !cmdqueue_serial_disabled) { //is print is saved (crash detection or filament detection), dont process data from serial line
char serial_char = MYSERIAL.read();
#endif
serialTimeoutTimer.start();
/* if (selectedSerialPort == 1)
{
selectedSerialPort = 0;
MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode
selectedSerialPort = 1;
} */ //RP - removed
TimeSent = _millis();
TimeNow = _millis();
if (serial_char < 0)
// Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names
@ -401,23 +419,22 @@ void get_command()
comment_mode = false; //for new command
return;
}
cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; // terminate string
char* cmd_head = cmdbuffer+bufindw+CMDHDRSIZE; // current command pointer
char* cmd_start = cmd_head; // pointer past the line number (if any)
cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
if(!comment_mode){
long gcode_N = -1; // seen line number
gcode_N = 0;
// Line numbers must be first in buffer
if (*cmd_head == 'N') {
// Line number met: decode the number, then move cmd_start past all spaces.
gcode_N = (strtol(cmd_head+1, &cmd_start, 10));
while (*cmd_start == ' ') ++cmd_start;
if ((strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA") == NULL) &&
(cmdbuffer[bufindw+CMDHDRSIZE] == 'N')) {
// Test whether the successive lines are stamped with an increasing line number ID.
if(gcode_N != gcode_LastN+1 && strncmp_P(cmd_start, PSTR("M110"), 4)) {
// Line numbers not sent in succession and M110 not seen.
// Line number met. When sending a G-code over a serial line, each line may be stamped with its index,
// and Marlin tests, whether the successive lines are stamped with an increasing line number ID
gcode_N = (strtol(cmdbuffer+bufindw+CMDHDRSIZE+1, NULL, 10));
if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) {
// M110 - set current line number.
// Line numbers not sent in succession.
SERIAL_ERROR_START;
SERIAL_ERRORRPGM(_n("Line Number is not Last Line Number+1, Last Line: "));////MSG_ERR_LINE_NO
SERIAL_ERRORLN(gcode_LastN);
@ -427,13 +444,13 @@ void get_command()
return;
}
if((strchr_pointer = strchr(cmd_start, '*')) != NULL)
if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL)
{
byte checksum = 0;
char *p = cmd_head;
char *p = cmdbuffer+bufindw+CMDHDRSIZE;
while (p != strchr_pointer)
checksum = checksum^(*p++);
if (code_value_short() != (int16_t)checksum) {
if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) {
SERIAL_ERROR_START;
SERIAL_ERRORRPGM(_n("checksum mismatch, Last Line: "));////MSG_ERR_CHECKSUM_MISMATCH
SERIAL_ERRORLN(gcode_LastN);
@ -453,82 +470,54 @@ void get_command()
serial_count = 0;
return;
}
// Don't parse N again with code_seen('N')
cmdbuffer[bufindw + CMDHDRSIZE] = '$';
//if no errors, continue parsing
gcode_LastN = gcode_N;
}
else
// if we don't receive 'N' but still see '*'
if ((cmdbuffer[bufindw + CMDHDRSIZE] != 'N') && (cmdbuffer[bufindw + CMDHDRSIZE] != '$') && (strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL))
{
// move cmd_start past all spaces
while (*cmd_start == ' ') ++cmd_start;
// if we didn't receive 'N' but still see '*'
if (strchr(cmd_start, '*') != NULL)
{
SERIAL_ERROR_START;
SERIAL_ERRORRPGM(_n("No Line Number with checksum, Last Line: "));////MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM
SERIAL_ERRORLN(gcode_LastN);
FlushSerialRequestResend();
serial_count = 0;
return;
}
}
// Handle KILL early, even when Stopped
if(strcmp_P(cmd_start, PSTR("M112")) == 0)
kill(MSG_M112_KILL);
// Bypass Stopped for some commands
bool allow_when_stopped = false;
if(strncmp_P(cmd_start, PSTR("M310"), 4) == 0)
allow_when_stopped = true;
// Handle the USB timer
if ((*cmd_start == 'G') && (GetPrinterState() != PrinterState::IsSDPrinting)) {
usb_timer.start();
SetPrinterState(PrinterState::IsHostPrinting); //set printer state busy printing to hide LCD menu while USB printing
eeprom_update_byte_notify((uint8_t*)EEPROM_UVLO, PowerPanic::NO_PENDING_RECOVERY);
}
if (allow_when_stopped == false && Stopped == true) {
// Stopped can be set either during error states (thermal error: cannot continue), or
// when a printer-initiated action is processed. In such case the printer will send to
// the host an action, but cannot know if the action has been processed while new
// commands are being sent. In this situation we just drop the command while issuing
// periodic "busy" messages in the main loop. Since we're not incrementing the received
// line number, a request for resend will happen (if necessary), ensuring we don't skip
// commands whenever Stopped is cleared and processing resumes.
SERIAL_ERROR_START;
SERIAL_ERRORRPGM(_n("No Line Number with checksum, Last Line: "));////MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM
SERIAL_ERRORLN(gcode_LastN);
FlushSerialRequestResend();
serial_count = 0;
return;
}
if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) {
if (! IS_SD_PRINTING) {
usb_printing_counter = 10;
is_usb_printing = true;
}
if (Stopped == true) {
int gcode = strtol(strchr_pointer+1, NULL, 10);
if (gcode >= 0 && gcode <= 3) {
SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);
LCD_MESSAGERPGM(_T(MSG_STOPPED));
}
}
} // end of 'G' command
// Command is complete: store the current line into buffer, move to the next line.
//If command was e-stop process now
if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0)
kill(MSG_M112_KILL, 2);
// Store the current line into buffer, move to the next line.
// Store type of entry
cmdbuffer[bufindw] = gcode_N >= 0 ? CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR : CMDBUFFER_CURRENT_TYPE_USB;
cmdbuffer[bufindw] = gcode_N ? CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR : CMDBUFFER_CURRENT_TYPE_USB;
#ifdef CMDBUFFER_DEBUG
SERIAL_ECHO_START;
SERIAL_ECHOPGM("Storing a command line to buffer: ");
SERIAL_ECHO(cmd_start);
SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE);
SERIAL_ECHOLNPGM("");
#endif /* CMDBUFFER_DEBUG */
// Store the command itself (without line number or checksum)
size_t cmd_len;
if (cmd_head == cmd_start)
cmd_len = strlen(cmd_start) + 1;
else {
// strip the line number
cmd_len = 0;
do { cmd_head[cmd_len] = cmd_start[cmd_len]; }
while (cmd_head[cmd_len++]);
}
bufindw += cmd_len + CMDHDRSIZE;
bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
if (bufindw == sizeof(cmdbuffer))
bufindw = 0;
++ buflen;
// Update the processed gcode line
if (gcode_N >= 0)
gcode_LastN = gcode_N;
#ifdef CMDBUFFER_DEBUG
SERIAL_ECHOPGM("Number of commands in the buffer: ");
SERIAL_ECHO(buflen);
@ -538,7 +527,7 @@ void get_command()
serial_count = 0; //clear buffer
// Don't call cmdqueue_could_enqueue_back if there are no characters waiting
// in the queue, as this function will reserve the memory.
if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
return;
} // end of "end of line" processing
else {
@ -546,20 +535,28 @@ void get_command()
if(serial_char == ';') comment_mode = true;
if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
}
#ifdef ENABLE_MEATPACK
}
#endif
} // end of serial line processing loop
if (serial_count > 0 && serialTimeoutTimer.expired(farm_mode ? 800 : 2000)) {
comment_mode = false;
serial_count = 0;
SERIAL_ECHOLNPGM("RX timeout");
return;
if(farm_mode){
TimeNow = _millis();
if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) {
cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0;
bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
if (bufindw == sizeof(cmdbuffer))
bufindw = 0;
++ buflen;
serial_count = 0;
SERIAL_ECHOPGM("TIMEOUT:");
//memset(cmdbuffer, 0 , sizeof(cmdbuffer));
return;
}
}
#ifdef SDSUPPORT
if(!card.sdprinting || !card.isFileOpen() || serial_count!=0){
if(!card.sdprinting || serial_count!=0){
// If there is a half filled buffer from serial line, wait until return before
// continuing with the serial line.
return;
@ -585,7 +582,7 @@ void get_command()
char serial_char = (char)n;
if( serial_char == '\n'
|| serial_char == '\r'
|| serial_char == '#'
|| ((serial_char == '#' || serial_char == ':') )
|| serial_count >= (MAX_CMD_SIZE - 1)
|| n==-1
){
@ -596,9 +593,9 @@ void get_command()
{
// This is either an empty line, or a line with just a comment.
// Continue to the following line, and continue accumulating the number of bytes
// read from the sdcard into sd_count,
// so that the length of the already read empty lines and comments will be added
// to the following non-empty line.
// read from the sdcard into sd_count,
// so that the lenght of the already read empty lines and comments will be added
// to the following non-empty line.
return; // prevent cycling indefinitely - let manage_heaters do their job
}
// The new command buffer could be updated non-atomically, because it is not yet considered
@ -635,11 +632,11 @@ void get_command()
comment_mode = false; //for new command
serial_count = 0; //clear buffer
if(card.eof()) break;
// The following line will reserve buffer space if available.
if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
return;
}
else
@ -656,28 +653,27 @@ void get_command()
// cleared by printingHasFinished after peforming all remaining moves.
if(!cmdqueue_calc_sd_length())
{
// queue is complete, but before we process EOF commands prevent
// re-entry by disabling SD processing from any st_synchronize call
card.closefile();
SERIAL_PROTOCOLLNRPGM(_n("Done printing file"));////MSG_FILE_PRINTED
stoptime=_millis();
char time[30];
uint32_t t = print_job_timer.duration() / 60;
unsigned long t=(stoptime-starttime-pause_time)/1000;
pause_time = 0;
int hours, minutes;
minutes = t % 60;
hours = t / 60;
save_statistics();
minutes=(t/60)%60;
hours=t/60/60;
save_statistics(total_filament_used, t);
sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
SERIAL_ECHO_START;
SERIAL_ECHOLN(time);
#ifndef SHOW_FILENAME_AFTER_FINISH
lcd_setstatus(time);
#endif //SHOW_FILENAME_AFTER_FINISH
card.printingHasFinished();
card.checkautostart(true);
if (farm_mode)
prusa_statistics(6);
{
prusa_statistics(6);
lcd_commands_type = LcdCommands::FarmModeConfirm;
}
}
}

View File

@ -2,11 +2,13 @@
#define CMDQUEUE_H
#include "Marlin.h"
#include "language.h"
// String circular buffer. Commands may be pushed to the buffer from both sides:
// Chained commands will be pushed to the front, interactive (from LCD menu)
// Chained commands will be pushed to the front, interactive (from LCD menu)
// and printing commands (from serial line or from SD card) are pushed to the tail.
// First character of each entry indicates the type of the entry:
// First character of each entry indicates the type of the entry:
#define CMDBUFFER_CURRENT_TYPE_UNKNOWN 0
// Command in cmdbuffer was sent over USB.
#define CMDBUFFER_CURRENT_TYPE_USB 1
@ -16,8 +18,8 @@
#define CMDBUFFER_CURRENT_TYPE_UI 3
// Command in cmdbuffer was generated by another G-code.
#define CMDBUFFER_CURRENT_TYPE_CHAINED 4
// Command has been processed and its SD card length has been possibly pushed
// to the planner queue, but not yet removed from the cmdqueue.
// Command has been processed and its SD card length has been possibly pushed
// to the planner queue, but not yet removed from the cmdqueue.
// This is a temporary state to reduce stepper interrupt locking time.
#define CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED 5
//Command in cmdbuffer was sent over USB and contains line number
@ -47,10 +49,15 @@ extern bool cmdqueue_serial_disabled;
extern uint32_t sdpos_atomic;
extern int serial_count;
extern bool comment_mode;
extern boolean comment_mode;
extern char *strchr_pointer;
extern unsigned long TimeSent;
extern unsigned long TimeNow;
extern long gcode_N;
extern long gcode_LastN;
extern long Stopped_gcode_LastN;
extern bool cmdqueue_pop_front();
extern void cmdqueue_reset();
@ -59,31 +66,29 @@ extern void cmdqueue_dump_to_serial_single_line(int nr, const char *p);
extern void cmdqueue_dump_to_serial();
#endif /* CMDBUFFER_DEBUG */
extern bool cmd_buffer_empty();
/// @brief Variant of enquecommand which accepts a format string
/// @param fmt a format string residing in PROGMEM
void enquecommandf_P(const char *fmt, ...);
extern void enquecommand(const char *cmd, bool from_progmem = false);
extern void enquecommand_front(const char *cmd, bool from_progmem = false);
extern void repeatcommand_front();
extern void get_command();
extern uint16_t cmdqueue_calc_sd_length();
#if defined(__cplusplus)
extern "C" {
#endif
extern double strtod_noE(const char* nptr, char** endptr);
#if defined(__cplusplus)
}
#endif
// Return True if a character was found
static inline bool code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
static inline bool code_seen_P(const char *code_PROGMEM) { return (strchr_pointer = strstr_P(CMDBUFFER_CURRENT_STRING, code_PROGMEM)) != NULL; }
static inline float code_value() { return strtod_noE(strchr_pointer+1, NULL);}
static inline float code_value() { return strtod(strchr_pointer+1, NULL);}
static inline long code_value_long() { return strtol(strchr_pointer+1, NULL, 10); }
static inline int16_t code_value_short() { return int16_t(strtol(strchr_pointer+1, NULL, 10)); };
static inline uint8_t code_value_uint8() { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); };
static inline float code_value_float()
{
char* e = strchr(strchr_pointer, 'E');
if (!e) return strtod(strchr_pointer + 1, NULL);
*e = 0;
float ret = strtod(strchr_pointer + 1, NULL);
*e = 'E';
return ret;
}
#endif //CMDQUEUE_H

View File

@ -2,22 +2,25 @@
#define _CONFIG_H
#include "Configuration_var.h"
#include "Configuration_prusa.h"
#include "pins.h"
#if (defined(VOLT_IR_PIN) && defined(IR_SENSOR))
# define IR_SENSOR_ANALOG
#endif
//ADC configuration
#if defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
#define ADC_CHAN_MSK 0b0000001101011111 //used AD channels bit mask (0,1,2,3,4,6,8,9)
#define ADC_DIDR_MSK 0b0000001001011111 //AD channels DIDR mask (1 ~ disabled digital input)
#define ADC_CHAN_CNT 8 //number of used channels)
#else
#ifndef IR_SENSOR_ANALOG
#define ADC_CHAN_MSK 0b0000001001011111 //used AD channels bit mask (0,1,2,3,4,6,9)
#define ADC_DIDR_MSK 0b0000001001011111 //AD channels DIDR mask (1 ~ disabled digital input)
#define ADC_CHAN_CNT 7 //number of used channels)
#endif
#else //!IR_SENSOR_ANALOG
#define ADC_CHAN_MSK 0b0000001101011111 //used AD channels bit mask (0,1,2,3,4,6,8,9)
#define ADC_DIDR_MSK 0b0000001001011111 //AD channels DIDR mask (1 ~ disabled digital input)
#define ADC_CHAN_CNT 8 //number of used channels)
#endif //!IR_SENSOR_ANALOG
#define ADC_OVRSAMPL 16 //oversampling multiplier
#define ADC_CALLBACK adc_callback //callback function ()
#define ADC_CALLBACK adc_ready //callback function ()
//SWI2C configuration
//#define SWI2C_SDA 20 //SDA on P3
@ -27,6 +30,7 @@
#define SWI2C_TMO 2048 //2048 cycles timeout
//PAT9125 configuration
//#define PAT9125_SWSPI // software SPI mode (incomplete)
#ifdef SWI2C_SCL
#define PAT9125_SWI2C // software I2C mode
#else
@ -38,12 +42,7 @@
//#define PAT9125_I2C_ADDR 0x73 //ID=NC
#define PAT9125_XRES 0
#define PAT9125_YRES 240 // maximum resolution (5*X cpi)
#define PAT9125_YRES_MM (5*PAT9125_YRES/25.4) // counts per mm
#define PAT9125_INVERT_X 0 //1 means flipped
#define PAT9125_INVERT_Y 1 //1 means flipped
#define PAT9125_SWAP_XY 0 //X is Y and Y is X
#define PAT9125_12B_RES 1 //8bit or 12bit signed motion data
#define PAT9125_NEW_INIT 1 //set to 1 to use the magic sequence provided by pixart.
#define PAT9124_YRES_MM (5*PAT9125_YRES/25.4) // counts per mm
//SM4 configuration
#define SM4_DEFDELAY 500 //default step delay [us]
@ -55,45 +54,18 @@
#define TMC2130_SPCR SPI_SPCR(TMC2130_SPI_RATE, 1, 1, 1, 0)
#define TMC2130_SPSR SPI_SPSR(TMC2130_SPI_RATE)
// This is set by the cmake build to be able to take control of
// the language flag, without breaking existing build mechanisms.
#ifndef CMAKE_CONTROL
//LANG - Multi-language support
//#define LANG_MODE 0 // primary language only
#define LANG_MODE 1 // sec. language support
#endif
#define LANG_SIZE_RESERVED 0x3500 // reserved space for secondary language (13568 bytes).
// 0x3D00 Maximum 15616 bytes as it depends on xflash_layout.h
// 16 Languages max. per group including stock
#if (LANG_SIZE_RESERVED % 256)
#error "LANG_SIZE_RESERVED should be a multiple of a page size"
#endif
#define LANG_SIZE_RESERVED 0x3000 // reserved space for secondary language (12288 bytes)
//Community language support
#define COMMUNITY_LANG_GROUP 1
#define COMMUNITY_LANG_NL // Community Dutch language
//#define COMMUNITY_LANG_QR // Community new language //..use this as a template and replace 'QR'
#if (COMMUNITY_LANG_GROUP == 1)
#define COMMUNITY_LANG_GROUP1_NL // Community Dutch language
#define COMMUNITY_LANG_GROUP1_RO // Community Romanian language
#define COMMUNITY_LANG_GROUP1_HU // Community Hungarian language
#define COMMUNITY_LANG_GROUP1_HR // Community Croatian language
#define COMMUNITY_LANG_GROUP1_SK // Community Slovak language
#define COMMUNITY_LANG_GROUP1_SV // Community Swedish language
#define COMMUNITY_LANG_GROUP1_NO // Community Norwegian language
//#define COMMUNITY_LANG_GROUP1_DA // Community Danish language
//#define COMMUNITY_LANG_GROUP1_SL // Community Slovanian language
//#define COMMUNITY_LANG_GROUP1_LB // Community Luxembourgish language
#endif //COMMUNITY_LANG_GROUP 1
#if (COMMUNITY_LANG_GROUP == 2)
#define COMMUNITY_LANG_GROUP2_LT // Community Lithuanian language
//#define COMMUNITY_LANG_GROUP1_QR // Community new language //..use this as a template and replace 'QR'
#endif //COMMUNITY_LANG_GROUP 2
#if (COMMUNITY_LANG_GROUP >=1 )
#define COMMUNITY_LANGUAGE_SUPPORT
#if defined(COMMUNITY_LANG_NL) //|| defined(COMMUNITY_LANG_QR) //..use last part as a template and replace 'QR'
#define COMMUNITY_LANG_SUPPORT
#endif
// Sanity checks for correct configuration of XFLASH_DUMP options
@ -117,11 +89,4 @@
#define EMERGENCY_HANDLERS
#endif
//FARM_MODE
#if ( LANG_MODE == 0 ) && defined(XFLASH) //Save resources on EINSY and disable FARM_MODE on multi-language version
#define PRUSA_FARM
#endif //PRUSA_FARM only in english on EINSYs
#ifndef XFLASH //enable FARM_MODE on miniRAMBo boards
#define PRUSA_FARM
#endif
#endif //_CONFIG_H

292
Firmware/conv2str.cpp Normal file
View File

@ -0,0 +1,292 @@
//conv2str.cpp - Float conversion utilities
#include "conv2str.h"
#include <stdlib.h>
// convert float to string with +123.4 format
char conv[8];
char *ftostr3(const float &x)
{
return itostr3((int)x);
}
char *itostr2(const uint8_t &x)
{
//sprintf(conv,"%5.1f",x);
int xx = x;
conv[0] = (xx / 10) % 10 + '0';
conv[1] = (xx) % 10 + '0';
conv[2] = 0;
return conv;
}
// Convert float to string with 123.4 format, dropping sign
char *ftostr31(const float &x)
{
int xx = x * 10;
conv[0] = (xx >= 0) ? '+' : '-';
xx = abs(xx);
conv[1] = (xx / 1000) % 10 + '0';
conv[2] = (xx / 100) % 10 + '0';
conv[3] = (xx / 10) % 10 + '0';
conv[4] = '.';
conv[5] = (xx) % 10 + '0';
conv[6] = 0;
return conv;
}
// Convert float to string with 123.4 format
char *ftostr31ns(const float &x)
{
int xx = x * 10;
//conv[0]=(xx>=0)?'+':'-';
xx = abs(xx);
conv[0] = (xx / 1000) % 10 + '0';
conv[1] = (xx / 100) % 10 + '0';
conv[2] = (xx / 10) % 10 + '0';
conv[3] = '.';
conv[4] = (xx) % 10 + '0';
conv[5] = 0;
return conv;
}
char *ftostr32(const float &x)
{
long xx = x * 100;
if (xx >= 0)
conv[0] = (xx / 10000) % 10 + '0';
else
conv[0] = '-';
xx = abs(xx);
conv[1] = (xx / 1000) % 10 + '0';
conv[2] = (xx / 100) % 10 + '0';
conv[3] = '.';
conv[4] = (xx / 10) % 10 + '0';
conv[5] = (xx) % 10 + '0';
conv[6] = 0;
return conv;
}
//// Convert float to rj string with 123.45 format
char *ftostr32ns(const float &x) {
long xx = abs(x);
conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' ';
conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' ';
conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : '0';
conv[3] = '.';
conv[4] = (xx / 10) % 10 + '0';
conv[5] = xx % 10 + '0';
return conv;
}
// Convert float to string with 1.234 format
char *ftostr43(const float &x, uint8_t offset)
{
const size_t maxOffset = sizeof(conv)/sizeof(conv[0]) - 6;
if (offset>maxOffset) offset = maxOffset;
long xx = x * 1000;
if (xx >= 0)
conv[offset] = (xx / 1000) % 10 + '0';
else
conv[offset] = '-';
xx = abs(xx);
conv[offset + 1] = '.';
conv[offset + 2] = (xx / 100) % 10 + '0';
conv[offset + 3] = (xx / 10) % 10 + '0';
conv[offset + 4] = (xx) % 10 + '0';
conv[offset + 5] = 0;
return conv;
}
//Float to string with 1.23 format
char *ftostr12ns(const float &x)
{
long xx = x * 100;
xx = abs(xx);
conv[0] = (xx / 100) % 10 + '0';
conv[1] = '.';
conv[2] = (xx / 10) % 10 + '0';
conv[3] = (xx) % 10 + '0';
conv[4] = 0;
return conv;
}
//Float to string with 1.234 format
char *ftostr13ns(const float &x)
{
long xx = x * 1000;
if (xx >= 0)
conv[0] = ' ';
else
conv[0] = '-';
xx = abs(xx);
conv[1] = (xx / 1000) % 10 + '0';
conv[2] = '.';
conv[3] = (xx / 100) % 10 + '0';
conv[4] = (xx / 10) % 10 + '0';
conv[5] = (xx) % 10 + '0';
conv[6] = 0;
return conv;
}
// convert float to space-padded string with -_23.4_ format
char *ftostr32sp(const float &x) {
long xx = abs(x * 100);
uint8_t dig;
if (x < 0) { // negative val = -_0
conv[0] = '-';
dig = (xx / 1000) % 10;
conv[1] = dig ? '0' + dig : ' ';
}
else { // positive val = __0
dig = (xx / 10000) % 10;
if (dig) {
conv[0] = '0' + dig;
conv[1] = '0' + (xx / 1000) % 10;
}
else {
conv[0] = ' ';
dig = (xx / 1000) % 10;
conv[1] = dig ? '0' + dig : ' ';
}
}
conv[2] = '0' + (xx / 100) % 10; // lsd always
dig = xx % 10;
if (dig) { // 2 decimal places
conv[5] = '0' + dig;
conv[4] = '0' + (xx / 10) % 10;
conv[3] = '.';
}
else { // 1 or 0 decimal place
dig = (xx / 10) % 10;
if (dig) {
conv[4] = '0' + dig;
conv[3] = '.';
}
else {
conv[3] = conv[4] = ' ';
}
conv[5] = ' ';
}
conv[6] = '\0';
return conv;
}
char *itostr31(const int &xx)
{
conv[0] = (xx >= 0) ? '+' : '-';
conv[1] = (xx / 1000) % 10 + '0';
conv[2] = (xx / 100) % 10 + '0';
conv[3] = (xx / 10) % 10 + '0';
conv[4] = '.';
conv[5] = (xx) % 10 + '0';
conv[6] = 0;
return conv;
}
// Convert int to rj string with 123 or -12 format
char *itostr3(const int &x)
{
int xx = x;
if (xx < 0) {
conv[0] = '-';
xx = -xx;
} else if (xx >= 100)
conv[0] = (xx / 100) % 10 + '0';
else
conv[0] = ' ';
if (xx >= 10)
conv[1] = (xx / 10) % 10 + '0';
else
conv[1] = ' ';
conv[2] = (xx) % 10 + '0';
conv[3] = 0;
return conv;
}
// Convert int to lj string with 123 format
char *itostr3left(const int &xx)
{
if (xx >= 100)
{
conv[0] = (xx / 100) % 10 + '0';
conv[1] = (xx / 10) % 10 + '0';
conv[2] = (xx) % 10 + '0';
conv[3] = 0;
}
else if (xx >= 10)
{
conv[0] = (xx / 10) % 10 + '0';
conv[1] = (xx) % 10 + '0';
conv[2] = 0;
}
else
{
conv[0] = (xx) % 10 + '0';
conv[1] = 0;
}
return conv;
}
// Convert int to rj string with 1234 format
char *itostr4(const int &xx) {
conv[0] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' ';
conv[1] = xx >= 100 ? (xx / 100) % 10 + '0' : ' ';
conv[2] = xx >= 10 ? (xx / 10) % 10 + '0' : ' ';
conv[3] = xx % 10 + '0';
conv[4] = 0;
return conv;
}
// Convert float to rj string with 12345 format
char *ftostr5(const float &x) {
long xx = abs(x);
conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' ';
conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' ';
conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : ' ';
conv[3] = xx >= 10 ? (xx / 10) % 10 + '0' : ' ';
conv[4] = xx % 10 + '0';
conv[5] = 0;
return conv;
}
// Convert float to string with +1234.5 format
char *ftostr51(const float &x)
{
long xx = x * 10;
conv[0] = (xx >= 0) ? '+' : '-';
xx = abs(xx);
conv[1] = (xx / 10000) % 10 + '0';
conv[2] = (xx / 1000) % 10 + '0';
conv[3] = (xx / 100) % 10 + '0';
conv[4] = (xx / 10) % 10 + '0';
conv[5] = '.';
conv[6] = (xx) % 10 + '0';
conv[7] = 0;
return conv;
}
// Convert float to string with +123.45 format
char *ftostr52(const float &x)
{
long xx = x * 100;
conv[0] = (xx >= 0) ? '+' : '-';
xx = abs(xx);
conv[1] = (xx / 10000) % 10 + '0';
conv[2] = (xx / 1000) % 10 + '0';
conv[3] = (xx / 100) % 10 + '0';
conv[4] = '.';
conv[5] = (xx / 10) % 10 + '0';
conv[6] = (xx) % 10 + '0';
conv[7] = 0;
return conv;
}

28
Firmware/conv2str.h Normal file
View File

@ -0,0 +1,28 @@
//conv2str.h - Float conversion utilities
#ifndef _CONV2STR_H
#define _CONV2STR_H
#include <inttypes.h>
char *itostr2(const uint8_t &x);
char *itostr31(const int &xx);
char *itostr3(const int &xx);
char *itostr3left(const int &xx);
char *itostr4(const int &xx);
char *ftostr3(const float &x);
char *ftostr31ns(const float &x); // float to string without sign character
char *ftostr31(const float &x);
char *ftostr32(const float &x);
char *ftostr32ns(const float &x);
char *ftostr43(const float &x, uint8_t offset = 0);
char *ftostr12ns(const float &x);
char *ftostr13ns(const float &x);
char *ftostr32sp(const float &x); // remove zero-padding from ftostr32
char *ftostr5(const float &x);
char *ftostr51(const float &x);
char *ftostr52(const float &x);
#endif //_CONV2STR_H

View File

@ -8,69 +8,98 @@
#include <avr/eeprom.h>
#include <stdint.h>
#include "language.h"
#if 0
template <typename T>
static T eeprom_read(T *address);
template<>
char eeprom_read<char>(char *address)
{
return eeprom_read_byte(reinterpret_cast<uint8_t*>(address));
}
#endif
template <typename T>
static void eeprom_write(T *address, T value);
template<>
void eeprom_write<char>(char *addres, char value)
{
eeprom_write_byte(reinterpret_cast<uint8_t*>(addres), static_cast<uint8_t>(value));
}
template <typename T>
static bool eeprom_is_uninitialized(T *address);
template <>
bool eeprom_is_uninitialized<char>(char *address)
{
return (0xff == eeprom_read_byte(reinterpret_cast<uint8_t*>(address)));
}
bool eeprom_is_sheet_initialized(uint8_t sheet_num)
{
return (0xffff != eeprom_read_word(reinterpret_cast<uint16_t*>(&(EEPROM_Sheets_base->
s[sheet_num].z_offset))));
}
void eeprom_init()
{
eeprom_init_default_byte((uint8_t*)EEPROM_POWER_COUNT, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_CRASH_COUNT_X, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_CRASH_COUNT_Y, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_FERROR_COUNT, 0);
eeprom_init_default_word((uint16_t*)EEPROM_POWER_COUNT_TOT, 0);
eeprom_init_default_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT, 0);
eeprom_init_default_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT, 0);
eeprom_init_default_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_POWER_COUNT, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_CRASH_COUNT_X, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_CRASH_COUNT_Y, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_FERROR_COUNT, 0);
if (eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_POWER_COUNT_TOT, 0);
if (eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT, 0);
if (eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT, 0);
if (eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, 0);
eeprom_init_default_word((uint16_t*)EEPROM_MMU_FAIL_TOT, 0);
eeprom_init_default_word((uint16_t*)EEPROM_MMU_LOAD_FAIL_TOT, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_MMU_FAIL, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL, 0);
eeprom_init_default_dword((uint32_t*)EEPROM_MMU_MATERIAL_CHANGES, 0);
if (eeprom_read_word((uint16_t*)EEPROM_MMU_FAIL_TOT) == 0xffff) eeprom_update_word((uint16_t *)EEPROM_MMU_FAIL_TOT, 0);
if (eeprom_read_word((uint16_t*)EEPROM_MMU_LOAD_FAIL_TOT) == 0xffff) eeprom_update_word((uint16_t *)EEPROM_MMU_LOAD_FAIL_TOT, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_MMU_FAIL) == 0xff) eeprom_update_byte((uint8_t *)EEPROM_MMU_FAIL, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL) == 0xff) eeprom_update_byte((uint8_t *)EEPROM_MMU_LOAD_FAIL, 0);
if (eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)) == EEPROM_EMPTY_VALUE)
{
eeprom_update_byte_notify(&(EEPROM_Sheets_base->active_sheet), 0);
eeprom_update_byte(&(EEPROM_Sheets_base->active_sheet), 0);
// When upgrading from version older version (before multiple sheets were implemented in v3.8.0)
// Sheet 1 uses the previous Live adjust Z (@EEPROM_BABYSTEP_Z)
int last_babystep = eeprom_read_word((uint16_t *)EEPROM_BABYSTEP_Z);
eeprom_update_word(reinterpret_cast<uint16_t *>(&(EEPROM_Sheets_base->s[0].z_offset)), last_babystep);
}
for (uint_least8_t i = 0; i < (sizeof(Sheets::s)/sizeof(Sheets::s[0])); ++i)
{
bool is_uninitialized = true;
for (uint_least8_t j = 0; j < (sizeof(Sheet::name)/sizeof(Sheet::name[0])); ++j)
{
if (!eeprom_is_uninitialized(&(EEPROM_Sheets_base->s[i].name[j]))) is_uninitialized = false;
}
if(is_uninitialized)
{
SheetName sheetName;
eeprom_default_sheet_name(i,sheetName);
// initialize the sheet names in eeprom
for (uint_least8_t i = 0; i < (sizeof(Sheets::s)/sizeof(Sheets::s[0])); i++) {
SheetName sheetName;
eeprom_default_sheet_name(i, sheetName);
eeprom_init_default_block(EEPROM_Sheets_base->s[i].name, (sizeof(Sheet::name)/sizeof(Sheet::name[0])), sheetName.c);
for (uint_least8_t a = 0; a < sizeof(Sheet::name); ++a){
eeprom_write(&(EEPROM_Sheets_base->s[i].name[a]), sheetName.c[a]);
}
}
}
if(!eeprom_is_sheet_initialized(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet))))
{
eeprom_switch_to_next_sheet();
}
check_babystep();
// initialize custom mendel name in eeprom
if (eeprom_read_byte((uint8_t*)EEPROM_CUSTOM_MENDEL_NAME) == EEPROM_EMPTY_VALUE) {
//SERIAL_ECHOLN("Init Custom Mendel Name");
eeprom_update_block_notify(CUSTOM_MENDEL_NAME, (uint8_t*)EEPROM_CUSTOM_MENDEL_NAME, sizeof(CUSTOM_MENDEL_NAME));
} //else SERIAL_ECHOLN("Found Custom Mendel Name");
#ifdef PINDA_TEMP_COMP
eeprom_init_default_byte((uint8_t*)EEPROM_PINDA_TEMP_COMPENSATION, 0);
if (eeprom_read_byte((uint8_t*)EEPROM_PINDA_TEMP_COMPENSATION) == 0xff) eeprom_update_byte((uint8_t *)EEPROM_PINDA_TEMP_COMPENSATION, 0);
#endif //PINDA_TEMP_COMP
eeprom_init_default_dword((uint32_t*)EEPROM_JOB_ID, 0);
eeprom_init_default_dword((uint32_t*)EEPROM_TOTALTIME, 0);
eeprom_init_default_dword((uint32_t*)EEPROM_FILAMENTUSED, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, 0);
eeprom_init_default_byte((uint8_t*)EEPROM_HEAT_BED_ON_LOAD_FILAMENT, 1);
}
void eeprom_adjust_bed_reset() {
eeprom_update_byte_notify((uint8_t*)EEPROM_BED_CORRECTION_VALID, 1);
eeprom_update_byte_notify((uint8_t*)EEPROM_BED_CORRECTION_LEFT, 0);
eeprom_update_byte_notify((uint8_t*)EEPROM_BED_CORRECTION_RIGHT, 0);
eeprom_update_byte_notify((uint8_t*)EEPROM_BED_CORRECTION_FRONT, 0);
eeprom_update_byte_notify((uint8_t*)EEPROM_BED_CORRECTION_REAR, 0);
if (eeprom_read_dword((uint32_t*)EEPROM_JOB_ID) == EEPROM_EMPTY_VALUE32)
eeprom_update_dword((uint32_t*)EEPROM_JOB_ID, 0);
}
//! @brief Get default sheet name for index
@ -81,8 +110,8 @@ void eeprom_adjust_bed_reset() {
//! | 1 | Smooth2 |
//! | 2 | Textur1 |
//! | 3 | Textur2 |
//! | 4 | Satin |
//! | 5 | NylonPA |
//! | 4 | Satin 1 |
//! | 5 | Satin 2 |
//! | 6 | Custom1 |
//! | 7 | Custom2 |
//!
@ -100,23 +129,17 @@ void eeprom_default_sheet_name(uint8_t index, SheetName &sheetName)
{
strcpy_P(sheetName.c, PSTR("Textur"));
}
else if (index < 5)
{
strcpy_P(sheetName.c, PSTR("Satin "));
}
else if (index < 6)
{
strcpy_P(sheetName.c, PSTR("NylonPA"));
strcpy_P(sheetName.c, PSTR("Satin "));
}
else
{
strcpy_P(sheetName.c, PSTR("Custom"));
}
if (index <4 || index >5)
{
sheetName.c[6] = '0' + ((index % 2)+1);
sheetName.c[7] = '\0';
}
sheetName.c[6] = '0' + ((index % 2)+1);
sheetName.c[7] = '\0';
}
//! @brief Get next initialized sheet
@ -137,267 +160,10 @@ int8_t eeprom_next_initialized_sheet(int8_t sheet)
return -1;
}
#ifdef DEBUG_EEPROM_CHANGES
static void eeprom_byte_notify(uint8_t *dst, uint8_t previous_value, uint8_t value, bool write) {
printf_P(PSTR("EEPROMChng b %s %u %d -> %d\n"), write ? "write":"", dst , previous_value, value);
}
static void eeprom_word_notify(uint16_t *dst, uint16_t previous_value, uint16_t value, bool write) {
printf_P(PSTR("EEPROMChng w %s %u %u -> %u\n"), write ? "write":"", dst , previous_value, value);
}
static void eeprom_dword_notify(uint32_t *dst, uint32_t previous_value, uint32_t value, bool write) {
printf_P(PSTR("EEPROMChng d %s %u %x -> %x\n"), write ? "write":"", reinterpret_cast<const uint16_t>(dst) , previous_value, value);
}
static void eeprom_float_notify(float *dst, float previous_value, float value, bool write) {
printf_P(PSTR("EEPROMChng f %s %u %f -> %f\n"), write ? "write":"", reinterpret_cast<const uint16_t>(dst) , previous_value, value);
}
static void eeprom_block_notify(void *dst, const uint8_t *previous_values, const uint8_t *values, size_t size, bool write) {
for(size_t i = 0; i < size; ++i){
if (previous_values[i] != values[i] || write) {
printf_P(PSTR("EEPROMChng bl %s %u %x -> %x\n"), write ? "write":"", reinterpret_cast<const uint16_t>(dst) + i, previous_values[i], values[i]);
}
}
}
#endif //DEBUG_EEPROM_CHANGES
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_write_byte_notify(uint8_t *dst, uint8_t value){
#else
void eeprom_write_byte_notify(uint8_t *dst, uint8_t value, bool active){
if (active) {
uint8_t previous_value = eeprom_read_byte(dst);
eeprom_byte_notify(dst, previous_value, value, true);
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_write_byte(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_update_byte_notify(uint8_t *dst, uint8_t value){
#else
void eeprom_update_byte_notify(uint8_t *dst, uint8_t value, bool active){
if (active) {
uint8_t previous_value = eeprom_read_byte(dst);
if (previous_value != value) {
eeprom_byte_notify(dst, previous_value, value, false);
}
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_update_byte(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_write_word_notify(uint16_t *dst, uint16_t value){
#else
void eeprom_write_word_notify(uint16_t *dst, uint16_t value, bool active){
if (active) {
uint16_t previous_value = eeprom_read_word(dst);
eeprom_word_notify(dst, previous_value, value, true);
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_write_word(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_update_word_notify(uint16_t *dst, uint16_t value){
#else
void eeprom_update_word_notify(uint16_t *dst, uint16_t value, bool active){
if (active) {
uint16_t previous_value = eeprom_read_word(dst);
if (previous_value != value) {
eeprom_word_notify(dst, previous_value, value, false);
}
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_update_word(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_write_dword_notify(uint32_t *dst, uint32_t value){
#else
void eeprom_write_dword_notify(uint32_t *dst, uint32_t value, bool active){
if (active) {
uint32_t previous_value = eeprom_read_dword(dst);
eeprom_dword_notify(dst, previous_value, value, true);
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_write_dword(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_update_dword_notify(uint32_t *dst, uint32_t value){
#else
void eeprom_update_dword_notify(uint32_t *dst, uint32_t value, bool active){
if (active) {
uint32_t previous_value = eeprom_read_dword(dst);
if (previous_value != value) {
eeprom_dword_notify(dst, previous_value, value, false);
}
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_update_dword(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_write_float_notify(float *dst, float value){
#else
void eeprom_write_float_notify(float *dst, float value, bool active){
if (active) {
float previous_value = eeprom_read_float(dst);
eeprom_float_notify(dst, previous_value, value, true);
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_write_float(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_update_float_notify(float *dst, float value){
#else
void eeprom_update_float_notify(float *dst, float value, bool active){
if (active) {
float previous_value = eeprom_read_float(dst);
if (previous_value != value) {
eeprom_float_notify(dst, previous_value, value, false);
}
}
#endif //DEBUG_EEPROM_CHANGES
eeprom_update_float(dst, value);
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_write_block_notify(const void *__src, void *__dst, size_t __n){
eeprom_write_block(__src, __dst, __n);
#else
void eeprom_write_block_notify(const void *__src, void *__dst, size_t __n, bool active){
if (active) {
uint8_t previous_values[__n];
uint8_t new_values[__n];
eeprom_read_block(previous_values, __dst, __n);
eeprom_write_block(__src, __dst, __n);
eeprom_read_block(new_values, __dst, __n);
eeprom_block_notify(__dst, previous_values, new_values, __n, true);
}
#endif //DEBUG_EEPROM_CHANGES
}
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_update_block_notify(const void *__src, void *__dst, size_t __n){
eeprom_update_block(__src, __dst, __n);
#else
void eeprom_update_block_notify(const void *__src, void *__dst, size_t __n, bool active){
if (active) {
uint8_t previous_values[__n];
uint8_t new_values[__n];
eeprom_read_block(previous_values, __dst, __n);
eeprom_update_block(__src, __dst, __n);
eeprom_read_block(new_values, __dst, __n);
eeprom_block_notify(__dst, previous_values, new_values, __n, false);
}
#endif //DEBUG_EEPROM_CHANGES
}
void eeprom_switch_to_next_sheet()
{
int8_t sheet = eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet));
sheet = eeprom_next_initialized_sheet(sheet);
if (sheet >= 0) eeprom_update_byte_notify(&(EEPROM_Sheets_base->active_sheet), sheet);
}
bool __attribute__((noinline)) eeprom_is_sheet_initialized(uint8_t sheet_num) {
return (eeprom_read_word(reinterpret_cast<uint16_t*>(&(EEPROM_Sheets_base->s[sheet_num].z_offset))) != EEPROM_EMPTY_VALUE16);
}
bool __attribute__((noinline)) eeprom_is_initialized_block(const void *__p, size_t __n) {
const uint8_t *p = (const uint8_t*)__p;
while (__n--) {
if (eeprom_read_byte(p++) != EEPROM_EMPTY_VALUE)
return true;
}
return false;
}
void eeprom_update_block_P(const void *__src, void *__dst, size_t __n) {
const uint8_t *src = (const uint8_t*)__src;
uint8_t *dst = (uint8_t*)__dst;
while (__n--) {
eeprom_update_byte_notify(dst++, pgm_read_byte(src++));
}
}
void eeprom_toggle(uint8_t *__p) {
eeprom_write_byte_notify(__p, !eeprom_read_byte(__p));
}
void __attribute__((noinline)) eeprom_increment_byte(uint8_t *__p) {
eeprom_write_byte_notify(__p, eeprom_read_byte(__p) + 1);
}
void __attribute__((noinline)) eeprom_increment_word(uint16_t *__p) {
eeprom_write_word_notify(__p, eeprom_read_word(__p) + 1);
}
void __attribute__((noinline)) eeprom_increment_dword(uint32_t *__p) {
eeprom_write_dword_notify(__p, eeprom_read_dword(__p) + 1);
}
void __attribute__((noinline)) eeprom_add_byte(uint8_t *__p, uint8_t add) {
eeprom_write_byte_notify(__p, eeprom_read_byte(__p) + add);
}
void __attribute__((noinline)) eeprom_add_word(uint16_t *__p, uint16_t add) {
eeprom_write_word_notify(__p, eeprom_read_word(__p) + add);
}
void __attribute__((noinline)) eeprom_add_dword(uint32_t *__p, uint32_t add) {
eeprom_write_dword_notify(__p, eeprom_read_dword(__p) + add);
}
uint8_t __attribute__((noinline)) eeprom_init_default_byte(uint8_t *__p, uint8_t def) {
uint8_t val = eeprom_read_byte(__p);
if (val == EEPROM_EMPTY_VALUE) {
eeprom_write_byte_notify(__p, def);
return def;
}
return val;
}
uint16_t __attribute__((noinline)) eeprom_init_default_word(uint16_t *__p, uint16_t def) {
uint16_t val = eeprom_read_word(__p);
if (val == EEPROM_EMPTY_VALUE16) {
eeprom_write_word_notify(__p, def);
return def;
}
return val;
}
uint32_t __attribute__((noinline)) eeprom_init_default_dword(uint32_t *__p, uint32_t def) {
uint32_t val = eeprom_read_dword(__p);
if (val == EEPROM_EMPTY_VALUE32) {
eeprom_write_dword_notify(__p, def);
return def;
}
return val;
}
void __attribute__((noinline)) eeprom_init_default_float(float *__p, float def) {
if (eeprom_read_dword((uint32_t*)__p) == EEPROM_EMPTY_VALUE32)
eeprom_write_float_notify(__p, def);
}
void __attribute__((noinline)) eeprom_init_default_block(void *__p, size_t __n, const void *def) {
if (!eeprom_is_initialized_block(__p, __n))
eeprom_update_block_notify(def, __p, __n);
}
void __attribute__((noinline)) eeprom_init_default_block_P(void *__p, size_t __n, const void *def) {
if (!eeprom_is_initialized_block(__p, __n))
eeprom_update_block_P(def, __p, __n);
if (sheet >= 0) eeprom_update_byte(&(EEPROM_Sheets_base->active_sheet), sheet);
}

View File

@ -4,7 +4,7 @@
* @author 3d-gussner
*/
/** \ingroup eeprom_table */
//! _This is a EEPROM table of currently implemented in Prusa firmware (dynamically generated from doxygen)._
@ -12,27 +12,16 @@
#define EEPROM_H
#include <stdint.h>
#include <stddef.h>
#include "Configuration_var.h"
// Custom Mendel Name
#ifndef CUSTOM_MENDEL_NAME
#define CUSTOM_MENDEL_NAME "Prusa i3"
#endif
#define MAX_CUSTOM_MENDEL_NAME_LENGTH 17
// Sheets
#define MAX_SHEETS 8
#define MAX_SHEET_NAME_LENGTH 7
typedef struct
{
unsigned char name[MAX_SHEET_NAME_LENGTH]; //!< Can be null terminated, doesn't need to be null terminated
char name[MAX_SHEET_NAME_LENGTH]; //!< Can be null terminated, doesn't need to be null terminated
int16_t z_offset; //!< Z_BABYSTEP_MIN .. Z_BABYSTEP_MAX = Z_BABYSTEP_MIN*2/1000 [mm] .. Z_BABYSTEP_MAX*2/1000 [mm]
uint8_t bed_temp; //!< 0 .. 254 [°C] NOTE: currently only written-to and never used
uint8_t pinda_temp; //!< 0 .. 254 [°C] NOTE: currently only written-to and never used
uint8_t bed_temp; //!< 0 .. 254 [°C]
uint8_t pinda_temp; //!< 0 .. 254 [°C]
} Sheet;
typedef struct
@ -48,29 +37,29 @@ typedef struct
static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEPROM_SHEETS_SIZEOF.");
#endif
/** @defgroup eeprom_table EEPROM Table
*
*
---------------------------------------------------------------------------------
EEPROM 8-bit Empty value = 0xFFh 255
EEPROM 16-bit Empty value = 0xFFFFh 65535
_Italic = unused or default_
__Bold = Status__
In Default/FactoryReset column the
- __L__ Language
- __S__ Statistics
- __P__ Shipping prep
- __M__ Service/Maintenance prep
- __S/P__ Statistics and Shipping prep
In Default/FactoryReset column the
- __L__ Language
- __S__ Statistics
- __P__ Shipping prep
- __M__ Service/Maintenance prep
- __S/P__ Statistics and Shipping prep
will overwrite existing values to 0 or default.
A FactoryReset All Data will overwrite the whole EEPROM with ffh and some values will be initialized automatically,
others need a reset / reboot.
---------------------------------------------------------------------------------
How can you use the debug codes?
- Serial terminal like Putty.
@ -78,355 +67,282 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
- _Pronterface_ does __not__ support D-codes
### !!! D-codes are case sensitive so please don't use upper case A,C or X in the address you want to read !!!
#### Useful tools/links:
To convert hex to ascii https://www.rapidtables.com/convert/number/hex-to-ascii.html
To convert hex to dec https://www.rapidtables.com/convert/number/hex-to-decimal.html
Version: 3.14.1
To convert hex to ascii https://www.rapidtables.com/convert/number/hex-to-ascii.html
To convert hex to dec https://www.rapidtables.com/convert/number/hex-to-decimal.html
Version: 1.0.1
---------------------------------------------------------------------------------
| Address begin | Bit/Type | Name | Valid values | Default/FactoryReset | Description | Gcode/Function| Debug code
| :-- | :-- | :-- | :--: | :--: | :-- | :--: | :--:
| 0x0FFFh 4095 | uchar | EEPROM_SILENT | 00h 0 | ffh 255 | TMC Stealth mode: __off__ / miniRambo Power mode | LCD menu | D3 Ax0fff C1
| ^ | ^ | ^ | 01h 1 | ^ | TMC Stealth mode: __on__ / miniRambo Silent mode | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | miniRambo Auto mode | ^ | ^
| 0x0FFEh 4094 | uchar | EEPROM_LANG | 00h 0 | ffh 255 __L__ | English / LANG_ID_PRI | LCD menu | D3 Ax0ffe C1
| ^ | ^ | ^ | 01h 1 | ^ | Other language LANG_ID_SEC | ^ | ^
| 0x0FFCh 4092 | uint16 | EEPROM_BABYSTEP_X | ??? | ff ffh 65535 | Babystep for X axis _unsued_ | ??? | D3 Ax0ffc C2
| 0x0FFAh 4090 | uint16 | EEPROM_BABYSTEP_Y | ??? | ff ffh 65535 | Babystep for Y axis _unsued_ | ^ | D3 Ax0ffa C2
| 0x0FF8h 4088 | uint16 | EEPROM_BABYSTEP_Z | ??? | ff ffh 65535 | Babystep for Z axis _lagacy_ | ^ | D3 Ax0ff8 C2
| ^ | ^ | ^ | ^ | ^ | multiple values stored now in EEPROM_Sheets_base | ^ | ^
| 0x0FF7h 4087 | uint8 | EEPROM_CALIBRATION_STATUS | ffh 255 | ffh 255 | Assembled _default_ | ??? | D3 Ax0ff7 C1
| ^ | ^ | ^ | 01h 1 | ^ | Calibrated | ^ | ^
| ^ | ^ | ^ | e6h 230 | ^ | needs Live Z adjustment | ^ | ^
| ^ | ^ | ^ | f0h 240 | ^ __P__ | needs Z calibration | ^ | ^
| ^ | ^ | ^ | fah 250 | ^ | needs XYZ calibration | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Unknown | ^ | ^
| 0x0FF5h 4085 | uint16 | EEPROM_BABYSTEP_Z0 | ??? | ff ffh 65535 | Babystep for Z ??? | ??? | D3 Ax0ff5 C2
| 0x0FF1h 4081 | uint32 | EEPROM_FILAMENTUSED | ??? | 00 00 00 00h 0 __S/P__| Filament used in meters | ??? | D3 Ax0ff1 C4
| 0x0FEDh 4077 | uint32 | EEPROM_TOTALTIME | ??? | 00 00 00 00h 0 __S/P__| Total print time | ??? | D3 Ax0fed C4
| 0x0FE5h 4069 | float | EEPROM_BED_CALIBRATION_CENTER | ??? | ff ff ff ffh | ??? | ??? | D3 Ax0fe5 C8
| 0x0FDDh 4061 | float | EEPROM_BED_CALIBRATION_VEC_X | ??? | ff ff ff ffh | ??? | ??? | D3 Ax0fdd C8
| 0x0FD5h 4053 | float | EEPROM_BED_CALIBRATION_VEC_Y | ??? | ff ff ff ffh | ??? | ??? | D3 Ax0fd5 C8
| 0x0FC5h 4037 | int16 | EEPROM_BED_CALIBRATION_Z_JITTER | ??? | ff ffh 65535 | ??? | ??? | D3 Ax0fc5 C16
| 0x0FC4h 4036 | bool | EEPROM_FARM_MODE | 00h 0 | ffh 255 __P__ | Prusa farm mode: __off__ | G99 | D3 Ax0fc4 C1
| ^ | ^ | ^ | 01h 1 | ^ | Prusa farm mode: __on__ | G98 | ^
| 0x0FC3h 4035 | free | _EEPROM_FREE_NR1_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0fc3 C1
| 0x0FC1h 4033 | ??? | EEPROM_FARM_NUMBER | 000-999 | ff ffh / 000 __P__ | Prusa farm number _only 0-9 are allowed: 000-999_ | LCD menu | D3 Ax0fc1 C2
| 0x0FC0h 4032 | bool | EEPROM_BED_CORRECTION_VALID | 00h 0 | 00h 0 | Bed correction invalid | ??? | D3 Ax0fc0 C1
| ^ | ^ | ^ | ffh 255 | | Bed correction valid | ??? | ^
| 0x0FBFh 4031 | char | EEPROM_BED_CORRECTION_LEFT | 00h ffh | 00h 0 | Bed manual correction left | LCD menu | D3 Ax0fbf C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Lxxx | ^
| 0x0FBEh 4030 | char | EEPROM_BED_CORRECTION_RIGHT | 00h ffh | 00h 0 | Bed manual correction right | LCD menu | D3 Ax0fbe C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Rxxx | ^
| 0x0FBDh 4029 | char | EEPROM_BED_CORRECTION_FRONT | 00h ffh | 00h 0 | Bed manual correction front | LCD menu | D3 Ax0fbd C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Fxxx | ^
| 0x0FBCh 4028 | char | EEPROM_BED_CORRECTION_BACK | 00h ffh | 00h 0 | Bed manual correction back | LCD menu | D3 Ax0fbc C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Bxxx | ^
| 0x0FBBh 4027 | bool | EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY | 00h 0 | ffh 255 | Toshiba Air: __off__ | LCD menu | D3 Ax0fbb C1
| ^ | ^ | ^ | 01h 1 | ^ | Toshiba Air: __on__ | ^ | ^
| 0x0FBAh 4026 | uchar | EEPROM_PRINT_FLAG | ??? | ??? | _unsued_ | ??? | D3 Ax0fba C1
| 0x0FB0h 4016 | int16 | EEPROM_PROBE_TEMP_SHIFT | ??? | ??? | ??? | ??? | D3 Ax0fb0 C10
| 0x0FAFh 4015 | bool | EEPROM_TEMP_CAL_ACTIVE | 00h 0 | 00h 0 | PINDA Temp cal.: __inactive__ | LCD menu | D3 Ax0faf C1
| ^ | ^ | ^ | ffh 255 | ^ | PINDA Temp cal.: __active__ | ^ | ^
| 0x0FA7h 4007 | uint32 | EEPROM_BOWDEN_LENGTH | ??? | ff 00 00 00h | Bowden length | ??? | D3 Ax0fae C8
| ^ | ^ | ^ | ^ | 00 00 00 00h | ^ | ^ | ^
| 0x0FA6h 4006 | uint8 | EEPROM_CALIBRATION_STATUS_PINDA | 00h 0 | ffh 255 | PINDA Temp: __not calibrated__ | ??? | D3 Ax0fa6 C1
| ^ | ^ | ^ | 01h 1 | ^ | PINDA Temp: __calibrated__ | ^ | ^
| 0x0FA5h 4005 | uint8 | EEPROM_UVLO | 00h 0 | ffh 255 | Power Panic flag: __inactive__ | ??? | D3 Ax0fa5 C1
| ^ | ^ | ^ | 01h 1 | ^ | Power Panic flag: __active__ | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | Power Panic flag: __???__ | ^ | ^
| 0x0F9Dh 3997 | float | EEPROM_UVLO_CURRENT_POSITION | ??? | ffh 255 | Power Panic position | ??? | D3 Ax0f9d C8
| 0x0F95h 3989 | char | EEPROM_FILENAME | ??? | ffh 255 | Power Panic Filename | ??? | D3 Ax0f95 C8
| 0x0F91h 3985 | uint32 | EEPROM_FILE_POSITION | ??? | ff ff ff ffh | Power Panic File Position | ??? | D3 Ax0f91 C4
| 0x0F8Dh 3981 | float | EEPROM_UVLO_CURRENT_POSITION_Z | ??? | ff ff ff ffh | Power Panic Z Position | ^ | D3 Ax0f8d C4
| 0x0F8Ch 3980 | ??? | EEPROM_UVLO_UNUSED_001 | ??? | ffh 255 | Power Panic _unused_ | ^ | D3 Ax0f8c C1
| 0x0F8Bh 3979 | uint8 | EEPROM_UVLO_TARGET_BED | ??? | ffh 255 | Power Panic Bed temperature | ^ | D3 Ax0f8b C1
| 0x0F89h 3977 | uint16 | EEPROM_UVLO_FEEDRATE | ??? | ff ffh 65535 | Power Panic Feedrate | ^ | D3 Ax0f89 C2
| 0x0F88h 3976 | uint8 | EEPROM_UVLO_FAN_SPEED | ??? | ffh 255 | Power Panic Fan speed | ^ | D3 Ax0f88 C1
| 0x0F87h 3975 | uint8 | EEPROM_FAN_CHECK_ENABLED | 00h 0 | ??? | Fan Check __disabled__ | LCD menu | D3 Ax0f87 C1
| ^ | ^ | ^ | 01h 1 | ffh 255 | Fan Check __enabled__ | ^ | ^
| 0x0F75h 3957 | uint16 | EEPROM_UVLO_MESH_BED_LEVELING | ??? | ff ffh 65535 | Power Panic Mesh Bed Leveling | ??? | D3 Ax0f75 C18
| 0x0F73h 3955 | uint16 | EEPROM_UVLO_Z_MICROSTEPS | ??? | ff ffh 65535 | Power Panic Z microsteps | ??? | D3 Ax0f73 C2
| 0x0F72h 3954 | uint8 | EEPROM_UVLO_E_ABS | ??? | ffh 255 | Power Panic ??? position | ??? | D3 Ax0f72 C1
| 0x0F6Eh 3950 | foat | EEPROM_UVLO_CURRENT_POSITION_E | ??? | ff ff ff ffh | Power Panic E position | ??? | D3 Ax0f6e C4
| 0x0F6Dh 3949 | ??? | _EEPROM_FREE_NR2_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0f6d C1
| 0x0F6Ch 3948 | ??? | _EEPROM_FREE_NR3_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0f6c C1
| 0x0F6Bh 3947 | ??? | _EEPROM_FREE_NR4_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0f6b C1
| 0x0F6Ah 3946 | ??? | _EEPROM_FREE_NR5_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0f6a C1
| 0x0F69h 3945 | uint8 | EEPROM_CRASH_DET | ffh 255 | ffh 255 | Crash detection: __enabled__ | LCD menu | D3 Ax0f69 C1
| ^ | ^ | ^ | 00h 0 | ^ | Crash detection: __disabled__ | LCD menu | ^
| 0x0F68h 3944 | uint8 | EEPROM_CRASH_COUNT_Y | 00h-ffh 0-255 | ffh 255 __S/P__ | Crashes detected on y axis | ??? | D3 Ax0f68 C1
| 0x0F67h 3943 | uint8 | EEPROM_FSENSOR | 01h 1 | ffh 255 __P__ | Filament sensor: __enabled__ | LCD menu | D3 Ax0f67 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament sensor: __disabled__ | LCD menu | ^
| 0x0F65h 3942 | uint8 | EEPROM_CRASH_COUNT_X | 00h-ffh 0-255 | ffh 255 __S/P__ | Crashes detected on x axis | ??? | D3 Ax0f66 C1
| 0x0F65h 3941 | uint8 | EEPROM_FERROR_COUNT | 00h-ffh 0-255 | ffh 255 __S/P__ | Filament sensor error counter | ??? | D3 Ax0f65 C1
| 0x0F64h 3940 | uint8 | EEPROM_POWER_COUNT | 00h-ffh 0-255 | ffh 255 __S/P__ | Power failure counter | ??? | D3 Ax0f64 C1
| 0x0F60h 3936 | float | EEPROM_XYZ_CAL_SKEW | ??? | ff ff ff ffh | XYZ skew value | ??? | D3 Ax0f60 C4
| 0x0F5Fh 3935 | uint8 | EEPROM_WIZARD_ACTIVE | 01h 1 | 01h 1 __P__ | Wizard __active__ | ??? | D3 Ax0f5f C1
| ^ | ^ | ^ | 00h 0 | ^ | Wizard __inactive__ | ^ | ^
| ^ | ^ | ^ | 02h 2 | 02h 2 __M__ | Wizard active - Z cal after shipping/service prep | ^ | ^
| 0x0F5Dh 3933 | uint16 | EEPROM_BELTSTATUS_X | ??? | ff ffh | X Beltstatus | ??? | D3 Ax0f5d C2
| 0x0F5Bh 3931 | uint16 | EEPROM_BELTSTATUS_Y | ??? | ff ffh | Y Beltstatus | ??? | D3 Ax0f5b C2
| 0x0F5Ah 3930 | uint8 | EEPROM_DIR_DEPTH | 00h-ffh 0-255 | ffh 255 | Directory depth | ??? | D3 Ax0f5a C1
| 0x0F0Ah 3850 | uint8 | EEPROM_DIRS | ??? | ffh 255 | Directories ??? | ??? | D3 Ax0f0a C80
| 0x0F09h 3849 | uint8 | EEPROM_SD_SORT | 00h 0 | ffh 255 | SD card sort by: __time__ | LCD menu | D3 Ax0f09 C1
| ^ | ^ | ^ | 01h 1 | ^ | SD card sort by: __alphabet__ | LCD menu | ^
| ^ | ^ | ^ | 02h 1 | ^ | SD card: __not sorted__ | LCD menu | ^
| 0x0F08h 3848 | uint8 | EEPROM_SECOND_SERIAL_ACTIVE | 00h 0 | ffh 255 | RPi Port: __disabled__ | LCD menu | D3 Ax0f08 C1
| ^ | ^ | ^ | 01h 1 | ^ | RPi Port: __enabled__ | LCD menu | ^
| 0x0F07h 3847 | uint8 | EEPROM_FSENS_AUTOLOAD_ENABLED | 01h 1 | ffh 255 __P__ | Filament autoload: __enabled__ | LCD menu | D3 Ax0f07 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament autoload: __disabled__ | LCD menu | ^
| 0x0F05h 3845 | uint16 | EEPROM_CRASH_COUNT_X_TOT | 0000-fffe | ff ffh __S/P__ | Total crashes on x axis | ??? | D3 Ax0f05 C2
| 0x0F03h 3843 | uint16 | EEPROM_CRASH_COUNT_Y_TOT | 0000-fffe | ff ffh __S/P__ | Total crashes on y axis | ??? | D3 Ax0f03 C2
| 0x0F01h 3841 | uint16 | EEPROM_FERROR_COUNT_TOT | 0000-fffe | ff ffh __S/P__ | Total filament sensor errors | ??? | D3 Ax0f01 C2
| 0x0EFFh 3839 | uint16 | EEPROM_POWER_COUNT_TOT | 0000-fffe | ff ffh __S/P__ | Total power failures | ??? | D3 Ax0eff C2
| 0x0EFEh 3838 | uint8 | EEPROM_TMC2130_HOME_X_ORIGIN | ??? | ffh 255 | ??? | ??? | D3 Ax0efe C1
| 0x0EFDh 3837 | uint8 | EEPROM MC2130_HOME_X_BSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0efd C1
| 0x0EFCh 3836 | uint8 | EEPROM_TMC2130_HOME_X_FSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0efc C1
| 0x0EFBh 3835 | uint8 | EEPROM_TMC2130_HOME_Y_ORIGIN | ??? | ffh 255 | ??? | ??? | D3 Ax0efb C1
| 0x0EFAh 3834 | uint8 | EEPROM_TMC2130_HOME_Y_BSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0efa C1
| 0x0EF9h 3833 | uint8 | EEPROM_TMC2130_HOME_Y_FSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0ef9 C1
| 0x0EF8h 3832 | uint8 | EEPROM_TMC2130_HOME_ENABLED | ??? | ffh 255 | ??? | ??? | D3 Ax0ef8 C1
| 0x0EF7h 3831 | uint8 | EEPROM_TMC2130_WAVE_X_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef7 C1
| 0x0EF6h 3830 | uint8 | EEPROM_TMC2130_WAVE_Y_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef6 C1
| 0x0EF5h 3829 | uint8 | EEPROM_TMC2130_WAVE_Z_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef5 C1
| 0x0EF4h 3828 | uint8 | EEPROM_TMC2130_WAVE_E_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef4 C1
| 0x0EF3h 3827 | uint8 | EEPROM_TMC2130_X_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef3 C1
| 0x0EF2h 3826 | uint8 | EEPROM_TMC2130_Y_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef2 C1
| 0x0EF1h 3825 | uint8 | EEPROM_TMC2130_Z_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef1 C1
| 0x0EF0h 3824 | uint8 | EEPROM_TMC2130_E_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef0 C1
| 0x0EEE 3822 | uint16 | EEPROM_PRINTER_TYPE | ??? | ff ffh 65535 | Printer Type | ??? | D3 Ax0eee C2
| ^ | ^ | ^ | 64 00h 100 | ^ | PRINTER_MK1 | ??? | ^
| ^ | ^ | ^ | c8 00h 200 | ^ | PRINTER_MK2 | ??? | ^
| ^ | ^ | ^ | c9 00h 201 | ^ | PRINTER_MK2 with MMU1 | ??? | ^
| ^ | ^ | ^ | ca 00h 202 | ^ | PRINTER_MK2S | ??? | ^
| ^ | ^ | ^ | cb 00h 203 | ^ | PRINTER_MK2S with MMU1 | ??? | ^
| ^ | ^ | ^ | fa 00h 250 | ^ | PRINTER_MK2.5 | ??? | ^
| ^ | ^ | ^ | 1a 4fh 20250 | ^ | PRINTER_MK2.5 with MMU2 | ??? | ^
| ^ | ^ | ^ | fc 00h 252 | ^ | PRINTER_MK2.5S | ??? | ^
| ^ | ^ | ^ | 1c 4fh 20252 | ^ | PRINTER_MK2.5S with MMU2S | ??? | ^
| ^ | ^ | ^ | 2c 01h 300 | ^ | PRINTER_MK3 | ??? | ^
| ^ | ^ | ^ | 4c 4fh 20300 | ^ | PRINTER_MK3 with MMU2 | ??? | ^
| ^ | ^ | ^ | 2e 01h 302 | ^ | PRINTER_MK3S | ??? | ^
| ^ | ^ | ^ | 4e 4fh 20302 | ^ | PRINTER_MK3S with MMU2S | ??? | ^
| 0x0EEC 3820 | uint16 | EEPROM_BOARD_TYPE | ??? | ff ffh 65535 | Board Type | ??? | D3 Ax0eec C2
| ^ | ^ | ^ | c8 00h 200 | ^ | BOARD_RAMBO_MINI_1_0 | ??? | ^
| ^ | ^ | ^ | cb 00h 203 | ^ | BOARD_RAMBO_MINI_1_3 | ??? | ^
| ^ | ^ | ^ | 36 01h 310 | ^ | BOARD_EINSY_1_0a | ??? | ^
| 0x0EE8 3816 | float | EEPROM_EXTRUDER_MULTIPLIER_0 | ??? | ff ff ff ffh | Power panic Extruder 0 multiplier | ??? | D3 Ax0ee8 C4
| 0x0EE4 3812 | float | EEPROM_EXTRUDER_MULTIPLIER_1 | ??? | ff ff ff ffh | Power panic Extruder 1 multiplier | ??? | D3 Ax0ee4 C4
| 0x0EE0 3808 | float | EEPROM_EXTRUDER_MULTIPLIER_2 | ??? | ff ff ff ffh | Power panic Extruder 2 multiplier | ??? | D3 Ax0ee0 C4
| 0x0EDE 3806 | uint16 | EEPROM_EXTRUDEMULTIPLY | ??? | ff ffh 65535 | Power panic Extruder multiplier | ??? | D3 Ax0ede C2
| 0x0EDA 3802 | float | EEPROM_UVLO_TINY_CURRENT_POSITION_Z | ??? | ff ff ff ffh | Power panic Z position | ??? | D3 Ax0eda C4
| 0x0ED8 3800 | uint16 | EEPROM_UVLO_TARGET_HOTEND | ??? | ff ffh 65535 | Power panic target Hotend temperature | ??? | D3 Ax0ed8 C2
| 0x0ED7 3799 | uint8 | EEPROM_SOUND_MODE | 00h 0 | ffh 255 | Sound mode: __loud__ | ??? | D3 Ax0ed7 C1
| ^ | ^ | ^ | 01h 1 | ^ | Sound mode: __once__ | ^ | ^
| ^ | ^ | ^ | 02h 1 | ^ | Sound mode: __silent__ | ^ | ^
| ^ | ^ | ^ | 03h 1 | ^ | Sound mode: __assist__ | ^ | ^
| 0x0ED6 3798 | bool | EEPROM_AUTO_DEPLETE | 01h 1 | ffh 255 | MMU2/s autodeplete: __on__ | ??? | D3 Ax0ed6 C1
| ^ | ^ | ^ | 00h 0 | ^ | MMU2/s autodeplete: __off__ | ^ | ^
| 0x0ED5 3797 | bool | EEPROM_FSENS_OQ_MEASS_ENABLED | ??? | ffh 255 | PAT1925 ??? | ??? | D3 Ax0ed5 C1
| ^ | ^ | ^ | ??? | ^ | PAT1925 ??? | ^ | ^
| 0x0ED3 3795 | uint16 | EEPROM_MMU_FAIL_TOT | ??? | ff ffh 65535 __S/P__ | MMU2/s total failures | ??? | D3 Ax0ed3 C2
| 0x0ED2 3794 | uint8 | EEPROM_MMU_FAIL | ??? | ffh 255 __S/P__ | MMU2/s fails during print | ??? | D3 Ax0ed2 C1
| 0x0ED0 3792 | uint16 | EEPROM_MMU_LOAD_FAIL_TOT | ??? | ff ffh 65535 __S/P__ | MMU2/s total load failures | ??? | D3 Ax0ed0 C2
| 0x0ECF 3791 | uint8 | EEPROM_MMU_LOAD_FAIL | ??? | ffh 255 __S/P__ | MMU2/s load failures during print | ??? | D3 Ax0ecf C1
| 0x0ECE 3790 | uint8 | EEPROM_MMU_CUTTER_ENABLED | 00h 0 | ffh 255 | MMU2/s cutter: __disabled__ | LCD menu | D3 Ax0ece C1
| ^ | ^ | ^ | 01h 1 | ^ | MMU2/s cutter: __enabled__ | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | MMU2/s cutter: __always__ | ^ | ^
| 0x0DAE 3502 | uint16 | EEPROM_UVLO_MESH_BED_LEVELING_FULL | ??? | ff ffh 65535 | Power panic Mesh bed leveling points | ??? | D3 Ax0dae C288
| 0x0DAD 3501 | uint8 | EEPROM_MBL_TYPE | ??? | ffh 255 | Mesh bed leveling precision _unused atm_ | ??? | D3 Ax0dad C1
| 0x0DAC 3500 | bool | EEPROM_MBL_MAGNET_ELIMINATION | 01h 1 | ffh 255 | Mesh bed leveling does: __ignores__ magnets | LCD menu | D3 Ax0dac C1
| ^ | ^ | ^ | 00h 0 | ^ | Mesh bed leveling does: __NOT ignores__ magnets | ^ | ^
| 0x0DAB 3499 | uint8 | EEPROM_MBL_POINTS_NR | 03h 3 | ffh 255 | Mesh bed leveling points: __3x3__ | LCD menu | D3 Ax0dab C1
| ^ | ^ | ^ | 07h 7 | ^ | Mesh bed leveling points: __7x7__ | ^ | ^
| 0x0DAA 3498 | uint8 | EEPROM_MBL_PROBE_NR | 03h 3 | ffh 255 | MBL times measurements for each point: __3__ | LCD menu | D3 Ax0daa C1
| ^ | ^ | ^ | 05h 5 | ^ | MBL times measurements for each point: __5__ | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | MBL times measurements for each point: __1__ | ^ | ^
| 0x0DA9 3497 | uint8 | EEPROM_MMU_STEALTH | 01h 1 | ffh 255 | MMU2/s Silent mode: __on__ | ??? | D3 Ax0da9 C1
| ^ | ^ | ^ | 00h 0 | ^ | MMU2/s Silent mode: __off__ | ^ | ^
| 0x0DA8 3496 | uint8 | EEPROM_CHECK_MODE | 01h 1 | ffh 255 | Check mode for nozzle is: __warn__ | LCD menu | D3 Ax0da8 C1
| ^ | ^ | ^ | 02h 0 | ^ | Check mode for nozzle is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for nozzle is: __none__ | ^ | ^
| 0x0DA7 3495 | uint8 | EEPROM_NOZZLE_DIAMETER | 28h 40 | ffh 255 | Nozzle diameter is: __40 or 0.40mm__ | LCD menu | D3 Ax0da7 C1
| ^ | ^ | ^ | 3ch 60 | ^ | Nozzle diameter is: __60 or 0.60mm__ | ^ | ^
| ^ | ^ | ^ | 3ch 80 | ^ | Nozzle diameter is: __80 or 0.80mm__ | ^ | ^
| ^ | ^ | ^ | 19h 25 | ^ | Nozzle diameter is: __25 or 0.25mm__ | ^ | ^
| 0x0DA5 3493 | uint16 | EEPROM_NOZZLE_DIAMETER_uM | 9001h | ff ffh 65535 | Nozzle diameter is: __400um__ | LCD menu | D3 Ax0da5 C2
| ^ | ^ | ^ | 5802h | ^ | Nozzle diameter is: __600um__ | ^ | ^
| ^ | ^ | ^ | 2003h | ^ | Nozzle diameter is: __800um__ | ^ | ^
| ^ | ^ | ^ | fa00h | ^ | Nozzle diameter is: __250um__ | ^ | ^
| 0x0DA4 3492 | uint8 | EEPROM_CHECK_MODEL | 01h 1 | ffh 255 | Check mode for printer model is: __warn__ | LCD menu | D3 Ax0da4 C1
| ^ | ^ | ^ | 02h 0 | ^ | Check mode for printer model is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for printer model is: __none__ | ^ | ^
| 0x0DA3 3491 | uint8 | EEPROM_CHECK_VERSION | 01h 1 | ffh 255 | Check mode for firmware is: __warn__ | LCD menu | D3 Ax0da3 C1
| ^ | ^ | ^ | 02h 0 | ^ | Check mode for firmware is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for firmware is: __none__ | ^ | ^
| 0x0DA2 3490 | uint8 | EEPROM_CHECK_GCODE | 01h 1 | ffh 255 | Check mode for gcode is: __warn__ _unused atm_ | LCD menu | D3 Ax0da2 C1
| ^ | ^ | ^ | 02h 0 | ^ | Check mode for gcode is: __strict__ _unused atm_ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for gcode is: __none__ _unused atm_ | ^ | ^
| 0x0D49 3401 | uint16 | EEPROM_SHEETS_BASE | ??? | ffh 255 | ??? | LCD menu | D3 Ax0d49 C89
| 0x0D49 3401 | char | _1st Sheet block_ | 536d6f6f746831| ffffffffffffff | 1st sheet - Name: _Smooth1_ | ^ | D3 Ax0d49 C7
| 0x0D50 3408 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 1st sheet - Z offset | ^ | D3 Ax0d50 C2
| 0x0D52 3410 | uint8 | ^ | 00h 0 | ffh 255 | 1st sheet - bed temp | ^ | D3 Ax0d52 C1
| 0x0D53 3411 | uint8 | ^ | 00h 0 | ffh 255 | 1st sheet - PINDA temp | ^ | D3 Ax0d53 C1
| 0x0D54 3412 | char | _2nd Sheet block_ | 536d6f6f746832| ffffffffffffff | 2nd sheet - Name: _Smooth2_ | ^ | D3 Ax0d54 C7
| 0x0D5B 3419 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 2nd sheet - Z offset | ^ | D3 Ax0d5b C2
| 0x0D5D 3421 | uint8 | ^ | 00h 0 | ffh 255 | 2nd sheet - bed temp | ^ | D3 Ax0d5d C1
| 0x0D5E 3422 | uint8 | ^ | 00h 0 | ffh 255 | 2nd sheet - PINDA temp | ^ | D3 Ax0d5e C1
| 0x0D5F 3423 | char | _3rd Sheet block_ | 54657874757231| ffffffffffffff | 3rd sheet - Name: _Textur1_ | ^ | D3 Ax0d5f C7
| 0x0D66 3430 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 3rd sheet - Z offset | ^ | D3 Ax0d66 C2
| 0x0D68 3432 | uint8 | ^ | 00h 0 | ffh 255 | 3rd sheet - bed temp | ^ | D3 Ax0d68 C1
| 0x0D69 3433 | uint8 | ^ | 00h 0 | ffh 255 | 3rd sheet - PINDA temp | ^ | D3 Ax0d69 C1
| 0x0D6A 3434 | char | _4th Sheet block_ | 54657874757232| ffffffffffffff | 4th sheet - Name: _Textur2_ | ^ | D3 Ax0d6a C7
| 0x0D71 3441 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 4th sheet - Z offset | ^ | D3 Ax0d71 C2
| 0x0D73 3443 | uint8 | ^ | 00h 0 | ffh 255 | 4th sheet - bed temp | ^ | D3 Ax0d73 C1
| 0x0D74 3444 | uint8 | ^ | 00h 0 | ffh 255 | 4th sheet - PINDA temp | ^ | D3 Ax0d74 C1
| 0x0D75 3445 | char | _5th Sheet block_ | 536174696e2031| ffffffffffffff | 5th sheet - Name: _Satin 1_ | ^ | D3 Ax0d75 C7
| 0x0D7C 3452 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 5th sheet - Z offset | ^ | D3 Ax0d7c C2
| 0x0D7E 3454 | uint8 | ^ | 00h 0 | ffh 255 | 5th sheet - bed temp | ^ | D3 Ax0d7e C1
| 0x0D7F 3455 | uint8 | ^ | 00h 0 | ffh 255 | 5th sheet - PINDA temp | ^ | D3 Ax0d7f C1
| 0x0D80 3456 | char | _6th Sheet block_ | 536174696e2032| ffffffffffffff | 6th sheet - Name: _Satin 2_ | ^ | D3 Ax0d80 C7
| 0x0D87 3463 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 6th sheet - Z offset | ^ | D3 Ax0d87 C2
| 0x0D89 3465 | uint8 | ^ | 00h 0 | ffh 255 | 6th sheet - bed temp | ^ | D3 Ax0d89 C1
| 0x0D8A 3466 | uint8 | ^ | 00h 0 | ffh 255 | 6th sheet - PINDA temp | ^ | D3 Ax0d8a C1
| 0x0D8B 3467 | char | _7th Sheet block_ | 437573746f6d31| ffffffffffffff | 7th sheet - Name: _Custom1_ | ^ | D3 Ax0d8b C7
| 0x0D92 3474 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 7th sheet - Z offset | ^ | D3 Ax0d92 C2
| 0x0D94 3476 | uint8 | ^ | 00h 0 | ffh 255 | 7th sheet - bed temp | ^ | D3 Ax0d94 C1
| 0x0D95 3477 | uint8 | ^ | 00h 0 | ffh 255 | 7th sheet - PINDA temp | ^ | D3 Ax0d95 C1
| 0x0D96 3478 | char | _8th Sheet block_ | 437573746f6d32| ffffffffffffff | 8th sheet - Name: _Custom2_ | ^ | D3 Ax0d96 C7
| 0x0D9D 3485 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 8th sheet - Z offset | ^ | D3 Ax0d9d C2
| 0x0D9F 3487 | uint8 | ^ | 00h 0 | ffh 255 | 8th sheet - bed temp | ^ | D3 Ax0d9f C1
| 0x0DA0 3488 | uint8 | ^ | 00h 0 | ffh 255 | 8th sheet - PINDA temp | ^ | D3 Ax0da0 C1
| 0x0DA1 3489 | uint8 | ??? | 00h 0 | ffh 255 | ??? | ??? | D3 Ax0da1 C1
| 0x0D48 3400 | uint8 | EEPROM_FSENSOR_PCB | ffh 255 | ffh 255 | Filament Sensor type IR unknown | LCD Support | D3 Ax0d48 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament Sensor type IR 0.3 or older | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | Filament Sensor type IR 0.4 or newer | ^ | ^
| 0x0D47 3399 | uint8 | EEPROM_FSENSOR_ACTION_NA | 00h 0 | ffh 255 | Filament Sensor action: __Continue__ | LCD menu | D3 Ax0d47 C1
| ^ | ^ | ^ | 01h 1 | ^ | Filament Sensor action: __Pause__ | ^ | ^
| 0x0D37 3383 | float | EEPROM_UVLO_SAVED_TARGET | ??? | ff ff ff ffh | Power panic saved target all-axis | ??? | D3 Ax0d37 C16
| ^ | ^ | ^ | ??? | ^ | Power panic saved target e-axis | ^ | D3 Ax0d43 C4
| ^ | ^ | ^ | ??? | ^ | Power panic saved target z-axis | ^ | D3 Ax0d3f C4
| ^ | ^ | ^ | ??? | ^ | Power panic saved target y-axis | ^ | D3 Ax0d3b C4
| ^ | ^ | ^ | ??? | ^ | Power panic saved target x-axis | ^ | D3 Ax0d37 C4
| 0x0D35 3381 | uint16 | EEPROM_UVLO_FEEDMULTIPLY | ??? | ff ffh 65355 | Power panic saved feed multiplier | ??? | D3 Ax0d35 C2
| 0x0D34 3380 | uint8 | EEPROM_BACKLIGHT_LEVEL_HIGH | 00h - ffh | 82h 130 | LCD backlight bright: __128__ Dim value to 255 | LCD menu | D3 Ax0d34 C1
| 0x0D33 3379 | uint8 | EEPROM_BACKLIGHT_LEVEL_LOW | 00h - ffh | 32h 50 | LCD backlight dim: __50__ 0 to Bright value | LCD menu | D3 Ax0d33 C1
| 0x0D32 3378 | uint8 | EEPROM_BACKLIGHT_MODE | 02h 2 | ffh 255 | LCD backlight mode: __Auto__ | LCD menu | D3 Ax0d32 C1
| ^ | ^ | ^ | 01h 1 | ^ | LCD backlight mode: __Bright__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | LCD backlight mode: __Dim__ | ^ | ^
| 0x0D30 3376 | uint16 | EEPROM_BACKLIGHT_TIMEOUT | 01 00 - ff ff | 0a 00h 65535 | LCD backlight timeout: __10__ seconds | LCD menu | D3 Ax0d30 C2
| 0x0D2C 3372 | float | EEPROM_UVLO_LA_K | ??? | ff ff ff ffh | Power panic saved Linear Advanced K value | ??? | D3 Ax0d2c C4
| 0x0D2B 3371 | uint8 | EEPROM_ALTFAN_OVERRIDE | ffh 255 | ffh 255 | ALTFAN override unknown state | LCD menu | D3 Ax0d2b C1
| ^ | ^ | ^ | 00h 0 | ^ | ALTFAN override deactivated | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | ALTFAN override activated | ^ | ^
| 0x0D2A 3370 | uint8 | EEPROM_EXPERIMENTAL_VISIBILITY | ffh 255 | ffh 255 | Experimental menu visibility unknown state | LCD menu | D3 Ax0d2a C1
| ^ | ^ | ^ | 00h 0 | ^ | Experimental menu visibility hidden | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | Experimental menu visibility visible | ^ | ^
| 0x0D29 3369 | uint8 | EEPROM_PINDA_TEMP_COMPENSATION | ffh 255 | ffh 255 | PINDA temp compensation unknown state | LCD menu | D3 Ax0d29 C1
| ^ | ^ | ^ | 00h 0 | ^ | PINDA has no temp compensation PINDA v1/2 | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | PINDA has temp compensation aka SuperPINDA | ^ | ^
| 0x0D15 3349 | char[20] | EEPROM_PRUSA_SN | SN[19] == 0 | ffffffffffffffff... | PRUSA Serial number string | PRUSA SN | D3 Ax0d15 C20
| 0x0D11 3345 | float | EEPROM_UVLO_ACCELL | ??? | ff ff ff ffh | Power panic saved normal acceleration | ??? | D3 Ax0d11 C4
| 0x0D0D 3341 | float | EEPROM_UVLO_RETRACT_ACCELL | ??? | ff ff ff ffh | Power panic saved retract acceleration | ??? | D3 Ax0d0d C4
| 0x0D09 3337 | float | EEPROM_UVLO_TRAVEL_ACCELL | ??? | ff ff ff ffh | Power panic saved travel acceleration | ??? | D3 Ax0d09 C4
| 0x0D05 3333 | uint32_t | EEPROM_JOB_ID | ??? | 00 00 00 00h | Job ID used by host software | D3 only | D3 Ax0d05 C4
| 0x0D04 3332 | uint8_t | EEPROM_ECOOL_ENABLE | ffh 255 | ^ | Disable extruder motor scaling for non-farm print | LCD menu | D3 Ax0d04 C1
| ^ | ^ | ^ | 2ah 42 | ^ | Enable extruder motor scaling for non-farm print | ^ | D3 Ax0d04 C1
| 0x0D03 3321 | uint8_t | EEPROM_FW_CRASH_FLAG | ffh 255 | ffh 255 | Last FW crash reason (dump_crash_reason) | D21/D22 | D3 Ax0d03 C1
| ^ | ^ | ^ | 00h 0 | ^ | manual | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | stack_error | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | watchdog | ^ | ^
| ^ | ^ | ^ | 03h 3 | ^ | bad_isr | ^ | ^
| ^ | ^ | ^ | 04h 4 | ^ | bad_pullup_temp_isr | ^ | ^
| ^ | ^ | ^ | 05h 5 | ^ | bad_pullup_step_isr | ^ | ^
|Address begin|Bit/Type | Name | Valid values | Default/FactoryReset | Description |Gcode/Function| Debug code
| :-- | :-- | :-- | :--: | :--: | :-- | :--: | :--:
| 0x0FFF 4095 | uchar | EEPROM_SILENT | 00h 0 | ffh 255 | TMC Stealth mode: __off__ / miniRambo Power mode | LCD menu | D3 Ax0fff C1
| ^ | ^ | ^ | 01h 1 | ^ | TMC Stealth mode: __on__ / miniRambo Silent mode | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | miniRambo Auto mode | ^ | ^
| 0x0FFE 4094 | uchar | EEPROM_LANG | 00h 0 | ffh 255 __L__ | English / LANG_ID_PRI | LCD menu | D3 Ax0ffe C1
| ^ | ^ | ^ | 01h 1 | ^ | Other language LANG_ID_SEC | ^ | ^
| 0x0FFC 4092 | uint16 | _EEPROM_FREE_NR10_ | ??? | ff ffh 65535 | _Free EEPROM space_ | _free space_ | D3 Ax0ffc C2
| 0x0FFA 4090 | uint16 | _EEPROM_FREE_NR11_ | ??? | ff ffh 65535 | _Free EEPROM space_ | _free space_ | D3 Ax0ffa C2
| 0x0FF8 4088 | uint16 | EEPROM_BABYSTEP_Z | ??? | ff ffh 65535 | Babystep for Z axis _legacy_ | ??? | D3 Ax0ff8 C2
| ^ | ^ | ^ | ^ | ^ | multiple values stored now in EEPROM_Sheets_base | ^ | ^
| 0x0FF7 4087 | uint8 | EEPROM_CALIBRATION_STATUS_V1 | ffh 255 | ffh 255 | Calibration status (<v3.12) | ??? | D3 Ax0ff7 C1
| ^ | ^ | ^ | 01h 1 | ^ | Calibrated | ^ | ^
| ^ | ^ | ^ | e6h 230 | ^ | needs Live Z adjustment | ^ | ^
| ^ | ^ | ^ | ebh 235 | ^ | needs Thermal Model calibration | ^ | ^
| ^ | ^ | ^ | f0h 240 | ^ __P__ | needs Z calibration | ^ | ^
| ^ | ^ | ^ | fah 250 | ^ | needs XYZ calibration | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Unknown (legacy) | ^ | ^
| 0x0FF5 4085 | uint16 | _EEPROM_FREE_NR12_ | ??? | ff ffh 65535 | _Free EEPROM space_ | _free space_ | D3 Ax0ff5 C2
| 0x0FF1 4081 | uint32 | EEPROM_FILAMENTUSED | ??? | 00 00 00 00h 0 __S/P__| Filament used in centimeters | ??? | D3 Ax0ff1 C4
| 0x0FED 4077 | uint32 | EEPROM_TOTALTIME | ??? | 00 00 00 00h 0 __S/P__| Total print time in minutes | ??? | D3 Ax0fed C4
| 0x0FE5 4069 | float | EEPROM_BED_CALIBRATION_CENTER | ??? | ff ff ff ffh | ??? | ??? | D3 Ax0fe5 C8
| 0x0FDD 4061 | float | EEPROM_BED_CALIBRATION_VEC_X | ??? | ff ff ff ffh | ??? | ??? | D3 Ax0fdd C8
| 0x0FD5 4053 | float | EEPROM_BED_CALIBRATION_VEC_Y | ??? | ff ff ff ffh | ??? | ??? | D3 Ax0fd5 C8
| 0x0FC5 4037 | int16 | EEPROM_BED_CALIBRATION_Z_JITTER | ??? | ff ffh 65535 | ??? | ??? | D3 Ax0fc5 C16
| 0x0FC4 4036 | bool | EEPROM_FARM_MODE | 00h 0 | ffh 255 __P__ | Prusa farm mode: __off__ | G99 | D3 Ax0fc4 C1
| ^ | ^ | ^ | 01h 1 | ^ | Prusa farm mode: __on__ | G98 | ^
| 0x0FC3 4035 | free | _EEPROM_FREE_NR1_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0fc3 C1
| 0x0FC1 4033 | ??? | _EEPROM_FREE_NR2_ | ??? | ff ffh 65535 | _Free EEPROM space_ | _free space_ | D3 Ax0fc1 C2
| 0x0FC0 4032 | bool | EEPROM_BED_CORRECTION_VALID | 00h 0 | 00h 0 | Bed correction: __invalid__ | ??? | D3 Ax0fc0 C1
| ^ | ^ | ^ | ffh 255 | ^ | Bed correction: __valid__ | ??? | ^
| 0x0FBF 4031 | char | EEPROM_BED_CORRECTION_LEFT | 00h ffh | 00h 0 | Bed manual correction left | LCD menu | D3 Ax0fbf C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Lxxx | ^
| 0x0FBE 4030 | char | EEPROM_BED_CORRECTION_RIGHT | 00h ffh | 00h 0 | Bed manual correction right | LCD menu | D3 Ax0fbe C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Rxxx | ^
| 0x0FBD 4029 | char | EEPROM_BED_CORRECTION_FRONT | 00h ffh | 00h 0 | Bed manual correction front | LCD menu | D3 Ax0fbd C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Fxxx | ^
| 0x0FBC 4028 | char | EEPROM_BED_CORRECTION_BACK | 00h ffh | 00h 0 | Bed manual correction back | LCD menu | D3 Ax0fbc C1
| ^ | ^ | ^ | ^ | ^ | At this moment limited to +-100um | G80 Bxxx | ^
| 0x0FBB 4027 | bool | EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY | 00h 0 | ffh 255 | Toshiba Air: __off__ | LCD menu | D3 Ax0fbb C1
| ^ | ^ | ^ | 01h 1 | ^ | Toshiba Air: __on__ | ^ | ^
| 0x0FBA 4026 | uint8 | _EEPROM_FREE_NR3_ | ??? | ??? | _Free EEPROM space_ | _free space_ | D3 Ax0fba C1
| 0x0FB0 4016 | int16 | EEPROM_PROBE_TEMP_SHIFT | ??? | ??? | ??? | ??? | D3 Ax0fb0 C10
| 0x0FAF 4015 | bool | EEPROM_TEMP_CAL_ACTIVE | 00h 0 | 00h 0 | PINDA Temp cal.: __inactive__ | LCD menu | D3 Ax0faf C1
| ^ | ^ | ^ | ffh 255 | ^ | PINDA Temp cal.: __active__ | ^ | ^
| 0x0FA7 4007 | ??? | _EEPROM_FREE_NR6_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0fae C8
| 0x0FA6 4006 | uint8 | EEPROM_CALIBRATION_STATUS_PINDA | 00h 0 | ffh 255 | PINDA Temp: __not calibrated__ | ??? | D3 Ax0fa6 C1
| ^ | ^ | ^ | 01h 1 | ^ | PINDA Temp: __calibrated__ | ^ | ^
| 0x0FA5 4005 | uint8 | EEPROM_UVLO | 00h 0 | ffh 255 | No print job recovery is pending | Power panic | D3 Ax0fa5 C1
| ^ | ^ | ^ | 01h 1 | ^ | Print job recovery is pending | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | Print job recovery retry is pending | ^ | ^
| 0x0F9D 3997 | float | EEPROM_UVLO_CURRENT_POSITION | ??? | ffh 255 | Saved machine position (X and Y axis) | Power Panic | D3 Ax0f9d C8
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0fa1 C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0f9d C4
| 0x0F95 3989 | char[8] | EEPROM_FILENAME | ??? | ffh 255 | SD print SFN without extension | Power Panic | D3 Ax0f95 C8
| 0x0F91 3985 | uint32 | EEPROM_FILE_POSITION | ??? | ff ff ff ffh | SD: file position, USB/Serial: last line number | Power Panic | D3 Ax0f91 C4
| 0x0F8D 3981 | float | EEPROM_UVLO_CURRENT_POSITION_Z | ??? | ff ff ff ffh | Saved machine position (Z axis) without MBL applied| Power Panic | D3 Ax0f8d C4
| 0x0F8C 3980 | uint8 | EEPROM_UVLO_PRINT_TYPE | 00h 0 | ffh 255 | print type: SD | Power Panic | D3 Ax0f8c C1
| ^ | ^ | ^ | 01h 1 | ^ | print type: USB / Serial | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | print type: None | ^ | ^
| 0x0F8B 3979 | uint8 | EEPROM_UVLO_TARGET_BED | ??? | ffh 255 | Saved bed target temperature | Power Panic | D3 Ax0f8b C1
| 0x0F89 3977 | uint16 | EEPROM_UVLO_FEEDRATE | ??? | ff ffh 65535 | Saved Feedrate | Power Panic | D3 Ax0f89 C2
| 0x0F88 3976 | uint8 | EEPROM_UVLO_FAN_SPEED | ??? | ffh 255 | Saved Fan speed | Power Panic | D3 Ax0f88 C1
| 0x0F87 3975 | uint8 | EEPROM_FAN_CHECK_ENABLED | 00h 0 | ??? | Fan Check __disabled__ | LCD menu | D3 Ax0f87 C1
| ^ | ^ | ^ | 01h 1 | ffh 255 | Fan Check __enabled__ | ^ | ^
| 0x0F75 3957 | uint16 | _EEPROM_FREE_NR7_ | ??? | ff ffh 65535 | _Free EEPROM space_ | _free space_ | D3 Ax0f75 C18
| 0x0F73 3955 | uint16 | _EEPROM_FREE_NR8_ | ??? | ff ffh 65535 | _Free EEPROM space_ | _free space_ | D3 Ax0f73 C2
| 0x0F72 3954 | uint8 | EEPROM_UVLO_E_ABS | ??? | ffh 0 | E axis was in relative mode (M83) | Power Panic | D3 Ax0f72 C1
| 0x0F72 3954 | uint8 | ^ | ??? | ffh 1 | E axis was in absolute mode (M82) | Power Panic | ^
| 0x0F6E 3950 | float | EEPROM_UVLO_CURRENT_POSITION_E | ??? | ff ff ff ffh | Saved machine position (E axis) | Power Panic | D3 Ax0f6e C4
| 0x0F6C 3948 | uint16 | EEPROM_UVLO_SAVED_SEGMENT_IDX | all | ff ffh 65535 | Saved index of multi-segment move | Power Panic | D3 Ax0f6c C2
| 0x0F6B 3947 | ??? | _EEPROM_FREE_NR4_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0f6b C1
| 0x0F6A 3946 | ??? | _EEPROM_FREE_NR5_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0f6a C1
| 0x0F69 3945 | uint8 | EEPROM_CRASH_DET | ffh 255 | ffh 255 | Crash detection: __enabled__ | LCD menu | D3 Ax0f69 C1
| ^ | ^ | ^ | 00h 0 | ^ | Crash detection: __disabled__ | LCD menu | ^
| 0x0F68 3944 | uint8 | EEPROM_CRASH_COUNT_Y | 00h-ffh 0-255| ffh 255 __S/P__ | Crash detection counter Y (last print) | Statistics | D3 Ax0f68 C1
| 0x0F67 3943 | uint8 | EEPROM_FSENSOR | 01h 1 | ffh 255 __P__ | Filament sensor: __enabled__ | LCD menu | D3 Ax0f67 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament sensor: __disabled__ | LCD menu | ^
| 0x0F65 3942 | uint8 | EEPROM_CRASH_COUNT_X | 00h-ffh 0-255| ffh 255 __S/P__ | Crash detection counter X (last print) | Statistics | D3 Ax0f66 C1
| 0x0F65 3941 | uint8 | EEPROM_FERROR_COUNT | 00h-ffh 0-255| ffh 255 __S/P__ | Filament runout/error counter (last print) | Statistics | D3 Ax0f65 C1
| 0x0F64 3940 | uint8 | EEPROM_POWER_COUNT | 00h-ffh 0-255| ffh 255 __S/P__ | Power loss errors (last print) | Statistics | D3 Ax0f64 C1
| 0x0F60 3936 | float | EEPROM_XYZ_CAL_SKEW | ??? | ff ff ff ffh | XYZ skew value | ??? | D3 Ax0f60 C4
| 0x0F5F 3935 | uint8 | EEPROM_WIZARD_ACTIVE | 01h 1 | 01h 1 __P__ | Wizard __active__ | ??? | D3 Ax0f5f C1
| ^ | ^ | ^ | 00h 0 | ^ | Wizard __inactive__ | ^ | ^
| ^ | ^ | ^ | 02h 2 | 02h 2 __M__ | Wizard active - Z cal after shipping/service prep | ^ | ^
| 0x0F5D 3933 | uint16 | EEPROM_BELTSTATUS_X | ??? | ff ffh | X Beltstatus | ??? | D3 Ax0f5d C2
| 0x0F5B 3931 | uint16 | EEPROM_BELTSTATUS_Y | ??? | ff ffh | Y Beltstatus | ??? | D3 Ax0f5b C2
| 0x0F5A 3930 | uint8 | EEPROM_DIR_DEPTH | 00h-ffh 0-255| ffh 255 | Directory depth | ??? | D3 Ax0f5a C1
| 0x0F0A 3850 | uint8 | EEPROM_DIRS | ??? | ffh 255 | Directories ??? | ??? | D3 Ax0f0a C80
| 0x0F09 3849 | uint8 | EEPROM_SD_SORT | 00h 0 | ffh 255 | SD card sort by: __time__ | LCD menu | D3 Ax0f09 C1
| ^ | ^ | ^ | 01h 1 | ^ | SD card sort by: __alphabet__ | LCD menu | ^
| ^ | ^ | ^ | 02h 2 | ^ | SD card: __not sorted__ | LCD menu | ^
| 0x0F08 3848 | uint8 | EEPROM_SECOND_SERIAL_ACTIVE | 00h 0 | ffh 255 | RPi Port: __disabled__ | LCD menu | D3 Ax0f08 C1
| ^ | ^ | ^ | 01h 1 | ^ | RPi Port: __enabled__ | LCD menu | ^
| 0x0F07 3847 | uint8 | EEPROM_FSENS_AUTOLOAD_ENABLED | 01h 1 | ffh 255 __P__ | Filament autoload: __enabled__ | LCD menu | D3 Ax0f07 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament autoload: __disabled__ | LCD menu | ^
| 0x0F05 3845 | uint16 | EEPROM_CRASH_COUNT_X_TOT | 0000-fffe | ff ffh __S/P__ | Total crashes on x axis | Statistics | D3 Ax0f05 C2
| 0x0F03 3843 | uint16 | EEPROM_CRASH_COUNT_Y_TOT | 0000-fffe | ff ffh __S/P__ | Total crashes on y axis | Statistics | D3 Ax0f03 C2
| 0x0F01 3841 | uint16 | EEPROM_FERROR_COUNT_TOT | 0000-fffe | ff ffh __S/P__ | Total filament sensor errors | Statistics | D3 Ax0f01 C2
| 0x0EFF 3839 | uint16 | EEPROM_POWER_COUNT_TOT | 0000-fffe | ff ffh __S/P__ | Total power failures | Statistics | D3 Ax0eff C2
| 0x0EFE 3838 | uint8 | EEPROM_TMC2130_HOME_X_ORIGIN | ??? | ffh 255 | ??? | ??? | D3 Ax0efe C1
| 0x0EFD 3837 | uint8 | EEPROM_TMC2130_HOME_X_BSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0efd C1
| 0x0EFC 3836 | uint8 | EEPROM_TMC2130_HOME_X_FSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0efc C1
| 0x0EFB 3835 | uint8 | EEPROM_TMC2130_HOME_Y_ORIGIN | ??? | ffh 255 | ??? | ??? | D3 Ax0efb C1
| 0x0EFA 3834 | uint8 | EEPROM_TMC2130_HOME_Y_BSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0efa C1
| 0x0EF9 3833 | uint8 | EEPROM_TMC2130_HOME_Y_FSTEPS | ??? | ffh 255 | ??? | ??? | D3 Ax0ef9 C1
| 0x0EF8 3832 | uint8 | EEPROM_TMC2130_HOME_ENABLED | ??? | ffh 255 | ??? | ??? | D3 Ax0ef8 C1
| 0x0EF7 3831 | uint8 | EEPROM_TMC2130_WAVE_X_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef7 C1
| 0x0EF6 3830 | uint8 | EEPROM_TMC2130_WAVE_Y_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef6 C1
| 0x0EF5 3829 | uint8 | EEPROM_TMC2130_WAVE_Z_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef5 C1
| 0x0EF4 3828 | uint8 | EEPROM_TMC2130_WAVE_E_FAC | ??? | ffh 255 | ??? | ??? | D3 Ax0ef4 C1
| 0x0EF3 3827 | uint8 | EEPROM_TMC2130_X_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef3 C1
| 0x0EF2 3826 | uint8 | EEPROM_TMC2130_Y_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef2 C1
| 0x0EF1 3825 | uint8 | EEPROM_TMC2130_Z_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef1 C1
| 0x0EF0 3824 | uint8 | EEPROM_TMC2130_E_MRES | ??? | ffh 255 | ??? | ??? | D3 Ax0ef0 C1
| 0x0EEE 3822 | uint16 | EEPROM_PRINTER_TYPE | ??? | ff ffh 65535 | Printer Type | ??? | D3 Ax0eee C2
| ^ | ^ | ^ | 64 00h 100 | ^ | PRINTER_MK1 | ??? | ^
| ^ | ^ | ^ | c8 00h 200 | ^ | PRINTER_MK2 | ??? | ^
| ^ | ^ | ^ | c9 00h 201 | ^ | PRINTER_MK2 with MMU1 | ??? | ^
| ^ | ^ | ^ | ca 00h 202 | ^ | PRINTER_MK2S | ??? | ^
| ^ | ^ | ^ | cb 00h 203 | ^ | PRINTER_MK2S with MMU1 | ??? | ^
| ^ | ^ | ^ | fa 00h 250 | ^ | PRINTER_MK2.5 | ??? | ^
| ^ | ^ | ^ | 1a 4fh 20250 | ^ | PRINTER_MK2.5 with MMU2 | ??? | ^
| ^ | ^ | ^ | fc 00h 252 | ^ | PRINTER_MK2.5S | ??? | ^
| ^ | ^ | ^ | 1c 4fh 20252 | ^ | PRINTER_MK2.5S with MMU2S | ??? | ^
| ^ | ^ | ^ | 2c 01h 300 | ^ | PRINTER_MK3 | ??? | ^
| ^ | ^ | ^ | 4c 4fh 20300 | ^ | PRINTER_MK3 with MMU2 | ??? | ^
| ^ | ^ | ^ | 5c 76h 30300 | ^ | PRINTER_MK3 with MMU3 | ??? | ^
| ^ | ^ | ^ | 2e 01h 302 | ^ | PRINTER_MK3S | ??? | ^
| ^ | ^ | ^ | 4e 4fh 20302 | ^ | PRINTER_MK3S with MMU2S | ??? | ^
| ^ | ^ | ^ | 5e 76h 30302 | ^ | PRINTER_MK3S with MMU3 | ??? | ^
| 0x0EEC 3820 | uint16 | EEPROM_BOARD_TYPE | ??? | ff ffh 65535 | Board Type | ??? | D3 Ax0eec C2
| ^ | ^ | ^ | c8 00h 200 | ^ | BOARD_RAMBO_MINI_1_0 | ??? | ^
| ^ | ^ | ^ | cb 00h 203 | ^ | BOARD_RAMBO_MINI_1_3 | ??? | ^
| ^ | ^ | ^ | 36 01h 310 | ^ | BOARD_EINSY_1_0a | ??? | ^
| 0x0EE8 3816 | float | EEPROM_EXTRUDER_MULTIPLIER_0 | ??? | ff ff ff ffh | Extruder 0 multiplier | Power Panic | D3 Ax0ee8 C4
| 0x0EE4 3812 | float | EEPROM_EXTRUDER_MULTIPLIER_1 | ??? | ff ff ff ffh | Extruder 1 multiplier | Power Panic | D3 Ax0ee4 C4
| 0x0EE0 3808 | float | EEPROM_EXTRUDER_MULTIPLIER_2 | ??? | ff ff ff ffh | Extruder 2 multiplier | Power Panic | D3 Ax0ee0 C4
| 0x0EDE 3806 | uint16 | EEPROM_EXTRUDEMULTIPLY | ??? | ff ffh 65535 | Extruder multiplier | Power Panic | D3 Ax0ede C2
| 0x0EDA 3802 | float | EEPROM_UVLO_TINY_CURRENT_POSITION_Z | ??? | ff ff ff ffh | Saved Z-axis position when recovering print failed| Power Panic | D3 Ax0eda C4
| 0x0ED8 3800 | uint16 | EEPROM_UVLO_TARGET_HOTEND | ??? | ff ffh 65535 | Saved hotend target temperature | Power Panic | D3 Ax0ed8 C2
| 0x0ED7 3799 | uint8 | EEPROM_SOUND_MODE | 00h 0 | ffh 255 | Sound mode: __loud__ | ??? | D3 Ax0ed7 C1
| ^ | ^ | ^ | 01h 1 | ^ | Sound mode: __once__ | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | Sound mode: __silent__ | ^ | ^
| ^ | ^ | ^ | 03h 3 | ^ | Sound mode: __assist__ | ^ | ^
| 0x0ED6 3798 | bool | EEPROM_SPOOL_JOIN | 01h 1 | ffh 255 | SpoolJoin: __on__ | MMU | D3 Ax0ed6 C1
| ^ | ^ | ^ | 00h 0 | ^ | SpoolJoin: __off__ | ^ | ^
| 0x0ED5 3797 | bool | EEPROM_FSENS_RUNOUT_ENABLED | 01h 1 | ffh 255 __P__ | Filament runout: __enabled__ | LCD menu | D3 Ax0ed5 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament runout: __disabled__ | ^ | ^
| 0x0ED3 3795 | uint16 | EEPROM_MMU_FAIL_TOT | ??? | ff ffh 65535 __S/P__ | MMU total failures | LCD menu | D3 Ax0ed3 C2
| 0x0ED2 3794 | uint8 | EEPROM_MMU_FAIL | ??? | ffh 255 __S/P__ | MMU fails during print | LCD menu | D3 Ax0ed2 C1
| 0x0ED0 3792 | uint16 | EEPROM_MMU_LOAD_FAIL_TOT | ??? | ff ffh 65535 __S/P__ | MMU total load failures | LCD menu | D3 Ax0ed0 C2
| 0x0ECF 3791 | uint8 | EEPROM_MMU_LOAD_FAIL | ??? | ffh 255 __S/P__ | MMU load failures during print | LCD menu | D3 Ax0ecf C1
| 0x0ECE 3790 | uint8 | EEPROM_MMU_CUTTER_ENABLED | 00h 0 | ffh 255 | MMU cutter: __disabled__ | LCD menu | D3 Ax0ece C1
| ^ | ^ | ^ | 01h 1 | ^ | MMU cutter: __enabled__ | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | MMU cutter: __always__ | ^ | ^
| 0x0DAE 3502 | uint16 | EEPROM_UVLO_MESH_BED_LEVELING_FULL | ??? | ff ffh 65535 | Saved MBL points | Power Panic | D3 Ax0dae C288
| 0x0DAD 3501 | uint8 | _EEPROM_FREE_NR9_ | ??? | ffh 255 | _Free EEPROM space_ | _free space_ | D3 Ax0dad C1
| 0x0DAC 3500 | bool | EEPROM_MBL_MAGNET_ELIMINATION | 01h 1 | ffh 255 | Mesh bed leveling does: __ignores__ magnets | LCD menu | D3 Ax0dac C1
| ^ | ^ | ^ | 00h 0 | ^ | Mesh bed leveling does: __NOT ignores__ magnets | ^ | ^
| 0x0DAB 3499 | uint8 | EEPROM_MBL_POINTS_NR | 03h 3 | ffh 255 | Mesh bed leveling points: __3x3__ | LCD menu | D3 Ax0dab C1
| ^ | ^ | ^ | 07h 7 | ^ | Mesh bed leveling points: __7x7__ | ^ | ^
| 0x0DAA 3498 | uint8 | EEPROM_MBL_PROBE_NR | 03h 3 | ffh 255 | MBL times measurements for each point: __3__ | LCD menu | D3 Ax0daa C1
| ^ | ^ | ^ | 05h 5 | ^ | MBL times measurements for each point: __5__ | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | MBL times measurements for each point: __1__ | ^ | ^
| 0x0DA9 3497 | uint8 | EEPROM_MMU_STEALTH | 01h 1 | ffh 255 | MMU Silent mode: __on__ | LCD menu | D3 Ax0da9 C1
| ^ | ^ | ^ | 00h 0 | ^ | MMU Silent mode: __off__ | ^ | ^
| 0x0DA8 3496 | uint8 | EEPROM_CHECK_MODE | 01h 1 | ffh 255 | Check mode for nozzle is: __warn__ | LCD menu | D3 Ax0da8 C1
| ^ | ^ | ^ | 02h 2 | ^ | Check mode for nozzle is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for nozzle is: __none__ | ^ | ^
| 0x0DA7 3495 | uint8 | EEPROM_NOZZLE_DIAMETER | 28h 40 | ffh 255 | Nozzle diameter is: __40 or 0.40mm__ | LCD menu | D3 Ax0da7 C1
| ^ | ^ | ^ | 3ch 60 | ^ | Nozzle diameter is: __60 or 0.60mm__ | ^ | ^
| ^ | ^ | ^ | 3ch 80 | ^ | Nozzle diameter is: __80 or 0.80mm__ | ^ | ^
| ^ | ^ | ^ | 19h 25 | ^ | Nozzle diameter is: __25 or 0.25mm__ | ^ | ^
| 0x0DA5 3493 | uint16 | EEPROM_NOZZLE_DIAMETER_uM | 9001h | ff ffh 65535 | Nozzle diameter is: __400um__ | LCD menu | D3 Ax0da5 C2
| ^ | ^ | ^ | 5802h | ^ | Nozzle diameter is: __600um__ | ^ | ^
| ^ | ^ | ^ | 2003h | ^ | Nozzle diameter is: __800um__ | ^ | ^
| ^ | ^ | ^ | fa00h | ^ | Nozzle diameter is: __250um__ | ^ | ^
| 0x0DA4 3492 | uint8 | EEPROM_CHECK_MODEL | 01h 1 | ffh 255 | Check mode for printer model is: __warn__ | LCD menu | D3 Ax0da4 C1
| ^ | ^ | ^ | 02h 2 | ^ | Check mode for printer model is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for printer model is: __none__ | ^ | ^
| 0x0DA3 3491 | uint8 | EEPROM_CHECK_VERSION | 01h 1 | ffh 255 | Check mode for firmware is: __warn__ | LCD menu | D3 Ax0da3 C1
| ^ | ^ | ^ | 02h 2 | ^ | Check mode for firmware is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for firmware is: __none__ | ^ | ^
| 0x0DA2 3490 | uint8 | EEPROM_CHECK_GCODE | 01h 1 | ffh 255 | Check mode for gcode is: __warn__ _unused atm_ | LCD menu | D3 Ax0da2 C1
| ^ | ^ | ^ | 02h 2 | ^ | Check mode for gcode is: __strict__ _unused atm_ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for gcode is: __none__ _unused atm_ | ^ | ^
| 0x0D49 3401 | uint16 | EEPROM_SHEETS_BASE | ??? | ffh 255 | ??? | LCD menu | D3 Ax0d49 C89
| 0x0D49 3401 | char | _1st Sheet block_ |536d6f6f746831| ffffffffffffff | 1st sheet - Name: _Smooth1_ | ^ | D3 Ax0d49 C7
| 0x0D50 3408 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 1st sheet - Z offset | ^ | D3 Ax0d50 C2
| 0x0D52 3410 | uint8 | ^ | 00h 0 | ffh 255 | 1st sheet - bed temp | ^ | D3 Ax0d52 C1
| 0x0D53 3411 | uint8 | ^ | 00h 0 | ffh 255 | 1st sheet - PINDA temp | ^ | D3 Ax0d53 C1
| 0x0D54 3412 | char | _2nd Sheet block_ |536d6f6f746832| ffffffffffffff | 2nd sheet - Name: _Smooth2_ | ^ | D3 Ax0d54 C7
| 0x0D5B 3419 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 2nd sheet - Z offset | ^ | D3 Ax0d5b C2
| 0x0D5D 3421 | uint8 | ^ | 00h 0 | ffh 255 | 2nd sheet - bed temp | ^ | D3 Ax0d5d C1
| 0x0D5E 3422 | uint8 | ^ | 00h 0 | ffh 255 | 2nd sheet - PINDA temp | ^ | D3 Ax0d5e C1
| 0x0D5F 3423 | char | _3rd Sheet block_ |54657874757231| ffffffffffffff | 3rd sheet - Name: _Textur1_ | ^ | D3 Ax0d5f C7
| 0x0D66 3430 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 3rd sheet - Z offset | ^ | D3 Ax0d66 C2
| 0x0D68 3432 | uint8 | ^ | 00h 0 | ffh 255 | 3rd sheet - bed temp | ^ | D3 Ax0d68 C1
| 0x0D69 3433 | uint8 | ^ | 00h 0 | ffh 255 | 3rd sheet - PINDA temp | ^ | D3 Ax0d69 C1
| 0x0D6A 3434 | char | _4th Sheet block_ |54657874757232| ffffffffffffff | 4th sheet - Name: _Textur2_ | ^ | D3 Ax0d6a C7
| 0x0D71 3441 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 4th sheet - Z offset | ^ | D3 Ax0d71 C2
| 0x0D73 3443 | uint8 | ^ | 00h 0 | ffh 255 | 4th sheet - bed temp | ^ | D3 Ax0d73 C1
| 0x0D74 3444 | uint8 | ^ | 00h 0 | ffh 255 | 4th sheet - PINDA temp | ^ | D3 Ax0d74 C1
| 0x0D75 3445 | char | _5th Sheet block_ |536174696e2020| ffffffffffffff | 5th sheet - Name: _Satin _ | ^ | D3 Ax0d75 C7
| 0x0D7C 3452 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 5th sheet - Z offset | ^ | D3 Ax0d7c C2
| 0x0D7E 3454 | uint8 | ^ | 00h 0 | ffh 255 | 5th sheet - bed temp | ^ | D3 Ax0d7e C1
| 0x0D7F 3455 | uint8 | ^ | 00h 0 | ffh 255 | 5th sheet - PINDA temp | ^ | D3 Ax0d7f C1
| 0x0D80 3456 | char | _6th Sheet block_ |4e796c6f6e5041| ffffffffffffff | 6th sheet - Name: _NylonPA_ | ^ | D3 Ax0d80 C7
| 0x0D87 3463 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 6th sheet - Z offset | ^ | D3 Ax0d87 C2
| 0x0D89 3465 | uint8 | ^ | 00h 0 | ffh 255 | 6th sheet - bed temp | ^ | D3 Ax0d89 C1
| 0x0D8A 3466 | uint8 | ^ | 00h 0 | ffh 255 | 6th sheet - PINDA temp | ^ | D3 Ax0d8a C1
| 0x0D8B 3467 | char | _7th Sheet block_ |437573746f6d31| ffffffffffffff | 7th sheet - Name: _Custom1_ | ^ | D3 Ax0d8b C7
| 0x0D92 3474 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 7th sheet - Z offset | ^ | D3 Ax0d92 C2
| 0x0D94 3476 | uint8 | ^ | 00h 0 | ffh 255 | 7th sheet - bed temp | ^ | D3 Ax0d94 C1
| 0x0D95 3477 | uint8 | ^ | 00h 0 | ffh 255 | 7th sheet - PINDA temp | ^ | D3 Ax0d95 C1
| 0x0D96 3478 | char | _8th Sheet block_ |437573746f6d32| ffffffffffffff | 8th sheet - Name: _Custom2_ | ^ | D3 Ax0d96 C7
| 0x0D9D 3485 | uint16 | ^ | 00 00h 0 | ff ffh 65535 | 8th sheet - Z offset | ^ | D3 Ax0d9d C2
| 0x0D9F 3487 | uint8 | ^ | 00h 0 | ffh 255 | 8th sheet - bed temp | ^ | D3 Ax0d9f C1
| 0x0DA0 3488 | uint8 | ^ | 00h 0 | ffh 255 | 8th sheet - PINDA temp | ^ | D3 Ax0da0 C1
| 0x0DA1 3489 | uint8 | active_sheet | 00h 0 | ffh 255 | Active sheet index | ^ | D3 Ax0da1 C1
| 0x0D48 3400 | uint8 | EEPROM_FSENSOR_PCB | ffh 255 | ffh 255 | Filament Sensor type IR unknown | LCD Support | D3 Ax0d48 C1
| ^ | ^ | ^ | 00h 0 | ^ | Filament Sensor type IR 0.3 or older | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | Filament Sensor type IR 0.4 or newer | ^ | ^
| 0x0D47 3399 | uint8 | EEPROM_FSENSOR_ACTION_NA | 00h 0 | ffh 255 | Filament Sensor action: __Continue__ | LCD menu | D3 Ax0d47 C1
| ^ | ^ | ^ | 01h 1 | ^ | Filament Sensor action: __Pause__ | ^ | ^
| 0x0D37 3383 | float | EEPROM_UVLO_SAVED_START_POSITION | ??? | ff ff ff ffh | Saved start position all-axis | Power Panic | D3 Ax0d37 C16
| ^ | ^ | ^ | ??? | ^ | E-axis | ^ | D3 Ax0d43 C4
| ^ | ^ | ^ | ??? | ^ | Z-axis | ^ | D3 Ax0d3f C4
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0d3b C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0d37 C4
| 0x0D35 3381 | uint16 | EEPROM_UVLO_FEEDMULTIPLY | ??? | ff ffh 65355 | Saved feed multiplier | Power Panic | D3 Ax0d35 C2
| 0x0D34 3380 | uint8 | EEPROM_BACKLIGHT_LEVEL_HIGH | 00h - ffh | 82h 130 | LCD backlight bright: __128__ Dim value to 255 | LCD menu | D3 Ax0d34 C1
| 0x0D33 3379 | uint8 | EEPROM_BACKLIGHT_LEVEL_LOW | 00h - ffh | 32h 50 | LCD backlight dim: __50__ 0 to Bright value | LCD menu | D3 Ax0d33 C1
| 0x0D32 3378 | uint8 | EEPROM_BACKLIGHT_MODE | 02h 2 | ffh 255 | LCD backlight mode: __Auto__ | LCD menu | D3 Ax0d32 C1
| ^ | ^ | ^ | 01h 1 | ^ | LCD backlight mode: __Bright__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | LCD backlight mode: __Dim__ | ^ | ^
| 0x0D30 3376 | uint16 | EEPROM_BACKLIGHT_TIMEOUT | 01 00 - ff ff| 0a 00h 65535 | LCD backlight timeout: __10__ seconds | LCD menu | D3 Ax0d30 C2
| 0x0D2C 3372 | float | EEPROM_UVLO_LA_K | ??? | ff ff ff ffh | Saved Linear Advanced K value | Power Panic | D3 Ax0d2c C4
| 0x0D2B 3371 | uint8 | EEPROM_ALTFAN_OVERRIDE | ffh 255 | ffh 255 | ALTFAN override unknown state | LCD menu | D3 Ax0d2b C1
| ^ | ^ | ^ | 00h 0 | ^ | ALTFAN override deactivated | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | ALTFAN override activated | ^ | ^
| 0x0D2A 3370 | uint8 | EEPROM_EXPERIMENTAL_VISIBILITY | ffh 255 | ffh 255 | Experimental menu visibility unknown state | LCD menu | D3 Ax0d2a C1
| ^ | ^ | ^ | 00h 0 | ^ | Experimental menu visibility hidden | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | Experimental menu visibility visible | ^ | ^
| 0x0D29 3369 | uint8 | EEPROM_PINDA_TEMP_COMPENSATION | ffh 255 | ffh 255 | PINDA temp compensation unknown state | LCD menu | D3 Ax0d29 C1
| ^ | ^ | ^ | 00h 0 | ^ | PINDA has no temp compensation PINDA v1/2 | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | PINDA has temp compensation aka SuperPINDA | ^ | ^
| 0x0D15 3349 | char[20]| EEPROM_PRUSA_SN | SN[19] == 0 | ffffffffffffffff... | PRUSA Serial number string | PRUSA SN | D3 Ax0d15 C20
| 0x0D11 3345 | float | EEPROM_UVLO_ACCELL | ??? | ff ff ff ffh | Saved print acceleration | Power Panic | D3 Ax0d11 C4
| 0x0D0D 3341 | float | EEPROM_UVLO_RETRACT_ACCELL | ??? | ff ff ff ffh | Saved retract acceleration | Power Panic | D3 Ax0d0d C4
| 0x0D09 3337 | float | EEPROM_UVLO_TRAVEL_ACCELL | ??? | ff ff ff ffh | Saved travel acceleration | Power Panic | D3 Ax0d09 C4
| 0x0D05 3333 | unint32 | EEPROM_JOB_ID | ??? | 00 00 00 00h | Job ID used by host software | D3 only | D3 Ax0d05 C4
| 0x0D04 3332 | uint8 | EEPROM_ECOOL_ENABLE | ffh 255 | ^ | Disable extruder motor scaling for non-farm print | LCD menu | D3 Ax0d04 C1
| ^ | ^ | ^ | 2ah 42 | ^ | Enable extruder motor scaling for non-farm print | ^ | D3 Ax0d04 C1
| 0x0D03 3331 | uint8 | EEPROM_FW_CRASH_FLAG | ffh 255 | ffh 255 | Last FW crash reason (dump_crash_reason) | D21/D22 | D3 Ax0d03 C1
| ^ | ^ | ^ | 00h 0 | ^ | manual | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | stack_error | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | watchdog | ^ | ^
| ^ | ^ | ^ | 03h 3 | ^ | bad_isr | ^ | ^
| ^ | ^ | ^ | 04h 4 | ^ | bad_pullup_temp_isr | ^ | ^
| ^ | ^ | ^ | 05h 5 | ^ | bad_pullup_step_isr | ^ | ^
| 0x0D02 3330 | uint8 | EEPROM_THERMAL_MODEL_ENABLE | 00h 0 | ff/00 | Thermal Model deactivated | Thermal Model| D3 Ax0d02 C1
| ^ | ^ | ^ | 01h 1 | ^ | Thermal Model activated | ^ | ^
| 0x0CFE 3326 | float | EEPROM_THERMAL_MODEL_P | ??? | ff ff ff ffh | Thermal Model power (W) | Thermal Model| D3 Ax0cfe C4
| 0x0CFA 3322 | float | EEPROM_THERMAL_MODEL_C | ??? | ff ff ff ffh | Thermal Model capacitance (J/K) | Thermal Model| D3 Ax0cfa C4
| 0x0CBA 3258 |float[16]| EEPROM_THERMAL_MODEL_R | ??? | ff ff ff ffh | Thermal Model resistance (K/W) | Thermal Model| D3 Ax0cba C64
| 0x0CB6 3254 | float | EEPROM_THERMAL_MODEL_Ta_corr | ??? | ff ff ff ffh | Thermal Model ambient temperature correction (K) | Thermal Model| D3 Ax0cb6 C4
| 0x0CB2 3250 | float | EEPROM_THERMAL_MODEL_W | ??? | ff ff ff ffh | Thermal Model warning threshold (K/s) | Thermal Model| D3 Ax0cb2 C4
| 0x0CAE 3246 | float | EEPROM_THERMAL_MODEL_E | ??? | ff ff ff ffh | Thermal Model error threshold (K/s) | Thermal Model| D3 Ax0cae C4
| 0x0CAD 3245 | uint8 | EEPROM_FSENSOR_JAM_DETECTION | 01h 1 | ff/01 | fsensor pat9125 jam detection feature | LCD menu | D3 Ax0cad C1
| 0x0CAC 3244 | uint8 | EEPROM_MMU_ENABLED | 00h 0 | ff/00 | MMU enabled | LCD menu | D3 Ax0cac C1
| 0x0CA8 3240 | uint32 | EEPROM_MMU_MATERIAL_CHANGES | ??? | ff ff ff ffh | MMU toolchange counter over printers lifetime | LCD statistic| D3 Ax0ca8 C4
| 0x0CA7 3239 | uint8 | EEPROM_HEAT_BED_ON_LOAD_FILAMENT | ffh 255 | ffh 255 | Heat bed on load filament unknown state | LCD menu | D3 Ax0ca7 C1
| ^ | ^ | ^ | 00h 0 | ^ | Do not heat bed on load filament | ^ | ^
| ^ | ^ | ^ | 01h 1 | ^ | Heat bed on load filament | ^ | ^
| 0x0CA6 3238 | uint8 | EEPROM_CALIBRATION_STATUS_V2 | ffh 255 | ffh 255 | Calibration status (>=v3.12) | ??? | D3 Ax0ca6 C1
| ^ | ^ | ^ | 01h 1 | ^ | Selftest passed | ^ | ^
| ^ | ^ | ^ | 02h 2 | ^ | XYZ cal passed | ^ | ^
| ^ | ^ | ^ | 04h 4 | ^ | Z cal passed | ^ | ^
| ^ | ^ | ^ | 08h 8 | ^ | Thermal Model cal passed | ^ | ^
| ^ | ^ | ^ | 10h 16 | ^ | Live Adjust set | ^ | ^
| ^ | ^ | ^ | 20h 32 | ^ | Free bit | ^ | ^
| ^ | ^ | ^ | 40h 64 | ^ | Free bit | ^ | ^
| ^ | ^ | ^ | 80h 128 | ^ | Unknown | ^ | ^
| 0x0CA2 3234 | float | EEPROM_THERMAL_MODEL_U | ??? | ff ff ff ffh | Thermal Model linear temp coefficient (W/K/W) | Thermal Model| D3 Ax0ca2 C4
| 0x0C9E 3230 | float | EEPROM_THERMAL_MODEL_V | ??? | ff ff ff ffh | Thermal Model linear temp intercept (W/W) | Thermal Model| D3 Ax0c9e C4
| 0x0C9A 3226 | float | EEPROM_THERMAL_MODEL_D | ??? | ff ff ff ffh | Thermal Model sim. 1st order IIR filter factor | Thermal Model| D3 Ax0c9a C4
| 0x0C98 3224 | uint16 | EEPROM_THERMAL_MODEL_L | 0-2160 | ff ffh | Thermal Model sim. response lag (ms) | Thermal Model| D3 Ax0c98 C2
| 0x0C97 3223 | uint8 | EEPROM_THERMAL_MODEL_VER | 0-255 | ffh | Thermal Model Version | Thermal Model| D3 Ax0c97 C1
| 0x0C95 3221 | PGM_P | EEPROM_KILL_MESSAGE | 0-65535 | ff ffh | Kill message PGM pointer | kill() | D3 Ax0c95 C2
| 0x0C94 3220 | uint8 | EEPROM_KILL_PENDING_FLAG | 42h, ffh | ffh | Kill pending flag (0x42 magic value) | kill() | D3 Ax0c94 C1
| 0x0C91 3217 | char[3] | EEPROM_FILENAME_EXTENSION | ??? | ffffffffh | DOS 8.3 filename extension | Power Panic | D3 Ax0c91 C1
| 0x0C80 3200 | char[17]| EEPROM_CUSTOM_MENDEL_NAME | Prusa i3 MK3S| ffffffffffffffffff... | Custom Printer Name | | D3 Ax0c80 C17
| 0x0C7F 3199 | bool | EEPROM_UVLO_Z_LIFTED | 00h 0 | 00h | Power Panic Z axis NOT lifted | Power Panic | D3 Ax0c7f C1
| ^ | ^ | ^ | 01h 1 | 01h | Power Panic Z axis lifted | ^ | ^
| 0x0C7d 3197 | uint16 | EEPROM_UVLO_EXTRUDE_MINTEMP | 0-305 | afh 175 | Power Panic Extrude mintemp | Power Panic | D3 Ax0c7d C2
| 0x0C6D 3181 | uint32 | EEPROM_UVLO_ACCELL_MM_S2_NORMAL | ??? | ff ff ff ffh | Power Panic acceleration mm per s2 normal | Power Panic | D3 Ax0c6d C16
| ^ | ^ | ^ | ??? | ^ | E-axis | ^ | D3 Ax0c79 C4
| ^ | ^ | ^ | ??? | ^ | Z-axis | ^ | D3 Ax0c75 C4
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0c71 C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0c6d C4
| 0x0C5D 3165 | uint32 | EEPROM_UVLO_ACCELL_MM_S2_SILENT | ??? | ff ff ff ffh | Power Panic acceleration mm per s2 silent | Power Panic | D3 Ax0c5d C16
| ^ | ^ | ^ | ??? | ^ | E-axis | ^ | D3 Ax0c69 C4
| ^ | ^ | ^ | ??? | ^ | Z-axis | ^ | D3 Ax0c65 C4
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0c61 C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0c5d C4
| 0x0C4D 3149 | float | EEPROM_UVLO_MAX_FEEDRATE_NORMAL | ??? | ff ff ff ffh | Power Panic max feedrate normal | Power Panic | D3 Ax0c4d C16
| ^ | ^ | ^ | ??? | ^ | E-axis | ^ | D3 Ax0d59 C4
| ^ | ^ | ^ | ??? | ^ | Z-axis | ^ | D3 Ax0d55 C4
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0d51 C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0c4d C4
| 0x0C3D 3133 | float | EEPROM_UVLO_MAX_FEEDRATE_SILENT | ??? | ff ff ff ffh | Power Panic max feedrate silent | Power Panic | D3 Ax0c3d C16
| ^ | ^ | ^ | ??? | ^ | E-axis | ^ | D3 Ax0d49 C4
| ^ | ^ | ^ | ??? | ^ | Z-axis | ^ | D3 Ax0d45 C4
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0d41 C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0c3d C4
| 0x0C39 3129 | float | EEPROM_UVLO_MIN_FEEDRATE | ??? | ff ff ff ffh | Power Panic min feedrate | Power Panic | D3 Ax0c39 C4
| 0x0C35 3125 | float | EEPROM_UVLO_MIN_TRAVEL_FEEDRATE | ??? | ff ff ff ffh | Power Panic min travel feedrate | Power Panic | D3 Ax0c35 C4
| 0x0C31 3121 | uint32 | EEPROM_UVLO_MIN_SEGMENT_TIME_US | ??? | ff ff ff ffh | Power Panic min segment time us | Power Panic | D3 Ax0c31 C4
| 0x0C21 3105 | float | EEPROM_UVLO_MAX_JERK | ??? | ff ff ff ffh | Power Panic max jerk | Power Panic | D3 Ax0c21 C16
| ^ | ^ | ^ | ??? | ^ | E-axis | ^ | D3 Ax0d2d C4
| ^ | ^ | ^ | ??? | ^ | Z-axis | ^ | D3 Ax0d29 C4
| ^ | ^ | ^ | ??? | ^ | Y-axis | ^ | D3 Ax0d25 C4
| ^ | ^ | ^ | ??? | ^ | X-axis | ^ | D3 Ax0c21 C4
| 0x0C11 3089 | uint8 | EEPROM_CHECK_FILAMENT | 01h 1 | ffh 255 | Check mode for filament is: __warn__ | LCD menu | D3 Ax0c11 C1
| ^ | ^ | ^ | 02h 2 | ^ | Check mode for filament is: __strict__ | ^ | ^
| ^ | ^ | ^ | 00h 0 | ^ | Check mode for filament is: __none__ | ^ | ^
|Address begin|Bit/Type | Name | Valid values | Default/FactoryReset | Description |Gcode/Function| Debug code
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--:
| 0x0012 18 | uint16 | EEPROM_FIRMWARE_VERSION_END | ??? | ff ffh 65535 | ??? | ??? | D3 Ax0012 C2
| 0x0010 16 | uint16 | EEPROM_FIRMWARE_VERSION_FLAVOR | ??? | ff ffh 65535 | ??? | ??? | D3 Ax0010 C2
| 0x000E 14 | uint16 | EEPROM_FIRMWARE_VERSION_REVISION | ??? | ff ffh 65535 | Firmware version revision number DEV/ALPHA/BETA/RC| ??? | D3 Ax000e C2
| 0x000C 12 | uint16 | EEPROM_FIRMWARE_VERSION_MINOR | ??? | ff ffh 65535 | Firmware version minor number | ??? | D3 Ax000c C2
| 0x000A 10 | uint16 | EEPROM_FIRMWARE_VERSION_MAJOR | ??? | ff ffh 65535 | Firmware version major number | ??? | D3 Ax000a C2
| 0x0000 0 | char | FW_PRUSA3D_MAGIC | ??? | ffffffffffffffffffff | __`PRUSA3DFW`__ | ??? | D3 Ax0000 C10
| Address begin | Bit/Type | Name | Valid values | Default/FactoryReset | Description | Gcode/Function| Debug code
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--:
| 0x0012 18 | uint16 | EEPROM_FIRMWARE_VERSION_END | ??? | ff ffh 65535 | ??? | ??? | D3 Ax0012 C2
| 0x0010 16 | uint16 | EEPROM_FIRMWARE_VERSION_FLAVOR | ??? | ff ffh 65535 | ??? | ??? | D3 Ax0010 C2
| 0x000E 14 | uint16 | EEPROM_FIRMWARE_VERSION_REVISION | ??? | ff ffh 65535 | Firmware version revision number DEV/ALPHA/BETA/RC| ??? | D3 Ax000e C2
| 0x000C 12 | uint16 | EEPROM_FIRMWARE_VERSION_MINOR | ??? | ff ffh 65535 | Firmware version minor number | ??? | D3 Ax000c C2
| 0x000A 10 | uint16 | EEPROM_FIRMWARE_VERSION_MAJOR | ??? | ff ffh 65535 | Firmware version major number | ??? | D3 Ax000a C2
| 0x0000 0 | char | FW_PRUSA3D_MAGIC | ??? | ffffffffffffffffffff | __`PRUSA3DFW`__ | ??? | D3 Ax0000 C10
*/
#define EEPROM_EMPTY_VALUE 0xFF
@ -437,11 +353,11 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
#define EEPROM_TOP 4096
#define EEPROM_SILENT 4095
#define EEPROM_LANG 4094
#define _EEPROM_FREE_NR10_ 4092 // uint16_t
#define _EEPROM_FREE_NR11_ 4090 // uint16_t
#define EEPROM_BABYSTEP_X 4092 //unused
#define EEPROM_BABYSTEP_Y 4090 //unused
#define EEPROM_BABYSTEP_Z 4088 //legacy, multiple values stored now in EEPROM_Sheets_base
#define EEPROM_CALIBRATION_STATUS_V1 4087 // legacy, used up to v3.11
#define _EEPROM_FREE_NR12_ (EEPROM_CALIBRATION_STATUS_V1 - 2) // uint16_t
#define EEPROM_CALIBRATION_STATUS 4087
#define EEPROM_BABYSTEP_Z0 4085
#define EEPROM_FILAMENTUSED 4081
// uint32_t
#define EEPROM_TOTALTIME 4077
@ -454,53 +370,55 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
// The offsets are saved as 16bit signed int, scaled to tenths of microns.
#define EEPROM_BED_CALIBRATION_Z_JITTER (EEPROM_BED_CALIBRATION_VEC_Y-2*8)
#define EEPROM_FARM_MODE (EEPROM_BED_CALIBRATION_Z_JITTER-1)
#define EEPROM_FREE_NR1 (EEPROM_FARM_MODE-1) // uint8_t
#define _EEPROM_FREE_NR2_ (EEPROM_FREE_NR1 - 2) // int16_t
#define EEPROM_FREE_NR1 (EEPROM_FARM_MODE-1)
#define EEPROM_FARM_NUMBER (EEPROM_FREE_NR1-2)
// Correction of the bed leveling, in micrometers.
// Maximum 50 micrometers allowed.
// Bed correction is valid if set to 1. If set to zero or 255, the successive 4 bytes are invalid.
#define EEPROM_BED_CORRECTION_VALID (_EEPROM_FREE_NR2_ - 1)
#define EEPROM_BED_CORRECTION_VALID (EEPROM_FARM_NUMBER-1)
#define EEPROM_BED_CORRECTION_LEFT (EEPROM_BED_CORRECTION_VALID-1)
#define EEPROM_BED_CORRECTION_RIGHT (EEPROM_BED_CORRECTION_LEFT-1)
#define EEPROM_BED_CORRECTION_FRONT (EEPROM_BED_CORRECTION_RIGHT-1)
#define EEPROM_BED_CORRECTION_REAR (EEPROM_BED_CORRECTION_FRONT-1)
#define EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY (EEPROM_BED_CORRECTION_REAR-1) // bool
#define _EEPROM_FREE_NR3_ (EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY - 1) // uint8_t
#define EEPROM_PROBE_TEMP_SHIFT (_EEPROM_FREE_NR3_ - 2*5) //5 x int for storing pinda probe temp shift relative to 50 C; unit: motor steps
#define EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY (EEPROM_BED_CORRECTION_REAR-1)
#define EEPROM_PRINT_FLAG (EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY-1)
#define EEPROM_PROBE_TEMP_SHIFT (EEPROM_PRINT_FLAG - 2*5) //5 x int for storing pinda probe temp shift relative to 50 C; unit: motor steps
#define EEPROM_TEMP_CAL_ACTIVE (EEPROM_PROBE_TEMP_SHIFT - 1)
#define _EEPROM_FREE_NR6_ (EEPROM_TEMP_CAL_ACTIVE - 2*4) //4 x int
#define EEPROM_CALIBRATION_STATUS_PINDA (_EEPROM_FREE_NR6_ - 1) //0 - not calibrated; 1 - calibrated
#define EEPROM_BOWDEN_LENGTH (EEPROM_TEMP_CAL_ACTIVE - 2*4) //4 x int for bowden lengths for multimaterial
#define EEPROM_CALIBRATION_STATUS_PINDA (EEPROM_BOWDEN_LENGTH - 1) //0 - not calibrated; 1 - calibrated
#define EEPROM_UVLO (EEPROM_CALIBRATION_STATUS_PINDA - 1) //1 - uvlo during print
#define EEPROM_UVLO_CURRENT_POSITION (EEPROM_UVLO-2*4) // 2 x float for current_position in X and Y axes
#define EEPROM_FILENAME (EEPROM_UVLO_CURRENT_POSITION - 8) //8chars to store filename without extension
#define EEPROM_FILE_POSITION (EEPROM_FILENAME - 4) //32 bit for uint32_t file position
#define EEPROM_UVLO_CURRENT_POSITION_Z (EEPROM_FILE_POSITION - 4) //float for current position in Z
#define EEPROM_UVLO_UNUSED_001 (EEPROM_UVLO_CURRENT_POSITION_Z - 1) // uint8_t (unused)
#define EEPROM_UVLO_TARGET_BED (EEPROM_UVLO_UNUSED_001 - 1)
#define EEPROM_UVLO_FEEDRATE (EEPROM_UVLO_TARGET_BED - 2) //uint16_t
#define EEPROM_UVLO_FAN_SPEED (EEPROM_UVLO_FEEDRATE - 1)
#define EEPROM_FAN_CHECK_ENABLED (EEPROM_UVLO_FAN_SPEED - 1)
#define EEPROM_UVLO_MESH_BED_LEVELING (EEPROM_FAN_CHECK_ENABLED - 9*2)
#define EEPROM_UVLO (EEPROM_CALIBRATION_STATUS_PINDA - 1) // uint8_t
#define EEPROM_UVLO_CURRENT_POSITION (EEPROM_UVLO-2*4) // 2 x float for current_position in X and Y axes
#define EEPROM_FILENAME (EEPROM_UVLO_CURRENT_POSITION - 8) //8chars to store filename without extension
#define EEPROM_FILE_POSITION (EEPROM_FILENAME - 4) //32 bit for uint32_t file position
#define EEPROM_UVLO_CURRENT_POSITION_Z (EEPROM_FILE_POSITION - 4) //float for current position in Z
#define EEPROM_UVLO_PRINT_TYPE (EEPROM_UVLO_CURRENT_POSITION_Z - 1) // uint8_t
#define EEPROM_UVLO_TARGET_BED (EEPROM_UVLO_PRINT_TYPE - 1)
#define EEPROM_UVLO_FEEDRATE (EEPROM_UVLO_TARGET_BED - 2) //uint16_t
#define EEPROM_UVLO_FAN_SPEED (EEPROM_UVLO_FEEDRATE - 1)
#define EEPROM_FAN_CHECK_ENABLED (EEPROM_UVLO_FAN_SPEED - 1)
#define EEPROM_UVLO_Z_MICROSTEPS (EEPROM_UVLO_MESH_BED_LEVELING - 2) // uint16_t (could be removed)
#define EEPROM_UVLO_E_ABS (EEPROM_UVLO_Z_MICROSTEPS - 1)
#define EEPROM_UVLO_CURRENT_POSITION_E (EEPROM_UVLO_E_ABS - 4) //float for current position in E
#define _EEPROM_FREE_NR7_ (EEPROM_FAN_CHECK_ENABLED - 9*2) // 9 x uint16_t
#define _EEPROM_FREE_NR8_ (_EEPROM_FREE_NR7_ - 2) // uint16_t
#define EEPROM_UVLO_E_ABS (_EEPROM_FREE_NR8_ - 1) // uint8_t
#define EEPROM_UVLO_CURRENT_POSITION_E (EEPROM_UVLO_E_ABS - 4) // float
#define EEPROM_UVLO_SAVED_SEGMENT_IDX (EEPROM_UVLO_CURRENT_POSITION_E - 2) //uint16_t
#define EEPROM_FREE_NR4 (EEPROM_UVLO_SAVED_SEGMENT_IDX - 1) // uint8_t
#define EEPROM_FREE_NR5 (EEPROM_FREE_NR4 - 1) // uint8_t
#define EEPROM_CRASH_DET (EEPROM_FREE_NR5 - 1) // uint8_t
#define EEPROM_CRASH_COUNT_Y (EEPROM_CRASH_DET - 1) // uint8_t
#define EEPROM_FSENSOR (EEPROM_CRASH_COUNT_Y - 1) // uint8_t
#define EEPROM_CRASH_COUNT_X (EEPROM_FSENSOR - 1) // uint8_t
#define EEPROM_FERROR_COUNT (EEPROM_CRASH_COUNT_X - 1) // uint8_t
#define EEPROM_POWER_COUNT (EEPROM_FERROR_COUNT - 1) // uint8_t
#define EEPROM_FREE_NR2 (EEPROM_UVLO_CURRENT_POSITION_E - 1) // FREE EEPROM SPACE
#define EEPROM_FREE_NR3 (EEPROM_FREE_NR2 - 1) // FREE EEPROM SPACE
#define EEPROM_FREE_NR4 (EEPROM_FREE_NR3 - 1) // FREE EEPROM SPACE
#define EEPROM_FREE_NR5 (EEPROM_FREE_NR4 - 1) // FREE EEPROM SPACE
// Crash detection mode EEPROM setting
#define EEPROM_CRASH_DET (EEPROM_FREE_NR5 - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-12)
// Crash detection counter Y (last print)
#define EEPROM_CRASH_COUNT_Y (EEPROM_CRASH_DET - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-15)
// Filament sensor on/off EEPROM setting
#define EEPROM_FSENSOR (EEPROM_CRASH_COUNT_Y - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-14)
// Crash detection counter X (last print)
#define EEPROM_CRASH_COUNT_X (EEPROM_FSENSOR - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-15)
// Filament runout/error coutner (last print)
#define EEPROM_FERROR_COUNT (EEPROM_CRASH_COUNT_X - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-16)
// Power loss errors (last print)
#define EEPROM_POWER_COUNT (EEPROM_FERROR_COUNT - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-17)
#define EEPROM_XYZ_CAL_SKEW (EEPROM_POWER_COUNT - 4) // float for skew backup
#define EEPROM_WIZARD_ACTIVE (EEPROM_XYZ_CAL_SKEW - 1) // 0: wizard not active, 1: wizard active, 2: wizard active without yes/no = forced calibrate Z after shipping/service prep.
@ -524,7 +442,7 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
#define EEPROM_POWER_COUNT_TOT (EEPROM_FERROR_COUNT_TOT - 2) // uint16
////////////////////////////////////////
// TMC2130 Accurate sensorless homing
// TMC2130 Accurate sensorless homing
// X-axis home origin (stepper phase in microsteps, 0..63 for 16ustep resolution)
#define EEPROM_TMC2130_HOME_X_ORIGIN (EEPROM_POWER_COUNT_TOT - 1) // uint8
@ -576,25 +494,24 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
// Sound Mode
#define EEPROM_SOUND_MODE (EEPROM_UVLO_TARGET_HOTEND-1) // uint8
#define EEPROM_SPOOL_JOIN (EEPROM_SOUND_MODE-1) //bool
#define EEPROM_AUTO_DEPLETE (EEPROM_SOUND_MODE-1) //bool
#define EEPROM_FSENS_RUNOUT_ENABLED (EEPROM_SPOOL_JOIN - 1) //bool
#define EEPROM_FSENS_OQ_MEASS_ENABLED (EEPROM_AUTO_DEPLETE - 1) //bool
#define EEPROM_MMU_FAIL_TOT (EEPROM_FSENS_RUNOUT_ENABLED - 2) //uint16_t
#define EEPROM_MMU_FAIL_TOT (EEPROM_FSENS_OQ_MEASS_ENABLED - 2) //uint16_t
#define EEPROM_MMU_FAIL (EEPROM_MMU_FAIL_TOT - 1) //uint8_t
#define EEPROM_MMU_LOAD_FAIL_TOT (EEPROM_MMU_FAIL - 2) // uint16_t
#define EEPROM_MMU_LOAD_FAIL (EEPROM_MMU_LOAD_FAIL_TOT - 1) // uint8_t
#define EEPROM_MMU_CUTTER_ENABLED (EEPROM_MMU_LOAD_FAIL - 1) // bool
#define EEPROM_MMU_LOAD_FAIL_TOT (EEPROM_MMU_FAIL - 2) //uint16_t
#define EEPROM_MMU_LOAD_FAIL (EEPROM_MMU_LOAD_FAIL_TOT - 1) //uint8_t
#define EEPROM_MMU_CUTTER_ENABLED (EEPROM_MMU_LOAD_FAIL - 1)
#define EEPROM_UVLO_MESH_BED_LEVELING_FULL (EEPROM_MMU_CUTTER_ENABLED - 12*12*2) //allow 12 calibration points for future expansion
#define _EEPROM_FREE_NR9_ (EEPROM_UVLO_MESH_BED_LEVELING_FULL-1) // uint8_t
#define EEPROM_MBL_MAGNET_ELIMINATION (_EEPROM_FREE_NR9_ - 1)
#define EEPROM_MBL_TYPE (EEPROM_UVLO_MESH_BED_LEVELING_FULL-1) //uint8_t for mesh bed leveling precision
#define EEPROM_MBL_MAGNET_ELIMINATION (EEPROM_MBL_TYPE -1)
#define EEPROM_MBL_POINTS_NR (EEPROM_MBL_MAGNET_ELIMINATION -1) //uint8_t number of points in one exis for mesh bed leveling
#define EEPROM_MBL_PROBE_NR (EEPROM_MBL_POINTS_NR-1) //number of measurements for each point
#define EEPROM_MMU_STEALTH (EEPROM_MBL_PROBE_NR-1) // bool
#define EEPROM_MMU_STEALTH (EEPROM_MBL_PROBE_NR-1)
#define EEPROM_CHECK_MODE (EEPROM_MMU_STEALTH-1) // uint8
#define EEPROM_NOZZLE_DIAMETER (EEPROM_CHECK_MODE-1) // uint8
@ -609,8 +526,8 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
#define EEPROM_FSENSOR_PCB (EEPROM_SHEETS_BASE-1) // uint8
#define EEPROM_FSENSOR_ACTION_NA (EEPROM_FSENSOR_PCB-1) // uint8
#define EEPROM_UVLO_SAVED_START_POSITION (EEPROM_FSENSOR_ACTION_NA - 4*4) // 4 x float for saved start position for all axes
#define EEPROM_UVLO_FEEDMULTIPLY (EEPROM_UVLO_SAVED_START_POSITION - 2) // uint16_t for feedmultiply
#define EEPROM_UVLO_SAVED_TARGET (EEPROM_FSENSOR_ACTION_NA - 4*4) // 4 x float for saved target for all axes
#define EEPROM_UVLO_FEEDMULTIPLY (EEPROM_UVLO_SAVED_TARGET - 2) // uint16_t for feedmultiply
#define EEPROM_BACKLIGHT_LEVEL_HIGH (EEPROM_UVLO_FEEDMULTIPLY-1) // uint8
#define EEPROM_BACKLIGHT_LEVEL_LOW (EEPROM_BACKLIGHT_LEVEL_HIGH-1) // uint8
@ -633,43 +550,8 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
#define EEPROM_ECOOL_ENABLE (EEPROM_JOB_ID-1) // uint8_t
#define EEPROM_FW_CRASH_FLAG (EEPROM_ECOOL_ENABLE-1) // uint8_t
#define EEPROM_THERMAL_MODEL_ENABLE (EEPROM_FW_CRASH_FLAG-1) // uint8_t
#define EEPROM_THERMAL_MODEL_P (EEPROM_THERMAL_MODEL_ENABLE-4) // float
#define EEPROM_THERMAL_MODEL_C (EEPROM_THERMAL_MODEL_P-4) // float
#define EEPROM_THERMAL_MODEL_R (EEPROM_THERMAL_MODEL_C-4*16) // float[16]
#define EEPROM_THERMAL_MODEL_Ta_corr (EEPROM_THERMAL_MODEL_R-4) // float
#define EEPROM_THERMAL_MODEL_W (EEPROM_THERMAL_MODEL_Ta_corr-4) // float
#define EEPROM_THERMAL_MODEL_E (EEPROM_THERMAL_MODEL_W-4) // float
#define EEPROM_FSENSOR_JAM_DETECTION (EEPROM_THERMAL_MODEL_E-1) // uint8_t
#define EEPROM_MMU_ENABLED (EEPROM_FSENSOR_JAM_DETECTION-1) // uint8_t
#define EEPROM_MMU_MATERIAL_CHANGES (EEPROM_MMU_ENABLED-4) // uint32_t
#define EEPROM_HEAT_BED_ON_LOAD_FILAMENT (EEPROM_MMU_MATERIAL_CHANGES-1) //uint8
#define EEPROM_CALIBRATION_STATUS_V2 (EEPROM_HEAT_BED_ON_LOAD_FILAMENT-1) //uint8
#define EEPROM_THERMAL_MODEL_U (EEPROM_CALIBRATION_STATUS_V2-4) //float
#define EEPROM_THERMAL_MODEL_V (EEPROM_THERMAL_MODEL_U-4) //float
#define EEPROM_THERMAL_MODEL_D (EEPROM_THERMAL_MODEL_V-4) //float
#define EEPROM_THERMAL_MODEL_L (EEPROM_THERMAL_MODEL_D-2) //uint16_t
#define EEPROM_THERMAL_MODEL_VER (EEPROM_THERMAL_MODEL_L-1) //uint8_t
#define EEPROM_KILL_MESSAGE (EEPROM_THERMAL_MODEL_VER-2) //PGM_P
#define EEPROM_KILL_PENDING_FLAG (EEPROM_KILL_MESSAGE-1) //uint8
#define EEPROM_FILENAME_EXTENSION (EEPROM_KILL_PENDING_FLAG - 3) // 3 x char
#define EEPROM_CUSTOM_MENDEL_NAME (EEPROM_FILENAME_EXTENSION-17) //char[17]
#define EEPROM_UVLO_Z_LIFTED (EEPROM_CUSTOM_MENDEL_NAME-1) //bool
#define EEPROM_UVLO_EXTRUDE_MINTEMP (EEPROM_UVLO_Z_LIFTED-2) //uint16_t
#define EEPROM_UVLO_ACCELL_MM_S2_NORMAL (EEPROM_UVLO_EXTRUDE_MINTEMP-4*4) // 4 x float
#define EEPROM_UVLO_ACCELL_MM_S2_SILENT (EEPROM_UVLO_ACCELL_MM_S2_NORMAL-4*4) // 4 x uint32_t
#define EEPROM_UVLO_MAX_FEEDRATE_NORMAL (EEPROM_UVLO_ACCELL_MM_S2_SILENT-4*4) // 4 x uint32_t
#define EEPROM_UVLO_MAX_FEEDRATE_SILENT (EEPROM_UVLO_MAX_FEEDRATE_NORMAL-4*4) // 4 x float
#define EEPROM_UVLO_MIN_FEEDRATE (EEPROM_UVLO_MAX_FEEDRATE_SILENT-4) //float
#define EEPROM_UVLO_MIN_TRAVEL_FEEDRATE (EEPROM_UVLO_MIN_FEEDRATE-4) //float
#define EEPROM_UVLO_MIN_SEGMENT_TIME_US (EEPROM_UVLO_MIN_TRAVEL_FEEDRATE-4) //uint32_t
#define EEPROM_UVLO_MAX_JERK (EEPROM_UVLO_MIN_SEGMENT_TIME_US-4*4) // 4 x float
#define EEPROM_CHECK_FILAMENT (EEPROM_UVLO_MAX_JERK-1) // uint8_t
//This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items.
#define EEPROM_LAST_ITEM EEPROM_CHECK_FILAMENT
#define EEPROM_LAST_ITEM EEPROM_FW_CRASH_FLAG
// !!!!!
// !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
// !!!!!
@ -702,7 +584,7 @@ enum
#ifdef __cplusplus
void eeprom_init();
void eeprom_adjust_bed_reset();
bool eeprom_is_sheet_initialized(uint8_t sheet_num);
struct SheetName
{
char c[sizeof(Sheet::name) + 1];
@ -710,50 +592,6 @@ struct SheetName
void eeprom_default_sheet_name(uint8_t index, SheetName &sheetName);
int8_t eeprom_next_initialized_sheet(int8_t sheet);
void eeprom_switch_to_next_sheet();
bool eeprom_is_sheet_initialized(uint8_t sheet_num);
bool eeprom_is_initialized_block(const void *__p, size_t __n);
void eeprom_update_block_P(const void *__src, void *__dst, size_t __n);
void eeprom_toggle(uint8_t *__p);
void eeprom_increment_byte(uint8_t *__p);
void eeprom_increment_word(uint16_t *__p);
void eeprom_increment_dword(uint32_t *__p);
void eeprom_add_byte(uint8_t *__p, uint8_t add);
void eeprom_add_word(uint16_t *__p, uint16_t add);
void eeprom_add_dword(uint32_t *__p, uint32_t add);
uint8_t eeprom_init_default_byte(uint8_t *__p, uint8_t def);
uint16_t eeprom_init_default_word(uint16_t *__p, uint16_t def);
uint32_t eeprom_init_default_dword(uint32_t *__p, uint32_t def);
void eeprom_init_default_float(float *__p, float def);
void eeprom_init_default_block(void *__p, size_t __n, const void *def);
void eeprom_init_default_block_P(void *__p, size_t __n, const void *def);
/// Updates eeprom byte and notifies the changed eeprom address (just the address!) onto the serial line
#ifndef DEBUG_EEPROM_CHANGES
void eeprom_write_byte_notify(uint8_t *dst, uint8_t value);
void eeprom_update_byte_notify(uint8_t *dst, uint8_t value);
void eeprom_write_word_notify(uint16_t *dst, uint16_t value);
void eeprom_update_word_notify(uint16_t *dst, uint16_t value);
void eeprom_write_dword_notify(uint32_t *dst, uint32_t value);
void eeprom_update_dword_notify(uint32_t *dst, uint32_t value);
void eeprom_write_float_notify(float *dst, float value);
void eeprom_update_float_notify(float *dst, float value);
void eeprom_write_block_notify(const void *__src, void *__dst , size_t __size);
void eeprom_update_block_notify(const void *__src, void *__dst, size_t __size);
#else
void eeprom_write_byte_notify(uint8_t *dst, uint8_t value, bool active = true);
void eeprom_update_byte_notify(uint8_t *dst, uint8_t value, bool active = true);
void eeprom_write_word_notify(uint16_t *dst, uint16_t value, bool active = true);
void eeprom_update_word_notify(uint16_t *dst, uint16_t value, bool active = true);
void eeprom_write_dword_notify(uint32_t *dst, uint32_t value, bool active = true);
void eeprom_update_dword_notify(uint32_t *dst, uint32_t value, bool active = true);
void eeprom_write_float_notify(float *dst, float value, bool active = true);
void eeprom_update_float_notify(float *dst, float value, bool active = true);
void eeprom_write_block_notify(const void *__src, void *__dst , size_t __size, bool active = true);
void eeprom_update_block_notify(const void *__src, void *__dst, size_t __size , bool active = true);
#endif //DEBUG_EEPROM_CHANGES
#endif
#endif // EEPROM_H

View File

@ -1,362 +0,0 @@
// fan control and check
#include "fancheck.h"
#include "ultralcd.h"
#include "sound.h"
#include "messages.h"
#include "temperature.h"
#include "stepper.h"
#include "stopwatch.h"
#define FAN_CHECK_PERIOD 5000 //5s
#define FAN_CHECK_DURATION 100 //100ms
//Macro for print fan speed
#define FAN_PULSE_WIDTH_LIMIT ((fanSpeed > 100) ? 3 : 4) //time in ms
#ifdef FANCHECK
volatile uint8_t fan_check_error = EFCE_OK;
#endif
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
static uint32_t t_fan_rising_edge;
#endif // #if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef EXTRUDER_ALTFAN_DETECT
static struct
{
uint8_t isAltfan : 1;
uint8_t altfanOverride : 1;
} altfanStatus;
#endif //EXTRUDER_ALTFAN_DETECT
unsigned long extruder_autofan_last_check = _millis();
bool fan_measuring = false;
static uint8_t fanState = 0;
#endif
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#if defined(FAN_PIN) && FAN_PIN > -1
#if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN
#error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN"
#endif
#endif
void setExtruderAutoFanState(uint8_t state)
{
//If bit 1 is set (0x02), then the hotend fan speed won't be adjusted according to temperature. Useful for forcing
//the fan to either On or Off during certain tests/errors.
fanState = state;
newFanSpeed = 0;
if (fanState & 0x01)
{
#ifdef EXTRUDER_ALTFAN_DETECT
if (altfanStatus.isAltfan && !altfanStatus.altfanOverride) newFanSpeed = EXTRUDER_ALTFAN_SPEED_SILENT;
else newFanSpeed = EXTRUDER_AUTO_FAN_SPEED;
#else //EXTRUDER_ALTFAN_DETECT
newFanSpeed = EXTRUDER_AUTO_FAN_SPEED;
#endif //EXTRUDER_ALTFAN_DETECT
}
timer4_set_fan0(newFanSpeed);
}
#if (defined(FANCHECK) && (((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1)))))
void countFanSpeed()
{
//SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]);
fan_speed[0] = (fan_edge_counter[0] * (float(250) / (_millis() - extruder_autofan_last_check)));
fan_speed[1] = (fan_edge_counter[1] * (float(250) / (_millis() - extruder_autofan_last_check)));
/*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(_millis() - extruder_autofan_last_check);
SERIAL_ECHOPGM("hotend fan speed:"); MYSERIAL.print(fan_speed[0]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[0]);
SERIAL_ECHOPGM("print fan speed:"); MYSERIAL.print(fan_speed[1]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[1]);
SERIAL_ECHOLNPGM(" ");*/
fan_edge_counter[0] = 0;
fan_edge_counter[1] = 0;
}
//! Prints serialMsg to serial port, displays lcdMsg onto the LCD and beeps.
//! Extracted from fanSpeedError to save some space.
//! @param serialMsg pointer into PROGMEM, this text will be printed to the serial port
//! @param lcdMsg pointer into PROGMEM, this text will be printed onto the LCD
static void fanSpeedErrorBeep(const char *serialMsg, const char *lcdMsg){
SERIAL_ECHOLNRPGM(serialMsg);
if (get_message_level() == 0) {
Sound_MakeCustom(200,0,true);
LCD_ALERTMESSAGERPGM(lcdMsg);
}
}
void fanSpeedError(unsigned char _fan) {
if (fan_check_error == EFCE_REPORTED) return;
fan_check_error = EFCE_REPORTED;
if (printJobOngoing()) {
// A print is ongoing, pause the print normally
if(!printingIsPaused()) {
if (usb_timer.running())
lcd_pause_usb_print();
else
lcd_pause_print();
}
}
else {
// Nothing is going on, but still turn off heaters and report the error
setTargetHotend(0);
heating_status = HeatingStatus::NO_HEATING;
}
switch (_fan) {
case 0: // extracting the same code from case 0 and case 1 into a function saves 72B
fanSpeedErrorBeep(PSTR("Hotend fan speed is lower than expected"), MSG_FANCHECK_HOTEND);
break;
case 1:
fanSpeedErrorBeep(PSTR("Print fan speed is lower than expected"), MSG_FANCHECK_PRINT);
break;
}
}
void checkFanSpeed()
{
uint8_t max_fan_errors[2];
#ifdef FAN_SOFT_PWM
max_fan_errors[1] = 3; // 15 seconds (Print fan)
max_fan_errors[0] = 2; // 10 seconds (Hotend fan)
#else //FAN_SOFT_PWM
max_fan_errors[1] = 15; // 15 seconds (Print fan)
max_fan_errors[0] = 5; // 5 seconds (Hotend fan)
#endif //FAN_SOFT_PWM
if(fans_check_enabled)
fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0);
static uint8_t fan_speed_errors[2] = { 0,0 };
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 >-1))
if ((fan_speed[0] < 20) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)){ fan_speed_errors[0]++;}
else fan_speed_errors[0] = 0;
#endif
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
if ((fan_speed[1] < 5) && ((blocks_queued() ? block_buffer[block_buffer_tail].fan_speed : fanSpeed) > MIN_PRINT_FAN_SPEED)) fan_speed_errors[1]++;
else fan_speed_errors[1] = 0;
#endif
// drop the fan_check_error flag when both fans are ok
if( fan_speed_errors[0] == 0 && fan_speed_errors[1] == 0 && fan_check_error == EFCE_REPORTED){
// we may even send some info to the LCD from here
fan_check_error = EFCE_FIXED;
}
if ((fan_check_error == EFCE_FIXED) && !printer_active()){
fan_check_error = EFCE_OK; //if the issue is fixed while the printer is doing nothing, reenable processing immediately.
lcd_reset_alert_level(); //for another fan speed error
lcd_setstatuspgm(MSG_WELCOME); // Reset the status line message to visually show the error is gone
}
if (fans_check_enabled && (fan_check_error != EFCE_REPORTED))
{
for (uint8_t fan = 0; fan < 2; fan++)
{
if (fan_speed_errors[fan] > max_fan_errors[fan])
{
fan_speed_errors[fan] = 0;
fanSpeedError(fan);
}
}
}
}
#endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
void setup_fan_interrupt() {
//INT7
DDRE &= ~(1 << 7); //input pin
PORTE &= ~(1 << 7); //no internal pull-up
//start with sensing rising edge
EICRB &= ~(1 << 6);
EICRB |= (1 << 7);
//enable INT7 interrupt
EIMSK |= (1 << 7);
}
// The fan interrupt is triggered at maximum 325Hz (may be a bit more due to component tollerances),
// and it takes 4.24 us to process (the interrupt invocation overhead not taken into account).
ISR(INT7_vect) {
//measuring speed now works for fanSpeed > 18 (approximately), which is sufficient because MIN_PRINT_FAN_SPEED is higher
#ifdef FAN_SOFT_PWM
if (!fan_measuring || (fanSpeedSoftPwm < MIN_PRINT_FAN_SPEED)) return;
#else //FAN_SOFT_PWM
if (fanSpeed < MIN_PRINT_FAN_SPEED) return;
#endif //FAN_SOFT_PWM
if ((1 << 6) & EICRB) { //interrupt was triggered by rising edge
t_fan_rising_edge = millis_nc();
}
else { //interrupt was triggered by falling edge
if ((millis_nc() - t_fan_rising_edge) >= FAN_PULSE_WIDTH_LIMIT) {//this pulse was from sensor and not from pwm
fan_edge_counter[1] += 2; //we are currently counting all edges so lets count two edges for one pulse
}
}
EICRB ^= (1 << 6); //change edge
}
#endif //(defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
#ifdef EXTRUDER_ALTFAN_DETECT
ISR(INT6_vect) {
fan_edge_counter[0]++;
}
bool extruder_altfan_detect()
{
// override isAltFan setting for detection
altfanStatus.isAltfan = 0;
// During initialisation, use the EEPROM value
altfanStatus.altfanOverride = eeprom_init_default_byte((uint8_t*)EEPROM_ALTFAN_OVERRIDE, 0);
setExtruderAutoFanState(3);
SET_INPUT(TACH_0);
CRITICAL_SECTION_START;
EICRB &= ~(1 << ISC61);
EICRB |= (1 << ISC60);
EIMSK |= (1 << INT6);
fan_edge_counter[0] = 0;
CRITICAL_SECTION_END;
extruder_autofan_last_check = _millis();
_delay(1000);
EIMSK &= ~(1 << INT6);
countFanSpeed();
// restore fan state
altfanStatus.isAltfan = fan_speed[0] > 100;
setExtruderAutoFanState(1);
return altfanStatus.isAltfan;
}
void altfanOverride_toggle()
{
altfanStatus.altfanOverride = !altfanStatus.altfanOverride;
eeprom_update_byte_notify((uint8_t *)EEPROM_ALTFAN_OVERRIDE, altfanStatus.altfanOverride);
}
bool altfanOverride_get()
{
return altfanStatus.altfanOverride;
}
#endif //EXTRUDER_ALTFAN_DETECT
void checkExtruderAutoFans()
{
#if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
if (!(fanState & 0x02))
{
fanState &= ~1;
fanState |= current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE;
fanState |= get_temp_error();
}
setExtruderAutoFanState(fanState);
#endif
}
#endif // any extruder auto fan pins set
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
void readFanTach() {
static bool fan_state[2];
#ifdef FAN_SOFT_PWM
if (READ(TACH_0) != fan_state[0]) {
if(fan_measuring) fan_edge_counter[0] ++;
fan_state[0] = !fan_state[0];
}
#else //FAN_SOFT_PWM
if (READ(TACH_0) != fan_state[0]) {
fan_edge_counter[0] ++;
fan_state[0] = !fan_state[0];
}
#endif
//if (READ(TACH_1) != fan_state[1]) {
// fan_edge_counter[1] ++;
// fan_state[1] = !fan_state[1];
//}
}
#endif //TACH_0
void checkFans()
{
#ifndef DEBUG_DISABLE_FANCHECK
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef FAN_SOFT_PWM
#ifdef FANCHECK
if ((_millis() - extruder_autofan_last_check > FAN_CHECK_PERIOD) && (!fan_measuring)) {
extruder_autofan_last_check = _millis();
fanSpeedBckp = fanSpeedSoftPwm;
if (fanSpeedSoftPwm >= MIN_PRINT_FAN_SPEED) { //if we are in rage where we are doing fan check, set full PWM range for a short time to measure fan RPM by reading tacho signal without modulation by PWM signal
// printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
fanSpeedSoftPwm = 255;
}
fan_measuring = true;
}
if ((_millis() - extruder_autofan_last_check > FAN_CHECK_DURATION) && (fan_measuring)) {
countFanSpeed();
checkFanSpeed();
//printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
fanSpeedSoftPwm = fanSpeedBckp;
//printf_P(PSTR("fan PWM: %d; extr fanSpeed measured: %d; print fan speed measured: %d \n"), fanSpeedBckp, fan_speed[0], fan_speed[1]);
extruder_autofan_last_check = _millis();
fan_measuring = false;
}
#endif //FANCHECK
checkExtruderAutoFans();
#else //FAN_SOFT_PWM
if(_millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently
{
#if (defined(FANCHECK) && ((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1))))
countFanSpeed();
checkFanSpeed();
#endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
checkExtruderAutoFans();
extruder_autofan_last_check = _millis();
}
#endif //FAN_SOFT_PWM
#endif
#endif //DEBUG_DISABLE_FANCHECK
}
void resetFanCheck() {
fan_measuring = false;
extruder_autofan_last_check = _millis();
}
void hotendFanSetFullSpeed()
{
#ifdef EXTRUDER_ALTFAN_DETECT
altfanStatus.altfanOverride = 1; //full speed
#endif //EXTRUDER_ALTFAN_DETECT
resetFanCheck();
setExtruderAutoFanState(3);
SET_OUTPUT(FAN_PIN);
#ifdef FAN_SOFT_PWM
fanSpeedSoftPwm = 255;
#else //FAN_SOFT_PWM
analogWrite(FAN_PIN, 255);
#endif //FAN_SOFT_PWM
fanSpeed = 255;
}
void hotendDefaultAutoFanState()
{
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef EXTRUDER_ALTFAN_DETECT
altfanStatus.altfanOverride = eeprom_read_byte((uint8_t*)EEPROM_ALTFAN_OVERRIDE);
#endif
resetFanCheck();
setExtruderAutoFanState(1);
#endif
}

View File

@ -1,42 +0,0 @@
// fan control and check
#pragma once
#include "Configuration.h"
#include "config.h"
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
enum {
EFCE_OK = 0, //!< normal operation, both fans are ok
EFCE_FIXED, //!< previous fan error was fixed
EFCE_REPORTED //!< fan error detected and reported to LCD and serial
};
extern volatile uint8_t fan_check_error;
void readFanTach();
#endif //(defined(TACH_0))
#if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
void setup_fan_interrupt();
#endif // (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
#ifdef EXTRUDER_ALTFAN_DETECT
extern bool extruder_altfan_detect();
extern void altfanOverride_toggle();
extern bool altfanOverride_get();
#endif //EXTRUDER_ALTFAN_DETECT
#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
#ifdef FAN_SOFT_PWM
extern bool fan_measuring;
#endif //FAN_SOFT_PWM
extern unsigned long extruder_autofan_last_check;
void setExtruderAutoFanState(uint8_t state);
void checkExtruderAutoFans();
#endif
void checkFans();
void resetFanCheck(); // resets the fan measuring state
void hotendFanSetFullSpeed();
void hotendDefaultAutoFanState();

View File

@ -62,7 +62,7 @@
/// Write to a pin wrapper, non critical.
/// This macro is cheaper than WRITE(IO,v) on ports H,I,J,K,L, as _WRITE_C disables / enables interrupts
/// and stores the old CPU flags on the stack.
/// This macro should only be called, where it cannot be interrupted.
/// This macro should only be called, where it cannot be interrupted.
#define WRITE_NC(IO, v) _WRITE_NC(IO, v)
/// toggle a pin wrapper
@ -931,10 +931,10 @@ pins
#define TXD DIO1
// SPI
#define SCK 52
#define MISO 50
#define MOSI 51
#define SS 53
#define SCK DIO52
#define MISO DIO50
#define MOSI DIO51
#define SS DIO53
// TWI (I2C)
#define SCL DIO21
@ -2067,7 +2067,7 @@ pins
pins
*/
//#define AT90USBxx_TEENSYPP_ASSIGNMENTS // Use Teensy++ 2.0 assignments
//#define AT90USBxx_TEENSYPP_ASSIGNMENTS // Use Teensy++ 2.0 assignments
#ifndef AT90USBxx_TEENSYPP_ASSIGNMENTS // Use traditional Marlin pin assignments
#define DIO0_PIN PINA0
@ -2707,8 +2707,8 @@ pins
/*
AT90USB 51 50 49 48 47 46 45 44 10 11 12 13 14 15 16 17 35 36 37 38 39 40 41 42 25 26 27 28 29 30 31 32 33 34 43 09 18 19 01 02 61 60 59 58 57 56 55 54
Port A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7
AT90USB 51 50 49 48 47 46 45 44 10 11 12 13 14 15 16 17 35 36 37 38 39 40 41 42 25 26 27 28 29 30 31 32 33 34 43 09 18 19 01 02 61 60 59 58 57 56 55 54
Port A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7
Marlin 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
Teensy 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45
The pins 46 and 47 are not supported by Teensyduino, but are supported below.

View File

@ -4,13 +4,127 @@
//! @brief First layer (Z offset) calibration
#include "first_lay_cal.h"
#include "Configuration_var.h"
#include "Configuration_prusa.h"
#include "language.h"
#include "Marlin.h"
#include "messages.h"
#include "cmdqueue.h"
#include "mmu2.h"
#include "mmu.h"
#include <avr/pgmspace.h>
#include <math.h>
//! @brief Wait for preheat
void lay1cal_wait_preheat()
{
static const char cmd_preheat_0[] PROGMEM = "M107";
static const char cmd_preheat_1[] PROGMEM = "M190";
static const char cmd_preheat_2[] PROGMEM = "M109";
static const char cmd_preheat_4[] PROGMEM = "G28";
static const char cmd_preheat_5[] PROGMEM = "G92 E0.0";
const char * const preheat_cmd[] =
{
cmd_preheat_0,
cmd_preheat_1,
cmd_preheat_2,
_T(MSG_M117_V2_CALIBRATION),
cmd_preheat_4,
cmd_preheat_5,
};
for (uint8_t i = 0; i < (sizeof(preheat_cmd)/sizeof(preheat_cmd[0])); ++i)
{
enquecommand_P(preheat_cmd[i]);
}
}
//! @brief Load filament
//! @param cmd_buffer character buffer needed to format gcodes
//! @param filament filament to use (applies for MMU only)
void lay1cal_load_filament(char *cmd_buffer, uint8_t filament)
{
if (mmu_enabled)
{
enquecommand_P(PSTR("M83"));
enquecommand_P(PSTR("G1 Y-3.0 F1000.0"));
enquecommand_P(PSTR("G1 Z0.4 F1000.0"));
sprintf_P(cmd_buffer, PSTR("T%d"), filament);
enquecommand(cmd_buffer);
}
}
//! @brief Print intro line
void lay1cal_intro_line()
{
static const char cmd_intro_mmu_3[] PROGMEM = "G1 X55.0 E32.0 F1073.0";
static const char cmd_intro_mmu_4[] PROGMEM = "G1 X5.0 E32.0 F1800.0";
static const char cmd_intro_mmu_5[] PROGMEM = "G1 X55.0 E8.0 F2000.0";
static const char cmd_intro_mmu_6[] PROGMEM = "G1 Z0.3 F1000.0";
static const char cmd_intro_mmu_7[] PROGMEM = "G92 E0.0";
static const char cmd_intro_mmu_8[] PROGMEM = "G1 X240.0 E25.0 F2200.0";
static const char cmd_intro_mmu_9[] PROGMEM = "G1 Y-2.0 F1000.0";
static const char cmd_intro_mmu_10[] PROGMEM = "G1 X55.0 E25 F1400.0";
static const char cmd_intro_mmu_11[] PROGMEM = "G1 Z0.20 F1000.0";
static const char cmd_intro_mmu_12[] PROGMEM = "G1 X5.0 E4.0 F1000.0";
static const char * const intro_mmu_cmd[] PROGMEM =
{
cmd_intro_mmu_3,
cmd_intro_mmu_4,
cmd_intro_mmu_5,
cmd_intro_mmu_6,
cmd_intro_mmu_7,
cmd_intro_mmu_8,
cmd_intro_mmu_9,
cmd_intro_mmu_10,
cmd_intro_mmu_11,
cmd_intro_mmu_12,
};
if (mmu_enabled)
{
for (uint8_t i = 0; i < (sizeof(intro_mmu_cmd)/sizeof(intro_mmu_cmd[0])); ++i)
{
enquecommand_P(static_cast<char*>(pgm_read_ptr(&intro_mmu_cmd[i])));
}
}
else
{
enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0"));
enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0"));
}
}
//! @brief Setup for printing meander
void lay1cal_before_meander()
{
static const char cmd_pre_meander_0[] PROGMEM = "G92 E0.0";
static const char cmd_pre_meander_1[] PROGMEM = "G21"; //set units to millimeters TODO unsupported command
static const char cmd_pre_meander_2[] PROGMEM = "G90"; //use absolute coordinates
static const char cmd_pre_meander_3[] PROGMEM = "M83"; //use relative distances for extrusion TODO: duplicate
static const char cmd_pre_meander_4[] PROGMEM = "G1 E-1.50000 F2100.00000";
static const char cmd_pre_meander_5[] PROGMEM = "G1 Z5 F7200.000";
static const char cmd_pre_meander_6[] PROGMEM = "M204 S1000"; //set acceleration
static const char cmd_pre_meander_7[] PROGMEM = "G1 F4000";
static const char * const cmd_pre_meander[] PROGMEM =
{
cmd_pre_meander_0,
cmd_pre_meander_1,
cmd_pre_meander_2,
cmd_pre_meander_3,
cmd_pre_meander_4,
cmd_pre_meander_5,
cmd_pre_meander_6,
cmd_pre_meander_7,
};
for (uint8_t i = 0; i < (sizeof(cmd_pre_meander)/sizeof(cmd_pre_meander[0])); ++i)
{
enquecommand_P(static_cast<char*>(pgm_read_ptr(&cmd_pre_meander[i])));
}
}
//! @brief Count extrude length
//!
@ -18,247 +132,83 @@
//! @param extrusion_width extrusion width in mm
//! @param extrusion_length extrusion length in mm
//! @return filament length in mm which needs to be extruded to form line
static constexpr float __attribute__((noinline)) count_e(float layer_height, float extrusion_width, float extrusion_length, float filament_diameter=1.75f)
static constexpr float count_e(float layer_height, float extrusion_width, float extrusion_length)
{
return (extrusion_length * ((M_PI * pow(layer_height, 2)) / 4 + layer_height * (extrusion_width - layer_height))) / ((M_PI * pow(filament_diameter, 2)) / 4);
return (extrusion_length * layer_height * extrusion_width / (M_PI * pow(1.75, 2) / 4));
}
//! @brief Extrusion spacing
//!
//! @param layer_height layer height in mm
//! @param extrusion_width extrusion width in mm
//! @return filament length in mm which needs to be extruded to form line
static constexpr float spacing(float layer_height, float extrusion_width, float overlap_factor=1.f)
{
return extrusion_width - layer_height * (overlap_factor - M_PI/4);
}
// Common code extracted into one function to reduce code size
static void lay1cal_common_enqueue_loop(const char * const * cmd_sequence, const uint8_t steps) {
for (uint8_t i = 0; i < steps; ++i)
{
void * const pgm_ptr = pgm_read_ptr(cmd_sequence + i);
// M702 is currently only used with MMU enabled
if (pgm_ptr == MSG_M702 && !MMU2::mmu2.Enabled()) {
continue;
}
enquecommand_P(static_cast<char*>(pgm_ptr));
}
}
static const char extrude_fmt_X[] PROGMEM = "G1X%.4fE%.4f";
static const char extrude_fmt_Y[] PROGMEM = "G1Y%.4fE%.4f";
static const char zero_extrusion[] PROGMEM = "G92E0";
static const char feedrate_F1080[] PROGMEM = "G1F1080";
#ifndef NEW_FIRST_LAYER_CAL
static constexpr int8_t invert = 1;
static constexpr float short_length = 20;
static constexpr float square_width = short_length;
#else
static constexpr int8_t invert = -1;
static constexpr float short_length = 13.2812; //max_pos[1]/2 / meander * 2
static constexpr float square_width = short_length*2;
#endif //NEW_FIRST_LAYER_CAL
static constexpr float long_length = 150;
//! @brief Wait for preheat
void lay1cal_wait_preheat()
{
static const char preheat_cmd_2[] PROGMEM = "M190";
static const char preheat_cmd_3[] PROGMEM = "M109";
static const char preheat_cmd_4[] PROGMEM = "G28";
static const char * const preheat_cmd[] PROGMEM =
{
MSG_M107,
preheat_cmd_2,
preheat_cmd_3,
preheat_cmd_4,
zero_extrusion
};
lay1cal_common_enqueue_loop(preheat_cmd, sizeof(preheat_cmd)/sizeof(preheat_cmd[0]));
}
//! @brief Load filament
//! @param cmd_buffer character buffer needed to format gcodes
//! @param filament filament to use (applies for MMU only)
//! @returns true if extra purge distance is needed in case of MMU prints (after a toolchange), otherwise false
bool lay1cal_load_filament(uint8_t filament)
{
if (MMU2::mmu2.Enabled())
{
enquecommand_P(MSG_M83);
enquecommand_P(PSTR("G1Y-3F1000"));
enquecommand_P(PSTR("G1Z0.4"));
uint8_t currentTool = MMU2::mmu2.get_current_tool();
if(currentTool == filament ){
// already have the correct tool loaded - do nothing
return false;
} else if( currentTool != (uint8_t)MMU2::FILAMENT_UNKNOWN){
// some other slot is loaded, perform an unload first
enquecommand_P(MSG_M702);
}
// perform a toolchange
enquecommandf_P(PSTR("T%d"), filament);
return true;
}
return false;
}
//! @brief Print intro line
//! @param extraPurgeNeeded false if the first MMU-related "G1 E29" have to be skipped because the nozzle is already full of filament
//! @param layer_height the height of the calibration layer
//! @param extrusion_width the width of the extrusion layer
void lay1cal_intro_line(bool extraPurgeNeeded, float layer_height, float extrusion_width)
{
static const char cmd_intro_mmu_3[] PROGMEM = "G1X55E29F1073";
static const char cmd_intro_mmu_4[] PROGMEM = "G1X5E29F1800";
static const char cmd_intro_mmu_5[] PROGMEM = "G1X55E8F2000";
static const char cmd_intro_mmu_6[] PROGMEM = "G1Z0.3F1000";
static const char cmd_intro_mmu_8[] PROGMEM = "G1X240E25F2200";
static const char cmd_intro_mmu_9[] PROGMEM = "G1Y-2F1000";
static const char cmd_intro_mmu_10[] PROGMEM = "G1X202.5E8F1400";
static const char cmd_intro_mmu_11[] PROGMEM = "G1Z0.2";
static const char * const cmd_intro_mmu[] PROGMEM =
{
// first 2 items are only relevant if filament was not loaded - i.e. extraPurgeNeeded == true
cmd_intro_mmu_3,
cmd_intro_mmu_4,
cmd_intro_mmu_5,
cmd_intro_mmu_6,
zero_extrusion,
cmd_intro_mmu_8,
cmd_intro_mmu_9,
cmd_intro_mmu_10,
cmd_intro_mmu_11,
};
if (MMU2::mmu2.Enabled())
{
for (uint8_t i = (extraPurgeNeeded ? 0 : 2); i < (sizeof(cmd_intro_mmu)/sizeof(cmd_intro_mmu[0])); ++i)
{
enquecommand_P(static_cast<char*>(pgm_read_ptr(&cmd_intro_mmu[i])));
}
}
else
{
enquecommand_P(feedrate_F1080); //fixed velocity for the intro line
enquecommandf_P(extrude_fmt_X, 60.f, count_e(layer_height, extrusion_width * 4.f, 60));
enquecommandf_P(extrude_fmt_X, 202.5f, count_e(layer_height, extrusion_width * 8.f, 142.5));
}
}
//! @brief Setup for printing meander
void lay1cal_before_meander()
{
#ifndef NEW_FIRST_LAYER_CAL
static const char cmd_pre_meander_4[] PROGMEM = "G1E-1.5F2100";
static const char cmd_pre_meander_5[] PROGMEM = "G1Z5F7200";
#endif //NEW_FIRST_LAYER_CAL
static const char cmd_pre_meander_6[] PROGMEM = "M204S1000"; //set acceleration
static const char * const cmd_pre_meander[] PROGMEM =
{
zero_extrusion,
MSG_G90,
MSG_M83, // use relative distances for extrusion
#ifndef NEW_FIRST_LAYER_CAL
cmd_pre_meander_4,
cmd_pre_meander_5,
#endif //NEW_FIRST_LAYER_CAL
cmd_pre_meander_6,
};
lay1cal_common_enqueue_loop(cmd_pre_meander, (sizeof(cmd_pre_meander)/sizeof(cmd_pre_meander[0])));
}
//! @brief Print meander start
void lay1cal_meander_start(float layer_height, float extrusion_width)
{
#ifndef NEW_FIRST_LAYER_CAL
enquecommand_P(PSTR("G1X50Y155"));
#endif //_NEW_FIRST_LAYER_CAL
static const char fmt1[] PROGMEM = "G1Z%.2f";
enquecommandf_P(fmt1, layer_height);
enquecommand_P(feedrate_F1080);
enquecommand_P(MSG_G91); //enable relative XYZ
#ifdef NEW_FIRST_LAYER_CAL
enquecommandf_P(extrude_fmt_Y, short_length, count_e(layer_height, extrusion_width, short_length));
enquecommandf_P(extrude_fmt_X, long_length*invert, count_e(layer_height, extrusion_width, long_length));
enquecommandf_P(extrude_fmt_Y, -short_length*invert, count_e(layer_height, extrusion_width, short_length));
#else
enquecommandf_P(extrude_fmt_X, 25.f*invert, count_e(layer_height, extrusion_width * 4.f, 25));
enquecommandf_P(extrude_fmt_X, 25.f*invert, count_e(layer_height, extrusion_width * 2.f, 25));
enquecommandf_P(extrude_fmt_X, 100.f*invert, count_e(layer_height, extrusion_width, 100));
enquecommandf_P(extrude_fmt_Y, -20.f*invert, count_e(layer_height, extrusion_width, 20));
#endif //_NEW_FIRST_LAYER_CAL
}
static const float width = 0.4; //!< line width
static const float length = 20 - width; //!< line length
static const float height = 0.2; //!< layer height TODO This is wrong, as current Z height is 0.15 mm
static const float extr = count_e(height, width, length); //!< E axis movement needed to print line
//! @brief Print meander
//! @param cmd_buffer character buffer needed to format gcodes
void lay1cal_meander(float layer_height, float extrusion_width)
void lay1cal_meander(char *cmd_buffer)
{
const float long_extrusion = count_e(layer_height, extrusion_width, long_length);
const float short_extrusion = count_e(layer_height, extrusion_width, short_length);
static const char cmd_meander_0[] PROGMEM = "G1 X50 Y155";
static const char cmd_meander_1[] PROGMEM = "G1 Z0.150 F7200.000";
static const char cmd_meander_2[] PROGMEM = "G1 F1080";
static const char cmd_meander_3[] PROGMEM = "G1 X75 Y155 E2.5";
static const char cmd_meander_4[] PROGMEM = "G1 X100 Y155 E2";
static const char cmd_meander_5[] PROGMEM = "G1 X200 Y155 E2.62773";
static const char cmd_meander_6[] PROGMEM = "G1 X200 Y135 E0.66174";
static const char cmd_meander_7[] PROGMEM = "G1 X50 Y135 E3.62773";
static const char cmd_meander_8[] PROGMEM = "G1 X50 Y115 E0.49386";
static const char cmd_meander_9[] PROGMEM = "G1 X200 Y115 E3.62773";
static const char cmd_meander_10[] PROGMEM = "G1 X200 Y95 E0.49386";
static const char cmd_meander_11[] PROGMEM = "G1 X50 Y95 E3.62773";
static const char cmd_meander_12[] PROGMEM = "G1 X50 Y75 E0.49386";
static const char cmd_meander_13[] PROGMEM = "G1 X200 Y75 E3.62773";
static const char cmd_meander_14[] PROGMEM = "G1 X200 Y55 E0.49386";
static const char cmd_meander_15[] PROGMEM = "G1 X50 Y55 E3.62773";
for(int8_t i = 0, xdir = -invert; i <= 4; i++, xdir = -xdir)
static const char * const cmd_meander[] PROGMEM =
{
enquecommandf_P(extrude_fmt_X, xdir * long_length, long_extrusion);
enquecommandf_P(extrude_fmt_Y, invert * -short_length, short_extrusion);
}
#ifdef NEW_FIRST_LAYER_CAL
constexpr float mid_length = 0.5f * long_length - 0.5f * square_width;
const float mid_extrusion = count_e(layer_height, extrusion_width, mid_length);
enquecommandf_P(extrude_fmt_X, -mid_length, mid_extrusion); //~Middle of bed X125
enquecommandf_P(extrude_fmt_Y, short_length, short_extrusion); //~Middle of bed Y105
#endif //NEW_FIRST_LAYER_CAL
cmd_meander_0,
cmd_meander_1,
cmd_meander_2,
cmd_meander_3,
cmd_meander_4,
cmd_meander_5,
cmd_meander_6,
cmd_meander_7,
cmd_meander_8,
cmd_meander_9,
cmd_meander_10,
cmd_meander_11,
cmd_meander_12,
cmd_meander_13,
cmd_meander_14,
cmd_meander_15,
};
for (uint8_t i = 0; i < (sizeof(cmd_meander)/sizeof(cmd_meander[0])); ++i)
{
enquecommand_P(static_cast<char*>(pgm_read_ptr(&cmd_meander[i])));
}
sprintf_P(cmd_buffer, PSTR("G1 X50 Y35 E%-.3f"), extr);
enquecommand(cmd_buffer);
}
//! @brief Print square
//!
//! This function enqueues 4 lines of the square, so it needs to be called multiple times
//! This function needs to be called 16 times for i from 0 to 15.
//!
//! @param cmd_buffer character buffer needed to format gcodes
void lay1cal_square(float layer_height, float extrusion_width)
//! @param i iteration
void lay1cal_square(char *cmd_buffer, uint8_t i)
{
const float Y_spacing = spacing(layer_height, extrusion_width);
const float long_extrusion = count_e(layer_height, extrusion_width, square_width);
const float short_extrusion = count_e(layer_height, extrusion_width, Y_spacing);
const float extr_short_segment = count_e(height, width, width);
for (uint8_t i = 0; i < 4; i++)
{
enquecommandf_P(extrude_fmt_X, square_width*invert, long_extrusion);
enquecommandf_P(extrude_fmt_Y, -Y_spacing*invert, short_extrusion);
enquecommandf_P(extrude_fmt_X, -square_width*invert, long_extrusion);
enquecommandf_P(extrude_fmt_Y, -Y_spacing*invert, short_extrusion);
}
}
void lay1cal_finish()
{
static const char cmd_cal_finish_3[] PROGMEM = "G1E-0.075F2100"; // Retract
static const char cmd_cal_finish_4[] PROGMEM = "M140S0"; // Turn off bed heater
static const char cmd_cal_finish_5[] PROGMEM = "G1Z10F1300"; // Lift Z
static const char cmd_cal_finish_6[] PROGMEM = "G1X10Y180F4000"; // Go to parking position
static const char cmd_cal_finish_8[] PROGMEM = "M104S0"; // Turn off hotend heater
static const char * const cmd_cal_finish[] PROGMEM =
{
MSG_G90, // Set to Absolute Positioning
MSG_M107, // Turn off printer fan
cmd_cal_finish_3, // Retract
cmd_cal_finish_4, // Turn off bed heater
cmd_cal_finish_5, // Lift Z
cmd_cal_finish_6, // Go to parking position
MSG_M702, // Unload filament (MMU only)
cmd_cal_finish_8, // Turn off hotend heater
MSG_M84 // Disable stepper motors
};
lay1cal_common_enqueue_loop(cmd_cal_finish, (sizeof(cmd_cal_finish)/sizeof(cmd_cal_finish[0])));
static const char fmt1[] PROGMEM = "G1 X%d Y%-.2f E%-.3f";
static const char fmt2[] PROGMEM = "G1 Y%-.2f E%-.3f";
sprintf_P(cmd_buffer, fmt1, 70, (35 - i*width * 2), extr);
enquecommand(cmd_buffer);
sprintf_P(cmd_buffer, fmt2, (35 - (2 * i + 1)*width), extr_short_segment);
enquecommand(cmd_buffer);
sprintf_P(cmd_buffer, fmt1, 50, (35 - (2 * i + 1)*width), extr);
enquecommand(cmd_buffer);
sprintf_P(cmd_buffer, fmt2, (35 - (i + 1)*width * 2), extr_short_segment);
enquecommand(cmd_buffer);
}

View File

@ -7,12 +7,10 @@
#include <stdint.h>
void lay1cal_wait_preheat();
[[nodiscard]] bool lay1cal_load_filament(uint8_t filament);
void lay1cal_intro_line(bool skipExtraPurge, float layer_height, float extrusion_width);
void lay1cal_load_filament(char *cmd_buffer, uint8_t filament);
void lay1cal_intro_line();
void lay1cal_before_meander();
void lay1cal_meander_start(float layer_height, float extrusion_width);
void lay1cal_meander(float layer_height, float extrusion_width);
void lay1cal_square(float layer_height, float extrusion_width);
void lay1cal_finish();
void lay1cal_meander(char *cmd_buffer);
void lay1cal_square(char *cmd_buffer, uint8_t i);
#endif /* FIRMWARE_FIRST_LAY_CAL_H_ */

789
Firmware/fsensor.cpp Executable file
View File

@ -0,0 +1,789 @@
//! @file
#include "Marlin.h"
#include "fsensor.h"
#include <avr/pgmspace.h>
#include "pat9125.h"
#include "stepper.h"
#include "cmdqueue.h"
#include "ultralcd.h"
#include "mmu.h"
#include "cardreader.h"
#include "adc.h"
#include "temperature.h"
#include "config.h"
//! @name Basic parameters
//! @{
#define FSENSOR_CHUNK_LEN 1.25 //!< filament sensor chunk length (mm)
#define FSENSOR_ERR_MAX 4 //!< filament sensor maximum error/chunk count for runout detection
#define FSENSOR_SOFTERR_CMAX 3 //!< number of contiguous soft failures before a triggering a runout
#define FSENSOR_SOFTERR_DELTA 30000 //!< maximum interval (ms) to consider soft failures contiguous
//! @}
//! @name Optical quality measurement parameters
//! @{
#define FSENSOR_OQ_MAX_ES 2 //!< maximum sum of error blocks during filament recheck
#define FSENSOR_OQ_MIN_YD 2 //!< minimum yd sum during filament check (counts per inch)
#define FSENSOR_OQ_MIN_BR 80 //!< minimum brightness value
#define FSENSOR_OQ_MAX_SH 10 //!< maximum shutter value
//! @}
const char ERRMSG_PAT9125_NOT_RESP[] PROGMEM = "PAT9125 not responding (%d)!\n";
// PJ7 can not be used (does not have PinChangeInterrupt possibility)
#define FSENSOR_INT_PIN 75 //!< filament sensor interrupt pin PJ4
#define FSENSOR_INT_PIN_MASK 0x10 //!< filament sensor interrupt pin mask (bit4)
#define FSENSOR_INT_PIN_PIN_REG PINJ // PIN register @ PJ4
#define FSENSOR_INT_PIN_VECT PCINT1_vect // PinChange ISR @ PJ4
#define FSENSOR_INT_PIN_PCMSK_REG PCMSK1 // PinChangeMaskRegister @ PJ4
#define FSENSOR_INT_PIN_PCMSK_BIT PCINT13 // PinChange Interrupt / PinChange Enable Mask @ PJ4
#define FSENSOR_INT_PIN_PCICR_BIT PCIE1 // PinChange Interrupt Enable / Flag @ PJ4
//! enabled = initialized and sampled every chunk event
bool fsensor_enabled = true;
//! runout watching is done in fsensor_update (called from main loop)
bool fsensor_watch_runout = true;
//! not responding - is set if any communication error occurred during initialization or readout
bool fsensor_not_responding = false;
#ifdef PAT9125
uint8_t fsensor_int_pin_old = 0;
//! optical checking "chunk lenght" (already in steps)
int16_t fsensor_chunk_len = 0;
//! enable/disable quality meassurement
bool fsensor_oq_meassure_enabled = false;
//! number of errors, updated in ISR
uint8_t fsensor_err_cnt = 0;
//! variable for accumulating step count (updated callbacks from stepper and ISR)
int16_t fsensor_st_cnt = 0;
//! count of total sensor "soft" failures (filament status checks)
uint8_t fsensor_softfail = 0;
//! timestamp of last soft failure
unsigned long fsensor_softfail_last = 0;
//! count of soft failures within the configured time
uint8_t fsensor_softfail_ccnt = 0;
#endif
#ifdef DEBUG_FSENSOR_LOG
//! log flag: 0=log disabled, 1=log enabled
uint8_t fsensor_log = 1;
#endif //DEBUG_FSENSOR_LOG
//! @name filament autoload variables
//! @{
//! autoload feature enabled
bool fsensor_autoload_enabled = true;
//! autoload watching enable/disable flag
bool fsensor_watch_autoload = false;
#ifdef PAT9125
//
uint16_t fsensor_autoload_y;
//
uint8_t fsensor_autoload_c;
//
uint32_t fsensor_autoload_last_millis;
//
uint8_t fsensor_autoload_sum;
//! @}
#endif
//! @name filament optical quality measurement variables
//! @{
//! Measurement enable/disable flag
bool fsensor_oq_meassure = false;
//! skip-chunk counter, for accurate measurement is necessary to skip first chunk...
uint8_t fsensor_oq_skipchunk;
//! number of samples from start of measurement
uint8_t fsensor_oq_samples;
//! sum of steps in positive direction movements
uint16_t fsensor_oq_st_sum;
//! sum of deltas in positive direction movements
uint16_t fsensor_oq_yd_sum;
//! sum of errors during measurement
uint16_t fsensor_oq_er_sum;
//! max error counter value during measurement
uint8_t fsensor_oq_er_max;
//! minimum delta value
int16_t fsensor_oq_yd_min;
//! maximum delta value
int16_t fsensor_oq_yd_max;
//! sum of shutter value
uint16_t fsensor_oq_sh_sum;
//! @}
#ifdef IR_SENSOR_ANALOG
ClFsensorPCB oFsensorPCB;
ClFsensorActionNA oFsensorActionNA;
bool bIRsensorStateFlag=false;
unsigned long nIRsensorLastTime;
#endif //IR_SENSOR_ANALOG
void fsensor_stop_and_save_print(void)
{
puts_P(PSTR("fsensor_stop_and_save_print"));
stop_and_save_print_to_ram(0, 0);
fsensor_watch_runout = false;
}
#ifdef PAT9125
// Reset all internal counters to zero, including stepper callbacks
void fsensor_reset_err_cnt()
{
fsensor_err_cnt = 0;
pat9125_y = 0;
st_reset_fsensor();
}
void fsensor_set_axis_steps_per_unit(float u)
{
fsensor_chunk_len = (int16_t)(FSENSOR_CHUNK_LEN * u);
}
#endif
void fsensor_restore_print_and_continue(void)
{
puts_P(PSTR("fsensor_restore_print_and_continue"));
fsensor_watch_runout = true;
#ifdef PAT9125
fsensor_reset_err_cnt();
#endif
restore_print_from_ram_and_continue(0);
}
// fsensor_checkpoint_print cuts the current print job at the current position,
// allowing new instructions to be inserted in the middle
void fsensor_checkpoint_print(void)
{
puts_P(PSTR("fsensor_checkpoint_print"));
stop_and_save_print_to_ram(0, 0);
restore_print_from_ram_and_continue(0);
}
#ifdef IR_SENSOR_ANALOG
const char* FsensorIRVersionText()
{
switch(oFsensorPCB)
{
case ClFsensorPCB::_Old:
return _T(MSG_IR_03_OR_OLDER);
case ClFsensorPCB::_Rev04:
return _T(MSG_IR_04_OR_NEWER);
default:
return _T(MSG_IR_UNKNOWN);
}
}
#endif //IR_SENSOR_ANALOG
void fsensor_init(void)
{
#ifdef PAT9125
uint8_t pat9125 = pat9125_init();
printf_P(PSTR("PAT9125_init:%hhu\n"), pat9125);
#endif //PAT9125
uint8_t fsensor_enabled = eeprom_read_byte((uint8_t*)EEPROM_FSENSOR);
fsensor_autoload_enabled=eeprom_read_byte((uint8_t*)EEPROM_FSENS_AUTOLOAD_ENABLED);
fsensor_not_responding = false;
#ifdef PAT9125
uint8_t oq_meassure_enabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_OQ_MEASS_ENABLED);
fsensor_oq_meassure_enabled = (oq_meassure_enabled == 1)?true:false;
fsensor_set_axis_steps_per_unit(cs.axis_steps_per_unit[E_AXIS]);
if (!pat9125){
fsensor_enabled = 0; //disable sensor
fsensor_not_responding = true;
}
#endif //PAT9125
#ifdef IR_SENSOR_ANALOG
bIRsensorStateFlag=false;
oFsensorPCB = (ClFsensorPCB)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_PCB);
oFsensorActionNA = (ClFsensorActionNA)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA);
// If the fsensor is not responding even at the start of the printer,
// set this flag accordingly to show N/A in Settings->Filament sensor.
// This is even valid for both fsensor board revisions (0.3 or older and 0.4).
// Must be done after reading what type of fsensor board we have
fsensor_not_responding = ! fsensor_IR_check();
#endif //IR_SENSOR_ANALOG
if (fsensor_enabled){
fsensor_enable(false); // (in this case) EEPROM update is not necessary
} else {
fsensor_disable(false); // (in this case) EEPROM update is not necessary
}
printf_P(PSTR("FSensor %S"), (fsensor_enabled?PSTR("ENABLED"):PSTR("DISABLED")));
#ifdef IR_SENSOR_ANALOG
printf_P(PSTR(" (sensor board revision:%S)\n"), FsensorIRVersionText());
#else //IR_SENSOR_ANALOG
MYSERIAL.println();
#endif //IR_SENSOR_ANALOG
if (check_for_ir_sensor()){
ir_sensor_detected = true;
}
}
bool fsensor_enable(bool bUpdateEEPROM)
{
#ifdef PAT9125
(void)bUpdateEEPROM; // silence unused warning in this variant
if (mmu_enabled == false) { //filament sensor is pat9125, enable only if it is working
uint8_t pat9125 = pat9125_init();
printf_P(PSTR("PAT9125_init:%hhu\n"), pat9125);
if (pat9125)
fsensor_not_responding = false;
else
fsensor_not_responding = true;
fsensor_enabled = pat9125 ? true : false;
fsensor_watch_runout = true;
fsensor_oq_meassure = false;
fsensor_reset_err_cnt();
eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, fsensor_enabled ? 0x01 : 0x00);
FSensorStateMenu = fsensor_enabled ? 1 : 0;
}
else //filament sensor is FINDA, always enable
{
fsensor_enabled = true;
eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, 0x01);
FSensorStateMenu = 1;
}
#else // PAT9125
#ifdef IR_SENSOR_ANALOG
if(!fsensor_IR_check())
{
bUpdateEEPROM=true;
fsensor_enabled=false;
fsensor_not_responding=true;
FSensorStateMenu=0;
}
else {
#endif //IR_SENSOR_ANALOG
fsensor_enabled=true;
fsensor_not_responding=false;
FSensorStateMenu=1;
#ifdef IR_SENSOR_ANALOG
}
#endif //IR_SENSOR_ANALOG
if(bUpdateEEPROM)
eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, FSensorStateMenu);
#endif //PAT9125
return fsensor_enabled;
}
void fsensor_disable(bool bUpdateEEPROM)
{
fsensor_enabled = false;
FSensorStateMenu = 0;
if(bUpdateEEPROM)
eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, 0x00);
}
void fsensor_autoload_set(bool State)
{
#ifdef PAT9125
if (!State) fsensor_autoload_check_stop();
#endif //PAT9125
fsensor_autoload_enabled = State;
eeprom_update_byte((unsigned char *)EEPROM_FSENS_AUTOLOAD_ENABLED, fsensor_autoload_enabled);
}
void pciSetup(byte pin)
{
// !!! "digitalPinTo?????bit()" does not provide the correct results for some MCU pins
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
#ifdef PAT9125
void fsensor_autoload_check_start(void)
{
// puts_P(_N("fsensor_autoload_check_start\n"));
if (!fsensor_enabled) return;
if (!fsensor_autoload_enabled) return;
if (fsensor_watch_autoload) return;
if (!pat9125_update()) //update sensor
{
fsensor_disable();
fsensor_not_responding = true;
fsensor_watch_autoload = false;
printf_P(ERRMSG_PAT9125_NOT_RESP, 3);
return;
}
puts_P(_N("fsensor_autoload_check_start - autoload ENABLED"));
fsensor_autoload_y = pat9125_y; //save current y value
fsensor_autoload_c = 0; //reset number of changes counter
fsensor_autoload_sum = 0;
fsensor_autoload_last_millis = _millis();
fsensor_watch_runout = false;
fsensor_watch_autoload = true;
}
void fsensor_autoload_check_stop(void)
{
// puts_P(_N("fsensor_autoload_check_stop\n"));
if (!fsensor_enabled) return;
// puts_P(_N("fsensor_autoload_check_stop 1\n"));
if (!fsensor_autoload_enabled) return;
// puts_P(_N("fsensor_autoload_check_stop 2\n"));
if (!fsensor_watch_autoload) return;
puts_P(_N("fsensor_autoload_check_stop - autoload DISABLED"));
fsensor_autoload_sum = 0;
fsensor_watch_autoload = false;
fsensor_watch_runout = true;
fsensor_reset_err_cnt();
}
#endif //PAT9125
bool fsensor_check_autoload(void)
{
if (!fsensor_enabled) return false;
if (!fsensor_autoload_enabled) return false;
if (ir_sensor_detected) {
if (digitalRead(IR_SENSOR_PIN) == 1) {
fsensor_watch_autoload = true;
}
else if (fsensor_watch_autoload == true) {
fsensor_watch_autoload = false;
return true;
}
}
#ifdef PAT9125
if (!fsensor_watch_autoload)
{
fsensor_autoload_check_start();
return false;
}
#if 0
uint8_t fsensor_autoload_c_old = fsensor_autoload_c;
#endif
if ((_millis() - fsensor_autoload_last_millis) < 25) return false;
fsensor_autoload_last_millis = _millis();
if (!pat9125_update_y()) //update sensor
{
fsensor_disable();
fsensor_not_responding = true;
printf_P(ERRMSG_PAT9125_NOT_RESP, 2);
return false;
}
int16_t dy = pat9125_y - fsensor_autoload_y;
if (dy) //? dy value is nonzero
{
if (dy > 0) //? delta-y value is positive (inserting)
{
fsensor_autoload_sum += dy;
fsensor_autoload_c += 3; //increment change counter by 3
}
else if (fsensor_autoload_c > 1)
fsensor_autoload_c -= 2; //decrement change counter by 2
fsensor_autoload_y = pat9125_y; //save current value
}
else if (fsensor_autoload_c > 0)
fsensor_autoload_c--;
if (fsensor_autoload_c == 0) fsensor_autoload_sum = 0;
#if 0
puts_P(_N("fsensor_check_autoload\n"));
if (fsensor_autoload_c != fsensor_autoload_c_old)
printf_P(PSTR("fsensor_check_autoload dy=%d c=%d sum=%d\n"), dy, fsensor_autoload_c, fsensor_autoload_sum);
#endif
// if ((fsensor_autoload_c >= 15) && (fsensor_autoload_sum > 30))
if ((fsensor_autoload_c >= 12) && (fsensor_autoload_sum > 20))
{
// puts_P(_N("fsensor_check_autoload = true !!!\n"));
return true;
}
#endif //PAT9125
return false;
}
#ifdef PAT9125
void fsensor_oq_meassure_set(bool State)
{
fsensor_oq_meassure_enabled = State;
eeprom_update_byte((unsigned char *)EEPROM_FSENS_OQ_MEASS_ENABLED, fsensor_oq_meassure_enabled);
}
void fsensor_oq_meassure_start(uint8_t skip)
{
if (!fsensor_enabled) return;
if (!fsensor_oq_meassure_enabled) return;
puts_P(PSTR("fsensor_oq_meassure_start"));
fsensor_oq_skipchunk = skip;
fsensor_oq_samples = 0;
fsensor_oq_st_sum = 0;
fsensor_oq_yd_sum = 0;
fsensor_oq_er_sum = 0;
fsensor_oq_er_max = 0;
fsensor_oq_yd_min = INT16_MAX;
fsensor_oq_yd_max = 0;
fsensor_oq_sh_sum = 0;
pat9125_update();
pat9125_y = 0;
fsensor_oq_meassure = true;
}
void fsensor_oq_meassure_stop(void)
{
if (!fsensor_enabled) return;
if (!fsensor_oq_meassure_enabled) return;
printf_P(PSTR("fsensor_oq_meassure_stop, %hhu samples\n"), fsensor_oq_samples);
printf_P(_N(" st_sum=%u yd_sum=%u er_sum=%u er_max=%hhu\n"), fsensor_oq_st_sum, fsensor_oq_yd_sum, fsensor_oq_er_sum, fsensor_oq_er_max);
printf_P(_N(" yd_min=%u yd_max=%u yd_avg=%u sh_avg=%u\n"), fsensor_oq_yd_min, fsensor_oq_yd_max, (uint16_t)((uint32_t)fsensor_oq_yd_sum * fsensor_chunk_len / fsensor_oq_st_sum), (uint16_t)(fsensor_oq_sh_sum / fsensor_oq_samples));
fsensor_oq_meassure = false;
}
#ifdef FSENSOR_QUALITY
const char _OK[] PROGMEM = "OK";
const char _NG[] PROGMEM = "NG!";
bool fsensor_oq_result(void)
{
if (!fsensor_enabled) return true;
if (!fsensor_oq_meassure_enabled) return true;
puts_P(_N("fsensor_oq_result"));
bool res_er_sum = (fsensor_oq_er_sum <= FSENSOR_OQ_MAX_ES);
printf_P(_N(" er_sum = %u %S\n"), fsensor_oq_er_sum, (res_er_sum?_OK:_NG));
bool res_er_max = (fsensor_oq_er_max <= FSENSOR_OQ_MAX_EM);
printf_P(_N(" er_max = %hhu %S\n"), fsensor_oq_er_max, (res_er_max?_OK:_NG));
uint8_t yd_avg = ((uint32_t)fsensor_oq_yd_sum * fsensor_chunk_len / fsensor_oq_st_sum);
bool res_yd_avg = (yd_avg >= FSENSOR_OQ_MIN_YD) && (yd_avg <= FSENSOR_OQ_MAX_YD);
printf_P(_N(" yd_avg = %hhu %S\n"), yd_avg, (res_yd_avg?_OK:_NG));
bool res_yd_max = (fsensor_oq_yd_max <= (yd_avg * FSENSOR_OQ_MAX_PD));
printf_P(_N(" yd_max = %u %S\n"), fsensor_oq_yd_max, (res_yd_max?_OK:_NG));
bool res_yd_min = (fsensor_oq_yd_min >= (yd_avg / FSENSOR_OQ_MAX_ND));
printf_P(_N(" yd_min = %u %S\n"), fsensor_oq_yd_min, (res_yd_min?_OK:_NG));
uint16_t yd_dev = (fsensor_oq_yd_max - yd_avg) + (yd_avg - fsensor_oq_yd_min);
printf_P(_N(" yd_dev = %u\n"), yd_dev);
uint16_t yd_qua = 10 * yd_avg / (yd_dev + 1);
printf_P(_N(" yd_qua = %u %S\n"), yd_qua, ((yd_qua >= 8)?_OK:_NG));
uint8_t sh_avg = (fsensor_oq_sh_sum / fsensor_oq_samples);
bool res_sh_avg = (sh_avg <= FSENSOR_OQ_MAX_SH);
if (yd_qua >= 8) res_sh_avg = true;
printf_P(_N(" sh_avg = %hhu %S\n"), sh_avg, (res_sh_avg?_OK:_NG));
bool res = res_er_sum && res_er_max && res_yd_avg && res_yd_max && res_yd_min && res_sh_avg;
printf_P(_N("fsensor_oq_result %S\n"), (res?_OK:_NG));
return res;
}
#endif //FSENSOR_QUALITY
FORCE_INLINE static void fsensor_isr(int st_cnt)
{
uint8_t old_err_cnt = fsensor_err_cnt;
uint8_t pat9125_res = fsensor_oq_meassure?pat9125_update():pat9125_update_y();
if (!pat9125_res)
{
fsensor_disable();
fsensor_not_responding = true;
printf_P(ERRMSG_PAT9125_NOT_RESP, 1);
}
if (st_cnt != 0)
{
// movement was planned, check for sensor movement
int8_t st_dir = st_cnt >= 0;
int8_t pat9125_dir = pat9125_y >= 0;
if (pat9125_y == 0)
{
if (st_dir)
{
// no movement detected: we might be within a blind sensor range,
// update the frame and shutter parameters we didn't earlier
if (!fsensor_oq_meassure)
pat9125_update_bs();
// increment the error count only if underexposed: filament likely missing
if ((pat9125_b < FSENSOR_OQ_MIN_BR) && (pat9125_s > FSENSOR_OQ_MAX_SH))
{
// check for a dark frame (<30% avg brightness) with long exposure
++fsensor_err_cnt;
}
else
{
// good frame, filament likely present
if(fsensor_err_cnt) --fsensor_err_cnt;
}
}
}
else if (pat9125_dir != st_dir)
{
// detected direction opposite of motor movement
if (st_dir) ++fsensor_err_cnt;
}
else if (pat9125_dir == st_dir)
{
// direction agreeing with planned movement
if (fsensor_err_cnt) --fsensor_err_cnt;
}
if (st_dir && fsensor_oq_meassure)
{
// extruding with quality assessment
if (fsensor_oq_skipchunk)
{
fsensor_oq_skipchunk--;
fsensor_err_cnt = 0;
}
else
{
if (st_cnt == fsensor_chunk_len)
{
if (pat9125_y > 0) if (fsensor_oq_yd_min > pat9125_y) fsensor_oq_yd_min = (fsensor_oq_yd_min + pat9125_y) / 2;
if (pat9125_y >= 0) if (fsensor_oq_yd_max < pat9125_y) fsensor_oq_yd_max = (fsensor_oq_yd_max + pat9125_y) / 2;
}
fsensor_oq_samples++;
fsensor_oq_st_sum += st_cnt;
if (pat9125_y > 0) fsensor_oq_yd_sum += pat9125_y;
if (fsensor_err_cnt > old_err_cnt)
fsensor_oq_er_sum += (fsensor_err_cnt - old_err_cnt);
if (fsensor_oq_er_max < fsensor_err_cnt)
fsensor_oq_er_max = fsensor_err_cnt;
fsensor_oq_sh_sum += pat9125_s;
}
}
}
#ifdef DEBUG_FSENSOR_LOG
if (fsensor_log)
{
printf_P(_N("FSENSOR cnt=%d dy=%d err=%hhu %S\n"), st_cnt, pat9125_y, fsensor_err_cnt, (fsensor_err_cnt > old_err_cnt)?_N("NG!"):_N("OK"));
if (fsensor_oq_meassure) printf_P(_N("FSENSOR st_sum=%u yd_sum=%u er_sum=%u er_max=%hhu yd_max=%u\n"), fsensor_oq_st_sum, fsensor_oq_yd_sum, fsensor_oq_er_sum, fsensor_oq_er_max, fsensor_oq_yd_max);
}
#endif //DEBUG_FSENSOR_LOG
pat9125_y = 0;
}
ISR(FSENSOR_INT_PIN_VECT)
{
if (mmu_enabled || ir_sensor_detected) return;
if (!((fsensor_int_pin_old ^ FSENSOR_INT_PIN_PIN_REG) & FSENSOR_INT_PIN_MASK)) return;
fsensor_int_pin_old = FSENSOR_INT_PIN_PIN_REG;
// prevent isr re-entry
static bool _lock = false;
if (!_lock)
{
// fetch fsensor_st_cnt atomically
int st_cnt = fsensor_st_cnt;
fsensor_st_cnt = 0;
_lock = true;
sei();
fsensor_isr(st_cnt);
cli();
_lock = false;
}
}
void fsensor_setup_interrupt(void)
{
pinMode(FSENSOR_INT_PIN, OUTPUT);
digitalWrite(FSENSOR_INT_PIN, LOW);
fsensor_int_pin_old = 0;
//pciSetup(FSENSOR_INT_PIN);
// !!! "pciSetup()" does not provide the correct results for some MCU pins
// so interrupt registers settings:
FSENSOR_INT_PIN_PCMSK_REG |= bit(FSENSOR_INT_PIN_PCMSK_BIT); // enable corresponding PinChangeInterrupt (individual pin)
PCIFR |= bit(FSENSOR_INT_PIN_PCICR_BIT); // clear previous occasional interrupt (set of pins)
PCICR |= bit(FSENSOR_INT_PIN_PCICR_BIT); // enable corresponding PinChangeInterrupt (set of pins)
}
void fsensor_st_block_chunk(int cnt)
{
if (!fsensor_enabled) return;
fsensor_st_cnt += cnt;
// !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins
WRITE(FSENSOR_INT_PIN, !READ(FSENSOR_INT_PIN));
}
#endif //PAT9125
//! Common code for enqueing M600 and supplemental codes into the command queue.
//! Used both for the IR sensor and the PAT9125
void fsensor_enque_M600(){
puts_P(PSTR("fsensor_update - M600"));
eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
enquecommand_front_P((PSTR("M600")));
}
//! @brief filament sensor update (perform M600 on filament runout)
//!
//! Works only if filament sensor is enabled.
//! When the filament sensor error count is larger then FSENSOR_ERR_MAX, pauses print, tries to move filament back and forth.
//! If there is still no plausible signal from filament sensor plans M600 (Filament change).
void fsensor_update(void)
{
#ifdef PAT9125
if (fsensor_watch_runout && (fsensor_err_cnt > FSENSOR_ERR_MAX))
{
fsensor_stop_and_save_print();
KEEPALIVE_STATE(IN_HANDLER);
bool autoload_enabled_tmp = fsensor_autoload_enabled;
fsensor_autoload_enabled = false;
bool oq_meassure_enabled_tmp = fsensor_oq_meassure_enabled;
fsensor_oq_meassure_enabled = true;
// move the nozzle away while checking the filament
current_position[Z_AXIS] += 0.8;
if(current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
plan_buffer_line_curposXYZE(max_feedrate[Z_AXIS]);
st_synchronize();
// check the filament in isolation
fsensor_reset_err_cnt();
fsensor_oq_meassure_start(0);
float e_tmp = current_position[E_AXIS];
current_position[E_AXIS] -= 3;
plan_buffer_line_curposXYZE(250/60);
current_position[E_AXIS] = e_tmp;
plan_buffer_line_curposXYZE(200/60);
st_synchronize();
fsensor_oq_meassure_stop();
bool err = false;
err |= (fsensor_err_cnt > 0); // final error count is non-zero
err |= (fsensor_oq_er_sum > FSENSOR_OQ_MAX_ES); // total error count is above limit
err |= (fsensor_oq_yd_sum < FSENSOR_OQ_MIN_YD); // total measured distance is below limit
fsensor_restore_print_and_continue();
fsensor_autoload_enabled = autoload_enabled_tmp;
fsensor_oq_meassure_enabled = oq_meassure_enabled_tmp;
unsigned long now = _millis();
if (!err && (now - fsensor_softfail_last) > FSENSOR_SOFTERR_DELTA)
fsensor_softfail_ccnt = 0;
if (!err && fsensor_softfail_ccnt <= FSENSOR_SOFTERR_CMAX)
{
puts_P(PSTR("fsensor_err_cnt = 0"));
++fsensor_softfail;
++fsensor_softfail_ccnt;
fsensor_softfail_last = now;
}
else
{
fsensor_softfail_ccnt = 0;
fsensor_softfail_last = 0;
fsensor_enque_M600();
}
}
#else //PAT9125
if (CHECK_FSENSOR && ir_sensor_detected)
{
if(digitalRead(IR_SENSOR_PIN))
{ // IR_SENSOR_PIN ~ H
#ifdef IR_SENSOR_ANALOG
if(!bIRsensorStateFlag)
{
bIRsensorStateFlag=true;
nIRsensorLastTime=_millis();
}
else
{
if((_millis()-nIRsensorLastTime)>IR_SENSOR_STEADY)
{
uint8_t nMUX1,nMUX2;
uint16_t nADC;
bIRsensorStateFlag=false;
// sequence for direct data reading from AD converter
DISABLE_TEMPERATURE_INTERRUPT();
nMUX1=ADMUX; // ADMUX saving
nMUX2=ADCSRB;
adc_setmux(VOLT_IR_PIN);
ADCSRA|=(1<<ADSC); // first conversion after ADMUX change discarded (preventively)
while(ADCSRA&(1<<ADSC))
;
ADCSRA|=(1<<ADSC); // second conversion used
while(ADCSRA&(1<<ADSC))
;
nADC=ADC;
ADMUX=nMUX1; // ADMUX restoring
ADCSRB=nMUX2;
ENABLE_TEMPERATURE_INTERRUPT();
// end of sequence for ...
// Detection of correct function of fsensor v04 - it must NOT read >4.6V
// If it does, it means a disconnected cables or faulty board
if( (oFsensorPCB == ClFsensorPCB::_Rev04) && ( (nADC*OVERSAMPLENR) > IRsensor_Hopen_TRESHOLD ) )
{
fsensor_disable();
fsensor_not_responding = true;
printf_P(PSTR("IR sensor not responding (%d)!\n"),1);
if((ClFsensorActionNA)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA)==ClFsensorActionNA::_Pause)
// if we are printing and FS action is set to "Pause", force pause the print
if(oFsensorActionNA==ClFsensorActionNA::_Pause)
lcd_pause_print();
}
else
{
#endif //IR_SENSOR_ANALOG
fsensor_checkpoint_print();
fsensor_enque_M600();
#ifdef IR_SENSOR_ANALOG
}
}
}
}
else
{ // IR_SENSOR_PIN ~ L
bIRsensorStateFlag=false;
#endif //IR_SENSOR_ANALOG
}
}
#endif //PAT9125
}
#ifdef IR_SENSOR_ANALOG
/// This is called only upon start of the printer or when switching the fsensor ON in the menu
/// We cannot do temporal window checks here (aka the voltage has been in some range for a period of time)
bool fsensor_IR_check(){
if( IRsensor_Lmax_TRESHOLD <= current_voltage_raw_IR && current_voltage_raw_IR <= IRsensor_Hmin_TRESHOLD ){
/// If the voltage is in forbidden range, the fsensor is ok, but the lever is mounted improperly.
/// Or the user is so creative so that he can hold a piece of fillament in the hole in such a genius way,
/// that the IR fsensor reading is within 1.5 and 3V ... this would have been highly unusual
/// and would have been considered more like a sabotage than normal printer operation
puts_P(PSTR("fsensor in forbidden range 1.5-3V - check sensor"));
return false;
}
if( oFsensorPCB == ClFsensorPCB::_Rev04 ){
/// newer IR sensor cannot normally produce 4.6-5V, this is considered a failure/bad mount
if( IRsensor_Hopen_TRESHOLD <= current_voltage_raw_IR && current_voltage_raw_IR <= IRsensor_VMax_TRESHOLD ){
puts_P(PSTR("fsensor v0.4 in fault range 4.6-5V - unconnected"));
return false;
}
/// newer IR sensor cannot normally produce 0-0.3V, this is considered a failure
#if 0 //Disabled as it has to be decided if we gonna use this or not.
if( IRsensor_Hopen_TRESHOLD <= current_voltage_raw_IR && current_voltage_raw_IR <= IRsensor_VMax_TRESHOLD ){
puts_P(PSTR("fsensor v0.4 in fault range 0.0-0.3V - wrong IR sensor"));
return false;
}
#endif
}
/// If IR sensor is "uknown state" and filament is not loaded > 1.5V return false
#if 0
if( (oFsensorPCB == ClFsensorPCB::_Undef) && ( current_voltage_raw_IR > IRsensor_Lmax_TRESHOLD ) ){
puts_P(PSTR("Unknown IR sensor version and no filament loaded detected."));
return false;
}
#endif
// otherwise the IR fsensor is considered working correctly
return true;
}
#endif //IR_SENSOR_ANALOG

124
Firmware/fsensor.h Executable file
View File

@ -0,0 +1,124 @@
//! @file
#ifndef FSENSOR_H
#define FSENSOR_H
#include <inttypes.h>
#include "config.h"
// enable/disable flag
extern bool fsensor_enabled;
// not responding flag
extern bool fsensor_not_responding;
#ifdef PAT9125
// optical checking "chunk lenght" (already in steps)
extern int16_t fsensor_chunk_len;
// count of soft failures
extern uint8_t fsensor_softfail;
#endif
//! @name save restore printing
//! @{
extern void fsensor_stop_and_save_print(void);
//! restore print - restore position and heatup to original temperature
extern void fsensor_restore_print_and_continue(void);
//! split the current gcode stream to insert new instructions
extern void fsensor_checkpoint_print(void);
//! @}
//! initialize
extern void fsensor_init(void);
#ifdef PAT9125
//! update axis resolution
extern void fsensor_set_axis_steps_per_unit(float u);
#endif
//! @name enable/disable
//! @{
extern bool fsensor_enable(bool bUpdateEEPROM=true);
extern void fsensor_disable(bool bUpdateEEPROM=true);
//! @}
//autoload feature enabled
extern bool fsensor_autoload_enabled;
extern void fsensor_autoload_set(bool State);
extern void fsensor_update(void);
#ifdef PAT9125
//! setup pin-change interrupt
extern void fsensor_setup_interrupt(void);
//! @name autoload support
//! @{
extern void fsensor_autoload_check_start(void);
extern void fsensor_autoload_check_stop(void);
#endif //PAT9125
extern bool fsensor_check_autoload(void);
//! @}
#ifdef PAT9125
//! @name optical quality measurement support
//! @{
extern bool fsensor_oq_meassure_enabled;
extern void fsensor_oq_meassure_set(bool State);
extern void fsensor_oq_meassure_start(uint8_t skip);
extern void fsensor_oq_meassure_stop(void);
extern bool fsensor_oq_result(void);
//! @}
//! @name callbacks from stepper
//! @{
extern void fsensor_st_block_chunk(int cnt);
// debugging
extern uint8_t fsensor_log;
// There's really nothing to do in block_begin: the stepper ISR likely has
// called us already at the end of the last block, making this integration
// redundant. LA1.5 might not always do that during a coasting move, so attempt
// to drain fsensor_st_cnt anyway at the beginning of the new block.
#define fsensor_st_block_begin(rev) fsensor_st_block_chunk(0)
//! @}
#endif //PAT9125
#define VOLT_DIV_REF 5
#ifdef IR_SENSOR_ANALOG
#define IR_SENSOR_STEADY 10 // [ms]
enum class ClFsensorPCB:uint_least8_t
{
_Old=0,
_Rev04=1,
_Undef=EEPROM_EMPTY_VALUE
};
enum class ClFsensorActionNA:uint_least8_t
{
_Continue=0,
_Pause=1,
_Undef=EEPROM_EMPTY_VALUE
};
extern ClFsensorPCB oFsensorPCB;
extern ClFsensorActionNA oFsensorActionNA;
extern const char* FsensorIRVersionText();
extern bool fsensor_IR_check();
constexpr uint16_t Voltage2Raw(float V){
return ( V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F;
}
constexpr float Raw2Voltage(uint16_t raw){
return VOLT_DIV_REF*(raw / (1023.F * OVERSAMPLENR) );
}
constexpr uint16_t IRsensor_Ldiode_TRESHOLD = Voltage2Raw(0.3F); // ~0.3V, raw value=982
constexpr uint16_t IRsensor_Lmax_TRESHOLD = Voltage2Raw(1.5F); // ~1.5V (0.3*Vcc), raw value=4910
constexpr uint16_t IRsensor_Hmin_TRESHOLD = Voltage2Raw(3.0F); // ~3.0V (0.6*Vcc), raw value=9821
constexpr uint16_t IRsensor_Hopen_TRESHOLD = Voltage2Raw(4.6F); // ~4.6V (N.C. @ Ru~20-50k, Rd'=56k, Ru'=10k), raw value=15059
constexpr uint16_t IRsensor_VMax_TRESHOLD = Voltage2Raw(5.F); // ~5V, raw value=16368
#endif //IR_SENSOR_ANALOG
#endif //FSENSOR_H

View File

@ -11,7 +11,7 @@
// Doing this at higher frequency than the bed "loudspeaker" can handle makes the click barely audible.
// Technically:
// timer0 is set to fast PWM mode at 62.5kHz (timer0 is linked to the bed heating pin) (zero prescaler)
// To keep the bed switching at 30Hz - we don't want the PWM running at 62kHz all the time
// To keep the bed switching at 30Hz - we don't want the PWM running at 62kHz all the time
// since it would burn the heatbed's MOSFET:
// 16MHz/256 levels of PWM duty gives us 62.5kHz
// 62.5kHz/256 gives ~244Hz, that is still too fast - 244/8 gives ~30Hz, that's what we need
@ -19,9 +19,9 @@
// The finite automaton is running in the ISR(TIMER0_OVF_vect)
// 2019-08-14 update: the original algorithm worked very well, however there were 2 regressions:
// 1. 62kHz ISR requires considerable amount of processing power,
// 1. 62kHz ISR requires considerable amount of processing power,
// USB transfer speed dropped by 20%, which was most notable when doing short G-code segments.
// 2. Some users reported TLed PSU started clicking when running at 120V/60Hz.
// 2. Some users reported TLed PSU started clicking when running at 120V/60Hz.
// This looks like the original algorithm didn't maintain base PWM 30Hz, but only 15Hz
// To address both issues, there is an improved approach based on the idea of leveraging
// different CLK prescalers in some automaton states - i.e. when holding LOW or HIGH on the output pin,
@ -40,7 +40,7 @@
// - it can toggle unnoticed, which will result in bed clicking again.
// That's why there are special transition states ZERO_TO_RISE and ONE_TO_FALL, which enable the
// counter change its operation atomically and without artefacts on the output pin.
// The resulting signal on the output pin was checked with an osciloscope.
// The resulting signal on the output pin was checked with an osciloscope.
// If there are any change requirements in the future, the signal must be checked with an osciloscope again,
// ad-hoc changes may completely screw things up!
@ -57,7 +57,7 @@ enum class States : uint8_t {
ZERO_TO_RISE, ///< metastate allowing the timer change its state atomically without artefacts on the output pin
RISE, ///< 16 fast PWM cycles with increasing duty up to steady ON
RISE_TO_ONE, ///< metastate allowing the timer change its state atomically without artefacts on the output pin
ONE, ///< steady 1 (ON), no change for the whole period
ONE, ///< steady 1 (ON), no change for the whole period
FALL, ///< 16 fast PWM cycles with decreasing duty down to steady OFF
FALL_TO_ZERO ///< metastate allowing the timer change its state atomically without artefacts on the output pin
};
@ -92,7 +92,7 @@ static const uint8_t fastShift = 4;
/// increment slowCounter by 1
/// but use less bits of soft PWM - something like soft_pwm_bed >> 2
/// that may further reduce the CPU cycles required by the bed heating automaton
/// Due to the nature of bed heating the reduced PID precision may not be a major issue, however doing 8x less ISR(timer0_ovf) may significantly improve the performance
/// Due to the nature of bed heating the reduced PID precision may not be a major issue, however doing 8x less ISR(timer0_ovf) may significantly improve the performance
static const uint8_t slowInc = 1;
ISR(TIMER0_OVF_vect) // timer compare interrupt service routine
@ -177,6 +177,6 @@ ISR(TIMER0_OVF_vect) // timer compare interrupt service routine
TCNT0 = 128;
OCR0B = 255;
TCCR0B = (1 << CS01); // change prescaler to 8, i.e. 7.8kHz
break;
break;
}
}

View File

@ -1,32 +0,0 @@
#include <string.h>
#include "Configuration_adv.h"
#include "host.h"
#include "Timer.h"
static LongTimer M79_timer;
static char host_status_screen_name[3];
void SetHostStatusScreenName(const char * name) {
strncpy(host_status_screen_name, name, 2);
host_status_screen_name[2] = '\0';
}
char * GetHostStatusScreenName() {
return host_status_screen_name;
}
void ResetHostStatusScreenName() {
memset(host_status_screen_name, 0, sizeof(host_status_screen_name));
}
void M79_timer_restart() {
M79_timer.start();
}
bool M79_timer_get_status() {
return M79_timer.running();
}
void M79_timer_update_status() {
M79_timer.expired(M79_TIMEOUT);
}

View File

@ -1,22 +0,0 @@
#pragma once
/// Assigns host name with up to two characters which will be shown on
/// the UI when printing. The function forces the third byte to be null delimiter.
void SetHostStatusScreenName(const char * name);
/// Returns a pointer to the host name
char * GetHostStatusScreenName();
/// Reset the memory to NULL when the host name should not be used
void ResetHostStatusScreenName();
/// Restart the M79 timer
void M79_timer_restart();
/// Get the current M79 timer status
/// @returns true if running, false otherwise
bool M79_timer_get_status();
/// Checks if the timer period has expired. If the timer
/// has expired, the timer is stopped
void M79_timer_update_status();

View File

@ -74,7 +74,7 @@ float la10c_jerk(float j)
// check for a compatible range of values prior to convert (be sure that
// a higher E-jerk would still be compatible wrt the E accell range)
if(j < 4.5 && cs.max_acceleration_mm_per_s2_normal[E_AXIS] < 2000)
if(j < 4.5 && cs.max_acceleration_units_per_sq_second_normal[E_AXIS] < 2000)
return j;
// bring low E-jerk values into equivalent LA 1.5 values by

View File

@ -1,7 +1,6 @@
//language.c
#include "language.h"
#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/eeprom.h>
#include "bootapp.h"
@ -29,7 +28,7 @@ uint8_t lang_is_selected(void) { return 1; }
#else //(LANG_MODE == 0) //secondary languages in progmem or xflash
//reserved xx kbytes for secondary language table
const char _SEC_LANG[LANG_SIZE_RESERVED] __attribute__((aligned(SPM_PAGESIZE))) PROGMEM_I2 = "_SEC_LANG";
const char _SEC_LANG[LANG_SIZE_RESERVED] PROGMEM_I2 = "_SEC_LANG";
//primary language signature
const uint32_t _PRI_LANG_SIGNATURE[1] __attribute__((section(".progmem0"))) = {0xffffffff};
@ -42,7 +41,7 @@ const char* lang_get_translation(const char* s)
if (lang_selected == 0) return s + 2; //primary language selected, return orig. str.
if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str.
uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id
if (ui == 0xffff) return s + 2; //id not assigned, return orig. str.
if (ui == 0xffff) return s + 2; //translation not found, return orig. str.
ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset
if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character
return s + 2;//zero length string == not translated, return orig. str.
@ -212,46 +211,16 @@ const char* lang_get_name_by_code(uint16_t code)
case LANG_CODE_FR: return _n("Francais");
case LANG_CODE_IT: return _n("Italiano");
case LANG_CODE_PL: return _n("Polski");
#ifdef COMMUNITY_LANGUAGE_SUPPORT //Community language support
#ifdef COMMUNITY_LANG_GROUP1_NL
case LANG_CODE_NL: return _n("Nederlands"); //community Dutch contribution
#endif // COMMUNITY_LANG_GROUP1_NL
#ifdef COMMUNITY_LANG_GROUP1_SV
case LANG_CODE_SV: return _n("Svenska"); //community Swedish contribution
#endif // COMMUNITY_LANG_GROUP1_SV
#ifdef COMMUNITY_LANG_GROUP1_NO
case LANG_CODE_NO: return _n("Norsk"); //community Swedish contribution
#endif // COMMUNITY_LANG_GROUP1_NO
#ifdef COMMUNITY_LANG_GROUP1_DA
case LANG_CODE_DA: return _n("Dansk"); //community Danish contribution
#endif // COMMUNITY_LANG_GROUP1_DA
#ifdef COMMUNITY_LANG_GROUP1_SK
case LANG_CODE_SK: return _n("Slovencina"); //community Slovak contribution
#endif // COMMUNITY_LANG_GROUP1_SK
#ifdef COMMUNITY_LANG_GROUP1_SL
case LANG_CODE_SL: return _n("Slovenscina"); //community Slovanian contribution
#endif // COMMUNITY_LANG_GROUP1_SL
#ifdef COMMUNITY_LANG_GROUP1_HU
case LANG_CODE_HU: return _n("Magyar"); //community Hungarian contribution
#endif // COMMUNITY_LANG_GROUP1_HU
#ifdef COMMUNITY_LANG_GROUP1_LB
case LANG_CODE_LB: return _n("Letzebuergesch"); //community Luxembourgish contribution
#endif // COMMUNITY_LANG_GROUP1_LB
#ifdef COMMUNITY_LANG_GROUP1_HR
case LANG_CODE_HR: return _n("Hrvatski"); //community Croatian contribution
#endif // COMMUNITY_LANG_GROUP1_HR
#ifdef COMMUNITY_LANG_GROUP2_LT
case LANG_CODE_LT: return _n("Lietuviu"); //community Lithuanian contribution
#endif // COMMUNITY_LANG_GROUP2_LT
#ifdef COMMUNITY_LANG_GROUP1_RO
case LANG_CODE_RO: return _n("Romana"); //community Romanian contribution
#endif // COMMUNITY_LANG_GROUP1_RO
#ifdef COMMUNITY_LANG_SUPPORT //Community language support
#ifdef COMMUNITY_LANG_NL
case LANG_CODE_NL: return _n("Nederlands"); //community contribution
#endif // COMMUNITY_LANG_NL
//Use the 3 lines below as a template and replace 'QR' and 'New language'
//#ifdef COMMUNITY_LANG_GROUP1_QR
//#ifdef COMMUNITY_LANG_QR
// case LANG_CODE_QR: return _n("New language"); //community contribution
//#endif // COMMUNITY_LANG_GROUP1_QR
#endif // COMMUNITY_LANGUAGE_SUPPORT
//#endif // COMMUNITY_LANG_QR
#endif // COMMUNITY_LANG_SUPPORT
}
return _n("??");
}
@ -276,7 +245,7 @@ const char* lang_get_sec_lang_str_by_id(uint16_t id)
return ui + pgm_read_word(((uint16_t*)(ui + 16 + id * 2))); //read relative offset and return calculated pointer
}
uint16_t lang_print_sec_lang()
uint16_t lang_print_sec_lang(FILE* out)
{
printf_P(_n("&_SEC_LANG = 0x%04x\n"), &_SEC_LANG);
printf_P(_n("sizeof(_SEC_LANG) = 0x%04x\n"), sizeof(_SEC_LANG));
@ -298,7 +267,7 @@ uint16_t lang_print_sec_lang()
puts_P(_n(" strings:\n"));
uint16_t ui = _SEC_LANG_TABLE; //table pointer
for (ui = 0; ui < _lt_count; ui++)
printf_P(_n(" %3d %S\n"), ui, lang_get_sec_lang_str_by_id(ui));
fprintf_P(out, _n(" %3d %S\n"), ui, lang_get_sec_lang_str_by_id(ui));
return _lt_count;
}
#endif //DEBUG_SEC_LANG
@ -310,5 +279,5 @@ void lang_boot_update_start(uint8_t lang)
{
uint8_t cnt = lang_get_count();
if ((lang < 2) || (lang > cnt)) return; //only languages from xflash can be selected
bootapp_reboot_user0(lang << 3);
bootapp_reboot_user0(lang << 4);
}

View File

@ -13,15 +13,22 @@
#define PROTOCOL_VERSION "1.0"
#ifndef CUSTOM_MENDEL_NAME
#define MACHINE_NAME "Mendel"
#endif
#ifndef MACHINE_UUID
#define MACHINE_UUID "00000000-0000-0000-0000-000000000000"
#endif
#if (LANG_MODE == 0) //primary language only
#define PROGMEM_I2 __attribute__((section(".progmem0")))
#define PROGMEM_I1 __attribute__((section(".progmem1")))
#define PROGMEM_N1 __attribute__((section(".progmem2")))
#define _I(s) (__extension__({static const char __c[] PROGMEM_I1 = s; &__c[0];}))
#define ISTR(s) (s) // declare a translatable string
#define _i(s) _I(s) // declare a translatable string and return the translated form
#define _T(s) (s) // return translated string from reference
#define _O(s) (s) // return original (untranslated) string from reference
#define ISTR(s) s
#define _i(s) _I(s)
#define _T(s) s
#else //(LANG_MODE == 0)
// section .loc_sec (originaly .progmem0) will be used for localized translated strings
#define PROGMEM_I2 __attribute__((section(".loc_sec")))
@ -33,17 +40,14 @@
#define ISTR(s) "\xff\xff" s
#define _i(s) lang_get_translation(_I(s))
#define _T(s) lang_get_translation(s)
#define _O(s) (s + 2)
#endif //(LANG_MODE == 0)
#define _N(s) (__extension__({static const char __c[] PROGMEM_N1 = s; &__c[0];}))
#define _n(s) _N(s) // declare and return untranslated string
#define _R(s) (s) // return reference to translatable string (for warning suppression)
#define _n(s) _N(s)
/** @brief lang_table_header_t structure - (size= 16byte) */
typedef struct
{
uint32_t magic; //+0
uint32_t magic; //+0
uint16_t size; //+4
uint16_t count; //+6
uint16_t checksum; //+8
@ -90,45 +94,15 @@ typedef struct
#define LANG_CODE_FR 0x6672 //!<'fr'
#define LANG_CODE_IT 0x6974 //!<'it'
#define LANG_CODE_PL 0x706c //!<'pl'
#ifdef COMMUNITY_LANGUAGE_SUPPORT //Community language support
#ifdef COMMUNITY_LANG_GROUP1_NL
#ifdef COMMUNITY_LANG_SUPPORT //Community language support
#ifdef COMMUNITY_LANG_NL
#define LANG_CODE_NL 0x6e6c //!<'nl'
#endif // COMMUNITY_LANG_GROUP1_NL
#ifdef COMMUNITY_LANG_GROUP1_SV
#define LANG_CODE_SV 0x7376 //!<'sv'
#endif // COMMUNITY_LANG_GROUP1_SV
#ifdef COMMUNITY_LANG_GROUP1_NO
#define LANG_CODE_NO 0x6E6F //!<'no'
#endif // COMMUNITY_LANG_GROUP1_NO
#ifdef COMMUNITY_LANG_GROUP1_DA
#define LANG_CODE_DA 0x6461 //!<'da'
#endif // COMMUNITY_LANG_GROUP1_DA
#ifdef COMMUNITY_LANG_GROUP1_SL
#define LANG_CODE_SL 0x736C //!<'sl'
#endif // COMMUNITY_LANG_GROUP1_SL
#ifdef COMMUNITY_LANG_GROUP1_HU
#define LANG_CODE_HU 0x6875 //!<'hu'
#endif // COMMUNITY_LANG_GROUP1_HU
#ifdef COMMUNITY_LANG_GROUP1_LB
#define LANG_CODE_LB 0x6C62 //!<'lb'
#endif // COMMUNITY_LANG_GROUP1_LB
#ifdef COMMUNITY_LANG_GROUP1_HR
#define LANG_CODE_HR 0x6872 //!<'hr'
#endif // COMMUNITY_LANG_GROUP1_HR
#ifdef COMMUNITY_LANG_GROUP2_LT
#define LANG_CODE_LT 0x6C74 //!<'lt'
#endif // COMMUNITY_LANG_GROUP2_LT
#ifdef COMMUNITY_LANG_GROUP1_SK
#define LANG_CODE_SK 0x736b //!<'sk'
#endif // COMMUNITY_LANG_GROUP1_SK
#ifdef COMMUNITY_LANG_GROUP1_RO
#define LANG_CODE_RO 0x726F //!<'ro'
#endif // COMMUNITY_LANG_GROUP1_RO
#endif // COMMUNITY_LANG_NL
//Use the 3 lines below as a template and replace 'QR', '0X7172' and 'qr'
//#ifdef COMMUNITY_LANG_GROUP1_QR
//#ifdef COMMUNITY_LANG_QR
//#define LANG_CODE_QR 0x7172 //!<'qr'
//#endif // COMMUNITY_LANG_GROUP1_QR
#endif // COMMUNITY_LANGUAGE_SUPPORT
//#endif // COMMUNITY_LANG_QR
#endif // COMMUNITY_LANG_SUPPORT
///@}
#if defined(__cplusplus)
@ -141,7 +115,9 @@ extern uint8_t lang_selected;
#if (LANG_MODE != 0)
extern const char _SEC_LANG[LANG_SIZE_RESERVED];
extern const char* lang_get_translation(const char* s);
#define _SEC_LANG_TABLE ((uint16_t)&_SEC_LANG)
/** @def _SEC_LANG_TABLE
* @brief Align table to start of 256 byte page */
#define _SEC_LANG_TABLE ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00)
#endif //(LANG_MODE != 0)
/** @brief selects language, eeprom is updated in case of success */
@ -163,7 +139,7 @@ extern uint8_t lang_is_selected(void);
#ifdef DEBUG_SEC_LANG
extern const char* lang_get_sec_lang_str_by_id(uint16_t id);
extern uint16_t lang_print_sec_lang();
extern uint16_t lang_print_sec_lang(FILE* out);
#endif //DEBUG_SEC_LANG
extern void lang_boot_update_start(uint8_t lang);

File diff suppressed because it is too large Load Diff

View File

@ -22,11 +22,20 @@ extern void lcd_clear(void);
extern void lcd_home(void);
extern void lcd_set_cursor(uint8_t col, uint8_t row);
/*extern void lcd_no_display(void);
extern void lcd_display(void);
extern void lcd_no_blink(void);
extern void lcd_blink(void);
extern void lcd_no_cursor(void);
extern void lcd_cursor(void);
extern void lcd_scrollDisplayLeft(void);
extern void lcd_scrollDisplayRight(void);
extern void lcd_leftToRight(void);
extern void lcd_rightToLeft(void);
extern void lcd_autoscroll(void);
extern void lcd_no_autoscroll(void);*/
/// @brief Change the cursor column position while preserving the current row position
/// @param col column number, ranges from 0 to LCD_WIDTH - 1
void lcd_set_cursor_column(uint8_t col);
extern void lcd_set_cursor(uint8_t col, uint8_t row);
extern void lcd_createChar_P(uint8_t, const uint8_t*);
@ -41,21 +50,29 @@ extern int lcd_printf_P(const char* format, ...);
extern void lcd_space(uint8_t n);
extern void lcd_printNumber(unsigned long n, uint8_t base);
extern void lcd_printFloat(double number, uint8_t digits);
extern void lcd_print(const char*);
extern uint8_t lcd_print_pad(const char* s, uint8_t len);
/// @brief print a string from PROGMEM with left-adjusted padding
/// @param s string from PROGMEM.
/// @param len maximum number of characters to print, including padding. Ranges from 0 to LCD_WIDTH.
/// @return number of padded bytes. 0 means there was no padding.
uint8_t lcd_print_pad_P(const char* s, uint8_t len);
extern void lcd_print(char, int = 0);
extern void lcd_print(unsigned char, int = 0);
extern void lcd_print(int, int = 10);
extern void lcd_print(unsigned int, int = 10);
extern void lcd_print(long, int = 10);
extern void lcd_print(unsigned long, int = 10);
extern void lcd_print(double, int = 2);
//! @brief Clear screen
#define ESC_2J "\x1b[2J"
//! @brief Show cursor
#define ESC_25h "\x1b[?25h"
//! @brief Hide cursor
#define ESC_25l "\x1b[?25l"
//! @brief Set cursor to
//! @param c column
//! @param r row
#define ESC_H(c,r) "\x1b["#r";"#c"H"
#define LCD_UPDATE_INTERVAL 100
#define LCD_TIMEOUT_TO_STATUS 30000ul //!< Generic timeout to status screen in ms, when no user action.
@ -72,9 +89,17 @@ typedef void (*lcd_lcdupdate_func_t)(void);
//Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial)
extern uint8_t lcd_draw_update;
extern int16_t lcd_encoder;
extern int32_t lcd_encoder;
extern uint8_t lcd_click_trigger;
extern uint8_t lcd_encoder_bits;
// lcd_encoder_diff is updated from interrupt context and added to lcd_encoder every LCD update
extern int8_t lcd_encoder_diff;
//the last checked lcd_buttons in a bit array.
extern uint8_t lcd_buttons;
extern uint8_t lcd_button_pressed;
extern uint8_t lcd_update_enabled;
@ -82,9 +107,13 @@ extern LongTimer lcd_timeoutToStatus;
extern uint32_t lcd_next_update_millis;
extern uint8_t lcd_status_update_delay;
extern lcd_longpress_func_t lcd_longpress_func;
extern bool lcd_longpress_trigger;
extern lcd_charsetup_func_t lcd_charsetup_func;
extern lcd_lcdupdate_func_t lcd_lcdupdate_func;
@ -96,10 +125,6 @@ extern void lcd_beeper_quick_feedback(void);
//Cause an LCD refresh, and give the user visual or audible feedback that something has happened
extern void lcd_quick_feedback(void);
/// @brief Check whether knob is rotated or clicked and update relevant
///variables. Flags are set by lcd_buttons_update in ISR context.
extern void lcd_knob_update();
extern void lcd_update(uint8_t lcdDrawUpdateOverride);
extern void lcd_update_enable(uint8_t enabled);
@ -111,25 +136,38 @@ extern void lcd_buttons_update(void);
//! When constructed (on stack), original state state of lcd_update_enabled is stored
//! and LCD updates are disabled.
//! When destroyed (gone out of scope), original state of LCD update is restored.
//! Do not call lcd_update_enable() to prevent calling lcd_update() in sensitive code.
//! in certain scenarios it will cause recursion e.g. in the menus.
//! It has zero overhead compared to storing bool saved = lcd_update_enabled
//! and calling lcd_update_enable(false) and lcd_update_enable(saved).
class LcdUpdateDisabler
{
public:
LcdUpdateDisabler(): m_updateEnabled(lcd_update_enabled)
{
lcd_update_enabled = false;
lcd_update_enable(false);
}
~LcdUpdateDisabler()
{
lcd_update_enabled = m_updateEnabled;
lcd_update_enable(m_updateEnabled);
}
private:
bool m_updateEnabled;
};
////////////////////////////////////
// Setup button and encode mappings for each panel (into 'lcd_buttons' variable
//
// This is just to map common functions (across different panels) onto the same
// macro name. The mapping is independent of whether the button is directly connected or
// via a shift/i2c register.
#define BLEN_B 1
#define BLEN_A 0
#define EN_B (1<<BLEN_B) // The two encoder pins are connected through BTN_EN1 and BTN_EN2
#define EN_A (1<<BLEN_A)
#define BLEN_C 2
#define EN_C (1<<BLEN_C)
//! @brief Was button clicked?
//!
@ -140,32 +178,41 @@ private:
//!
//! @retval 0 button was not clicked
//! @retval 1 button was clicked
#define LCD_CLICKED (lcd_click_trigger)
#define LCD_CLICKED (lcd_buttons&EN_C)
////////////////////////
// Setup Rotary Encoder Bit Values (for two pin encoders to indicate movement)
// These values are independent of which pins are used for EN_A and EN_B indications
// The rotary encoder part is also independent to the chipset used for the LCD
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
////////////////////////////////////
//Custom characters defined in the first 8 characters of the LCD
#define LCD_STR_ARROW_RIGHT "\x7E" //from the default character set
#define LCD_STR_ARROW_LEFT "\x7F" //from the default character set
#define LCD_STR_BEDTEMP "\x80"
#define LCD_STR_DEGREE "\x81"
#define LCD_STR_THERMOMETER "\x82"
#define LCD_STR_UPLEVEL "\x83"
#define LCD_STR_REFRESH "\x84"
#define LCD_STR_FOLDER "\x85"
#define LCD_STR_FEEDRATE "\x86"
#define LCD_STR_CLOCK "\x87"
#define LCD_STR_ARROW_2_DOWN "\x88"
#define LCD_STR_CONFIRM "\x89"
#define LCD_STR_SOLID_BLOCK "\xFF" //from the default character set
#define LCD_STR_BEDTEMP "\x00"
#define LCD_STR_DEGREE "\x01"
#define LCD_STR_THERMOMETER "\x02"
#define LCD_STR_UPLEVEL "\x03"
#define LCD_STR_REFRESH "\x04"
#define LCD_STR_FOLDER "\x05"
#define LCD_STR_FEEDRATE "\x06"
#define LCD_STR_CLOCK "\x07"
#define LCD_STR_ARROW_UP "\x0B"
#define LCD_STR_ARROW_DOWN "\x01"
#define LCD_STR_ARROW_RIGHT "\x7E" //from the default character set
extern void lcd_frame_start();
extern void lcd_set_custom_characters(void);
extern void lcd_set_custom_characters_arrows(void);
extern void lcd_set_custom_characters_nextpage(void);
extern void lcd_set_custom_characters_degree(void);
//! @brief Consume click and longpress event
//! @brief Consume click event
inline void lcd_consume_click()
{
lcd_click_trigger = 0;
lcd_longpress_trigger = 0;
lcd_button_pressed = 0;
lcd_buttons &= 0xff^EN_C;
}

View File

@ -11,9 +11,6 @@
#define CRITICAL_SECTION_END SREG = _sreg;
#endif //CRITICAL_SECTION_START
#define _REGNAME(registerbase,number,suffix) registerbase##number##suffix
#define _REGNAME_SHORT(registerbase,suffix) registerbase##suffix
// Macros to make a string from a macro
#define STRINGIFY_(M) #M
#define STRINGIFY(M) STRINGIFY_(M)

View File

@ -1,379 +0,0 @@
/*
* MeatPack G-Code Compression
*
* Algorithm & Implementation: Scott Mudge - mail@scottmudge.com
* Date: Dec. 2020
*/
#include "meatpack.h"
#ifdef ENABLE_MEATPACK
#include "language.h"
#include "Marlin.h"
//#define MP_DEBUG
// Utility definitions
#define MeatPack_CommandByte 0b11111111
#define MeatPack_NextPackedFirst 0b00000001
#define MeatPack_NextPackedSecond 0b00000010
#define MeatPack_SpaceCharIdx 11U
#define MeatPack_SpaceCharReplace 'E'
#define MeatPack_ProtocolVersion "PV01"
/*
Character Frequencies from ~30 MB of comment-stripped gcode:
'1' -> 4451136
'0' -> 4253577
' ' -> 3053297
'.' -> 3035310
'2' -> 1523296
'8' -> 1366812
'4' -> 1353273
'9' -> 1352147
'3' -> 1262929
'5' -> 1189871
'6' -> 1127900
'7' -> 1112908
'\n' -> 1087683
'G' -> 1075806
'X' -> 975742
'E' -> 965275
'Y' -> 965274
'F' -> 99416
'-' -> 90242
'Z' -> 34109
'M' -> 11879
'S' -> 9910
If spaces are omitted, we add 'E'
*/
// Note:
// I've tried both a switch/case method and a lookup table. The disassembly is exactly the same after compilation, byte-to-byte.
// Thus, performance is identical.
#define USE_LOOKUP_TABLE
// State variables
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
enum MeatPack_ConfigStateFlags {
MPConfig_None = 0,
MPConfig_Active = (1 << 0),
MPConfig_NoSpaces = (1 << 1)
};
uint8_t mp_config = MPConfig_None; // Configuration state
uint8_t mp_cmd_active = 0; // Is a command is pending
uint8_t mp_char_buf = 0; // Buffers a character if dealing with out-of-sequence pairs
uint8_t mp_cmd_count = 0; // Counts how many command bytes are received (need 2)
uint8_t mp_full_char_queue = 0; // Counts how many full-width characters are to be received
uint8_t mp_char_out_buf[2]; // Output buffer for caching up to 2 characters
uint8_t mp_char_out_count = 0; // Stores number of characters to be read out.
#ifdef USE_LOOKUP_TABLE
// The 15 most-common characters used in G-code, ~90-95% of all g-code uses these characters
// NOT storing this with PROGMEM, given how frequently this table will be accessed.
uint8_t MeatPackLookupTbl[16] = {
'0', // 0000
'1', // 0001
'2', // 0010
'3', // 0011
'4', // 0100
'5', // 0101
'6', // 0110
'7', // 0111
'8', // 1000
'9', // 1001
'.', // 1010
' ', // 1011
'\n', // 1100
'G', // 1101
'X', // 1110
'\0' // never used, 0b1111 is used to indicate next 8-bits is a full character
};
#else
inline uint8_t get_char(const uint8_t in) {
switch (in) {
case 0b0000:
return '0';
break;
case 0b0001:
return '1';
break;
case 0b0010:
return '2';
break;
case 0b0011:
return '3';
break;
case 0b0100:
return '4';
break;
case 0b0101:
return '5';
break;
case 0b0110:
return '6';
break;
case 0b0111:
return '7';
break;
case 0b1000:
return '8';
break;
case 0b1001:
return '9';
break;
case 0b1010:
return '.';
break;
case 0b1011:
return (mp_config & MPConfig_NoSpaces) ? MeatPack_SpaceCharReplace : ' ';
break;
case 0b1100:
return '\n';
break;
case 0b1101:
return 'G';
break;
case 0b1110:
return 'X';
break;
}
return 0;
}
#endif
// #DEBUGGING
#ifdef MP_DEBUG
uint32_t mp_chars_decoded = 0;
#endif
void FORCE_INLINE mp_handle_output_char(const uint8_t c) {
mp_char_out_buf[mp_char_out_count++] = c;
#ifdef MP_DEBUG
if (mp_chars_decoded < 4096) {
++mp_chars_decoded;
SERIAL_ECHOPGM("RB: ");
MYSERIAL.print((char)c);
SERIAL_ECHOLNPGM("");
}
#endif
}
// Storing
// packed = ((low & 0xF) << 4) | (high & 0xF);
// Unpacking
// low = (packed >> 4) & 0xF;
// high = (packed & 0xF);
//==========================================================================
uint8_t FORCE_INLINE mp_unpack_chars(const uint8_t pk, uint8_t* __restrict const chars_out) {
uint8_t out = 0;
#ifdef USE_LOOKUP_TABLE
// If lower 4 bytes is 0b1111, the higher 4 are unused, and next char is full.
if ((pk & MeatPack_FirstNotPacked) == MeatPack_FirstNotPacked) out |= MeatPack_NextPackedFirst;
else chars_out[0] = MeatPackLookupTbl[(pk & 0xF)]; // Assign lower char
// Check if upper 4 bytes is 0b1111... if so, we don't need the second char.
if ((pk & MeatPack_SecondNotPacked) == MeatPack_SecondNotPacked) out |= MeatPack_NextPackedSecond;
else chars_out[1] = MeatPackLookupTbl[((pk >> 4) & 0xf)]; // Assign upper char
#else
// If lower 4 bytes is 0b1111, the higher 4 are unused, and next char is full.
if ((pk & MeatPack_FirstNotPacked) == MeatPack_FirstNotPacked) out |= MeatPack_NextPackedFirst;
else chars_out[0] = get_char(pk & 0xF); // Assign lower char
// Check if upper 4 bytes is 0b1111... if so, we don't need the second char.
if ((pk & MeatPack_SecondNotPacked) == MeatPack_SecondNotPacked) out |= MeatPack_NextPackedSecond;
else chars_out[1] = get_char((pk >> 4) & 0xf); // Assign upper char
#endif
return out;
}
//==============================================================================
void FORCE_INLINE mp_reset_state() {
mp_char_out_count = 0;
mp_cmd_active = MPCommand_None;
mp_config = MPConfig_None;
mp_char_buf = 0;
mp_cmd_count = 0;
mp_cmd_active = 0;
mp_full_char_queue = 0;
#ifdef MP_DEBUG
mp_chars_decoded = 0;
SERIAL_ECHOLNPGM("MP Reset");
#endif
}
//==========================================================================
void FORCE_INLINE mp_handle_rx_char_inner(const uint8_t c) {
// Packing enabled, handle character and re-arrange them appropriately.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if (mp_config & MPConfig_Active) {
if (mp_full_char_queue > 0) {
mp_handle_output_char(c);
if (mp_char_buf > 0) {
mp_handle_output_char(mp_char_buf);
mp_char_buf = 0;
}
--mp_full_char_queue;
}
else {
uint8_t buf[2] = { 0,0 };
const uint8_t res = mp_unpack_chars(c, buf);
if (res & MeatPack_NextPackedFirst) {
++mp_full_char_queue;
if (res & MeatPack_NextPackedSecond) ++mp_full_char_queue;
else mp_char_buf = buf[1];
}
else {
mp_handle_output_char(buf[0]);
if (buf[0] != '\n') {
if (res & MeatPack_NextPackedSecond) ++mp_full_char_queue;
else mp_handle_output_char(buf[1]);
}
}
}
}
else // Packing not enabled, just copy character to output
mp_handle_output_char(c);
}
//==========================================================================
void FORCE_INLINE mp_echo_config_state() {
SERIAL_ECHOPGM(" [MP] "); // Add space at idx 0 just in case first character is dropped due to timing/sync issues.
// NOTE: if any configuration vars are added below, the outgoing sync text for host plugin
// should not contain the "PV' substring, as this is used to indicate protocol version
SERIAL_ECHOPGM(MeatPack_ProtocolVersion);
// Echo current state
if (mp_config & MPConfig_Active)
SERIAL_ECHOPGM(" ON");
else
SERIAL_ECHOPGM(" OFF");
if (mp_config & MPConfig_NoSpaces)
SERIAL_ECHOPGM(" NSP"); // [N]o [SP]aces
else
SERIAL_ECHOPGM(" ESP"); // [E]nabled [SP]aces
SERIAL_ECHOLNPGM("");
// Validate config vars
#ifdef USE_LOOKUP_TABLE
if (mp_config & MPConfig_NoSpaces)
MeatPackLookupTbl[MeatPack_SpaceCharIdx] = (uint8_t)(MeatPack_SpaceCharReplace);
else
MeatPackLookupTbl[MeatPack_SpaceCharIdx] = ' ';
#endif
}
//==========================================================================
void FORCE_INLINE mp_handle_cmd(const MeatPack_Command c) {
switch (c) {
case MPCommand_EnablePacking: {
mp_config |= MPConfig_Active;
#ifdef MP_DEBUG
SERIAL_ECHOLNPGM("[MPDBG] ENABL REC");
#endif
} break;
case MPCommand_DisablePacking: {
mp_config &= ~(MPConfig_Active);
#ifdef MP_DEBUG
SERIAL_ECHOLNPGM("[MPDBG] DISBL REC");
#endif
} break;
case MPCommand_ResetAll: {
mp_reset_state();
#ifdef MP_DEBUG
SERIAL_ECHOLNPGM("[MPDBG] RESET REC");
#endif
} break;
case MPCommand_EnableNoSpaces: {
mp_config |= MPConfig_NoSpaces;
#ifdef MP_DEBUG
SERIAL_ECHOLNPGM("[MPDBG] ENABL NSP");
#endif
} break;
case MPCommand_DisableNoSpaces: {
mp_config &= ~(MPConfig_NoSpaces);
#ifdef MP_DEBUG
SERIAL_ECHOLNPGM("[MPDBG] DISBL NSP");
#endif
} break;
default: {
#ifdef MP_DEBUG
SERIAL_ECHOLN("[MPDBG] UNK CMD REC");
#endif
}
case MPCommand_QueryConfig:
break;
}
mp_echo_config_state();
}
//==========================================================================
void mp_handle_rx_char(const uint8_t c) {
// Check for commit complete
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if (c == (uint8_t)(MeatPack_CommandByte)) {
if (mp_cmd_count > 0) {
mp_cmd_active = 1;
mp_cmd_count = 0;
}
else
++mp_cmd_count;
return;
}
if (mp_cmd_active > 0) {
mp_handle_cmd((MeatPack_Command)c);
mp_cmd_active = 0;
return;
}
if (mp_cmd_count > 0) {
mp_handle_rx_char_inner((uint8_t)(MeatPack_CommandByte));
mp_cmd_count = 0;
}
mp_handle_rx_char_inner(c);
}
//==========================================================================
uint8_t mp_get_result_char(char* const __restrict out) {
if (mp_char_out_count > 0) {
const uint8_t res = mp_char_out_count;
for (uint8_t i = 0; i < mp_char_out_count; ++i)
out[i] = (char)mp_char_out_buf[i];
mp_char_out_count = 0;
return res;
}
return 0;
}
//==============================================================================
void mp_trigger_cmd(const MeatPack_Command cmd)
{
mp_handle_cmd(cmd);
}
#endif

View File

@ -1,70 +0,0 @@
/*
* MeatPack G-Code Compression
*
* Algorithm & Implementation: Scott Mudge - mail@scottmudge.com
* Date: Dec. 2020
*
* Specifically optimized for 3D printing G-Code, this is a zero-cost data compression method
* which packs ~180-190% more data into the same amount of bytes going to the CNC controller.
* As a majority of G-Code can be represented by a restricted alphabet, I performed histogram
* analysis on a wide variety of 3D printing gcode samples, and found ~93% of all gcode could
* be represented by the same 15-character alphabet.
*
* This allowed me to design a system of packing 2 8-bit characters into a single byte, assuming
* they fall within this limited 15-character alphabet. Using a 4-bit lookup table, these 8-bit
* characters can be represented by a 4-bit index.
*
* Combined with some logic to allow commingling of full-width characters outside of this 15-
* character alphabet (at the cost of an extra 8-bits per full-width character), and by stripping
* out unnecessary comments, the end result is gcode which is roughly half the original size.
*
* Why did I do this? I noticed micro-stuttering and other data-bottleneck issues while printing
* objects with high curvature, especially at high speeds. There is also the issue of the limited
* baud rate provided by Prusa's Atmega2560-based boards, over the USB serial connection. So soft-
* ware like OctoPrint would also suffer this same micro-stuttering and poor print quality issue.
*
*/
#include <stdint.h>
#include "Configuration.h"
#ifndef MEATPACK_H_
#define MEATPACK_H_
#ifdef ENABLE_MEATPACK
#define MeatPack_SecondNotPacked 0b11110000
#define MeatPack_FirstNotPacked 0b00001111
// These are commands sent to MeatPack to control its behavior.
// They are sent by first sending 2x MeatPack_CommandByte (0xFF) in sequence,
// followed by one of the command bytes below.
// Provided that 0xFF is an exceedingly rare character that is virtually never
// present in g-code naturally, it is safe to assume 2 in sequence should never
// happen naturally, and so it is used as a signal here.
//
// 0xFF *IS* used in "packed" g-code (used to denote that the next 2 characters are
// full-width), however 2 in a row will never occur, as the next 2 bytes will always
// some non-0xFF character.
enum MeatPack_Command {
MPCommand_None = 0U,
// MPCommand_TogglePacking = 253U, -- Unused, byte 253 can be re-used later.
MPCommand_EnablePacking = 251U,
MPCommand_DisablePacking = 250U,
MPCommand_ResetAll = 249U,
MPCommand_QueryConfig = 248U,
MPCommand_EnableNoSpaces = 247U,
MPCommand_DisableNoSpaces = 246U
};
// Pass in a character rx'd by SD card or serial. Automatically parses command/ctrl sequences,
// and will control state internally.
extern void mp_handle_rx_char(const uint8_t c);
// After passing in rx'd char using above method, call this to get characters out. Can return
// from 0 to 2 characters at once.
// @param out [in] Output pointer for unpacked/processed data.
// @return Number of characters returned. Range from 0 to 2.
extern uint8_t mp_get_result_char(char* const __restrict out);
#endif
#endif // MEATPACK_H_

View File

@ -14,6 +14,8 @@
#include "static_assert.h"
#include "sound.h"
extern int32_t lcd_encoder;
#define MENU_DEPTH_MAX 7
static menu_record_t menu_stack[MENU_DEPTH_MAX];
@ -24,7 +26,7 @@ uint8_t menu_data[MENU_DATA_SIZE];
#endif
uint8_t menu_depth = 0;
uint8_t menu_block_mask = MENU_BLOCK_NONE;
uint8_t menu_block_entering_on_serious_errors = SERIOUS_ERR_NONE;
uint8_t menu_line = 0;
uint8_t menu_item = 0;
uint8_t menu_row = 0;
@ -45,7 +47,7 @@ void menu_data_reset(void)
memset(&menu_data, 0, sizeof(menu_data));
}
void menu_goto(menu_func_t menu, const int16_t encoder, bool reset_menu_state, const bool feedback)
void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bool reset_menu_state)
{
CRITICAL_SECTION_START;
if (menu_menu != menu)
@ -53,10 +55,11 @@ void menu_goto(menu_func_t menu, const int16_t encoder, bool reset_menu_state, c
menu_menu = menu;
lcd_encoder = encoder;
menu_top = 0; //reset menu view. Needed if menu_back() is called from deep inside a menu, such as Support
lcd_draw_update = 2; // Full LCD re-draw
CRITICAL_SECTION_END;
if (feedback) lcd_beeper_quick_feedback();
if (reset_menu_state) menu_data_reset();
if (reset_menu_state)
menu_data_reset();
if (feedback) lcd_quick_feedback();
}
else
CRITICAL_SECTION_END;
@ -64,6 +67,7 @@ void menu_goto(menu_func_t menu, const int16_t encoder, bool reset_menu_state, c
void menu_start(void)
{
if (lcd_encoder > 0x8000) lcd_encoder = 0;
if (lcd_encoder < 0)
{
lcd_encoder = 0;
@ -72,16 +76,11 @@ void menu_start(void)
if (lcd_encoder < menu_top)
menu_top = lcd_encoder;
menu_line = menu_top;
menu_clicked = lcd_clicked(); // Consume click event
menu_clicked = LCD_CLICKED;
}
void menu_end(void)
{
if (menu_row >= LCD_HEIGHT)
{
// Early abort if the menu was clicked. The current menu might have changed because of the click event
return;
}
if (lcd_encoder >= menu_item)
{
lcd_encoder = menu_item - 1;
@ -90,6 +89,7 @@ void menu_end(void)
if (((uint8_t)lcd_encoder) >= menu_top + LCD_HEIGHT)
{
menu_top = lcd_encoder - LCD_HEIGHT + 1;
lcd_draw_update = 1;
menu_line = menu_top - 1;
menu_row = -1;
}
@ -98,7 +98,7 @@ void menu_end(void)
void menu_back(uint8_t nLevel)
{
menu_depth = ((menu_depth > nLevel) ? (menu_depth - nLevel) : 0);
menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true);
menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true, true);
}
void menu_back(void)
@ -110,8 +110,8 @@ void menu_back_no_reset(void)
{
if (menu_depth > 0)
{
menu_depth--;
menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, false);
menu_depth--;
menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true, false);
}
}
@ -121,46 +121,71 @@ void menu_back_if_clicked(void)
menu_back();
}
void menu_submenu(menu_func_t submenu, const bool feedback)
void menu_back_if_clicked_fb(void)
{
if (lcd_clicked())
{
lcd_quick_feedback();
menu_back();
}
}
void menu_submenu(menu_func_t submenu)
{
if (menu_depth < MENU_DEPTH_MAX)
{
menu_stack[menu_depth].menu = menu_menu;
menu_stack[menu_depth++].position = lcd_encoder;
menu_goto(submenu, 0, true, feedback);
menu_goto(submenu, 0, true, true);
}
}
void menu_submenu_no_reset(menu_func_t submenu, const bool feedback)
void menu_submenu_no_reset(menu_func_t submenu)
{
if (menu_depth < MENU_DEPTH_MAX)
{
menu_stack[menu_depth].menu = menu_menu;
menu_stack[menu_depth++].position = lcd_encoder;
menu_goto(submenu, 0, false, feedback);
menu_goto(submenu, 0, true, false);
}
}
void menu_item_ret(void)
uint8_t menu_item_ret(void)
{
lcd_beeper_quick_feedback();
lcd_draw_update = 2;
menu_item++;
//prevent the rest of the menu items from rendering or getting clicked
menu_row = LCD_HEIGHT; // early exit from the MENU_BEGIN() for loop at the end of the current cycle
menu_line = 0; // prevent subsequent menu items from rendering at all in the current MENU_BEGIN() for loop cycle
menu_clicked = 0; // prevent subsequent items from being able to be clicked in case the current menu or position was changed by the clicked menu item
lcd_button_pressed = false;
return 1;
}
/*
int menu_draw_item_printf_P(char type_char, const char* format, ...)
{
va_list args;
va_start(args, format);
int ret = 0;
lcd_set_cursor(0, menu_row);
if (lcd_encoder == menu_item)
lcd_print('>');
else
lcd_print(' ');
int cnt = vfprintf_P(lcdout, format, args);
for (int i = cnt; i < 18; i++)
lcd_print(' ');
lcd_print(type_char);
va_end(args);
return ret;
}
*/
static char menu_selection_mark(){
return (lcd_encoder == menu_item)?'>':' ';
}
static void menu_draw_item_puts_P(char type_char, const char* str)
{
lcd_putc_at(0, menu_row, menu_selection_mark());
lcd_print_pad_P(str, LCD_WIDTH - 2);
lcd_putc(type_char);
lcd_set_cursor(0, menu_row);
lcd_printf_P(PSTR("%c%-18.18S%c"), menu_selection_mark(), str, type_char);
}
static void menu_draw_toggle_puts_P(const char* str, const char* toggle, const uint8_t settings)
@ -169,21 +194,14 @@ static void menu_draw_toggle_puts_P(const char* str, const char* toggle, const u
//xxxxxcba
//a = selection mark. If it's set(1), then '>' will be used as the first character on the line. Else leave blank
//b = toggle string is from progmem
uint8_t is_progmem = settings & 0x02;
const char eol = (toggle == NULL) ? LCD_STR_ARROW_RIGHT[0] : ' ';
//c = do not set cursor at all. Must be handled externally.
char lineStr[LCD_WIDTH + 1];
const char eol = (toggle == NULL)?LCD_STR_ARROW_RIGHT[0]:' ';
if (toggle == NULL) toggle = _T(MSG_NA);
uint8_t len = 4 + (is_progmem ? strlen_P(toggle) : strlen(toggle));
lcd_putc_at(0, menu_row, (settings & 0x01) ? '>' : ' ');
lcd_print_pad_P(str, LCD_WIDTH - len);
lcd_putc('[');
if (is_progmem)
{
lcd_puts_P(toggle);
} else {
lcd_print(toggle);
}
lcd_putc(']');
lcd_putc(eol);
sprintf_P(lineStr, PSTR("%c%-18.18S"), (settings & 0x01)?'>':' ', str);
sprintf_P(lineStr + LCD_WIDTH - ((settings & 0x02)?strlen_P(toggle):strlen(toggle)) - 3, (settings & 0x02)?PSTR("[%S]%c"):PSTR("[%s]%c"), toggle, eol);
if (!(settings & 0x04)) lcd_set_cursor(0, menu_row);
fputs(lineStr, lcdout);
}
//! @brief Format sheet name
@ -216,32 +234,38 @@ void menu_format_sheet_select_E(const Sheet &sheet_E, SheetFormatBuffer &buffer)
static void menu_draw_item_select_sheet_E(char type_char, const Sheet &sheet)
{
lcd_set_cursor(0, menu_row);
SheetFormatBuffer buffer;
menu_format_sheet_select_E(sheet, buffer);
lcd_putc_at(0, menu_row, menu_selection_mark());
lcd_print_pad(buffer.c, LCD_WIDTH - 2);
lcd_putc(type_char);
lcd_printf_P(PSTR("%c%-18.18s%c"), menu_selection_mark(), buffer.c, type_char);
}
static void menu_draw_item_puts_E(char type_char, const Sheet &sheet)
{
lcd_set_cursor(0, menu_row);
SheetFormatBuffer buffer;
menu_format_sheet_E(sheet, buffer);
lcd_putc_at(0, menu_row, menu_selection_mark());
lcd_print_pad(buffer.c, LCD_WIDTH - 2);
lcd_putc(type_char);
lcd_printf_P(PSTR("%c%-18.18s%c"), menu_selection_mark(), buffer.c, type_char);
}
static void menu_draw_item_puts_P(char type_char, const char* str, char num)
{
const uint8_t max_strlen = LCD_WIDTH - 3;
lcd_putc_at(0, menu_row, menu_selection_mark());
uint8_t len = lcd_print_pad_P(str, max_strlen);
lcd_putc_at((max_strlen - len) + 2, menu_row, num);
lcd_putc_at(LCD_WIDTH - 1, menu_row, type_char);
lcd_set_cursor(0, menu_row);
lcd_printf_P(PSTR("%c%-.16S "), menu_selection_mark(), str);
lcd_putc(num);
lcd_putc_at(19, menu_row, type_char);
}
/*
int menu_draw_item_puts_P_int16(char type_char, const char* str, int16_t val, )
{
lcd_set_cursor(0, menu_row);
int cnt = lcd_printf_P(PSTR("%c%-18S%c"), (lcd_encoder == menu_item)?'>':' ', str, type_char);
return cnt;
}
*/
void menu_item_dummy(void)
{
menu_item++;
@ -253,16 +277,13 @@ uint8_t menu_item_text_P(const char* str)
{
if (lcd_draw_update) menu_draw_item_puts_P(' ', str);
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_item_ret();
return 1;
}
return menu_item_ret();
}
menu_item++;
return 0;
}
void menu_item_submenu_P(const char* str, menu_func_t submenu)
uint8_t menu_item_submenu_P(const char* str, menu_func_t submenu)
{
if (menu_item == menu_line)
{
@ -270,14 +291,14 @@ void menu_item_submenu_P(const char* str, menu_func_t submenu)
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_submenu(submenu);
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
void menu_item_submenu_E(const Sheet &sheet, menu_func_t submenu)
uint8_t menu_item_submenu_E(const Sheet &sheet, menu_func_t submenu)
{
if (menu_item == menu_line)
{
@ -285,31 +306,33 @@ void menu_item_submenu_E(const Sheet &sheet, menu_func_t submenu)
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_submenu(submenu);
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
void __attribute__((noinline)) menu_item_function_E(const Sheet &sheet, menu_func_t func)
uint8_t __attribute__((noinline)) menu_item_function_E(const Sheet &sheet, menu_func_t func)
{
if (menu_item == menu_line)
{
if (lcd_draw_update) menu_draw_item_select_sheet_E(' ', sheet);
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_clicked = false;
lcd_consume_click();
lcd_update_enabled = 0;
if (func) func();
lcd_update_enabled = 1;
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
void menu_item_back_P(const char* str)
uint8_t menu_item_back_P(const char* str)
{
if (menu_item == menu_line)
{
@ -317,32 +340,34 @@ void menu_item_back_P(const char* str)
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_back();
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
bool __attribute__((noinline)) menu_item_leave(){
return ((menu_item == menu_line) && menu_clicked && (lcd_encoder == menu_item)) || menu_leaving;
}
void menu_item_function_P(const char* str, menu_func_t func)
uint8_t menu_item_function_P(const char* str, menu_func_t func)
{
if (menu_item == menu_line)
{
if (lcd_draw_update) menu_draw_item_puts_P(' ', str);
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_clicked = false;
lcd_consume_click();
lcd_update_enabled = 0;
if (func) func();
lcd_update_enabled = 1;
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
//! @brief Menu item function taking single parameter
@ -354,24 +379,26 @@ void menu_item_function_P(const char* str, menu_func_t func)
//! @param fn_par value to be passed to function
//! @retval 0
//! @retval 1 Item was clicked
void menu_item_function_P(const char* str, char number, void (*func)(uint8_t), uint8_t fn_par)
uint8_t menu_item_function_P(const char* str, char number, void (*func)(uint8_t), uint8_t fn_par)
{
if (menu_item == menu_line)
{
if (lcd_draw_update) menu_draw_item_puts_P(' ', str, number);
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_clicked = false;
lcd_consume_click();
lcd_update_enabled = 0;
if (func) func(fn_par);
lcd_update_enabled = 1;
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
void menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, const uint8_t settings)
uint8_t menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, const uint8_t settings)
{
if (menu_item == menu_line)
{
@ -381,21 +408,24 @@ void menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, c
if (toggle == NULL) // print N/A warning message
{
menu_submenu(func);
return menu_item_ret();
}
else // do the actual toggling
{
menu_clicked = false;
lcd_consume_click();
lcd_update_enabled = 0;
if (func) func();
lcd_update_enabled = 1;
return menu_item_ret();
}
menu_item_ret();
return;
}
}
menu_item++;
return 0;
}
void menu_item_gcode_P(const char* str, const char* str_gcode)
uint8_t menu_item_gcode_P(const char* str, const char* str_gcode)
{
if (menu_item == menu_line)
{
@ -403,54 +433,69 @@ void menu_item_gcode_P(const char* str, const char* str_gcode)
if (menu_clicked && (lcd_encoder == menu_item))
{
if (str_gcode) enquecommand_P(str_gcode);
menu_item_ret();
return;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
const char menu_fmt_int3[] PROGMEM = "%c%.15S:%s%3d";
const char menu_fmt_float31[] PROGMEM = "%-12.12S%+8.1f";
const char menu_fmt_float13[] PROGMEM = "%c%-13.13S%+5.3f";
/// @brief Draw the label and value for a menu edit item
/// @param chr 1 byte character
/// @param str String residing in program memory (PROGMEM)
/// @param val value to render, ranges from -999 to 9999
static void menu_draw_P(const char chr, const char* str, const int16_t val)
template<typename T>
static void menu_draw_P(char chr, const char* str, int16_t val);
template<>
void menu_draw_P<int16_t*>(char chr, const char* str, int16_t val)
{
lcd_putc(chr);
lcd_puts_P(str);
lcd_putc(':');
int text_len = strlen_P(str);
if (text_len > 15) text_len = 15;
char spaces[LCD_WIDTH + 1] = {0};
memset(spaces,' ', LCD_WIDTH);
if (val <= -100) spaces[15 - text_len - 1] = 0;
else spaces[15 - text_len] = 0;
lcd_printf_P(menu_fmt_int3, chr, str, spaces, val);
}
// Padding to compensate variable string length
const uint8_t len = strlen_P(str);
lcd_space((LCD_WIDTH - 4) - (2 + len));
// Right adjusted value
lcd_printf_P(PSTR("%4d"), val);
template<>
void menu_draw_P<uint8_t*>(char chr, const char* str, int16_t val)
{
menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]);
float factor = 1.0f + static_cast<float>(val) / 1000.0f;
if (val <= _md->minEditValue)
{
menu_draw_toggle_puts_P(str, _T(MSG_OFF), 0x04 | 0x02 | (chr=='>'));
}
else
{
lcd_printf_P(menu_fmt_float13, chr, str, factor);
}
}
//! @brief Draw up to 10 chars of text and a float number in format from +0.0 to +12345.0. The increased range is necessary
//! for displaying large values of extruder positions, which caused text overflow in the previous implementation.
//!
//!
//! @param str string label to print
//! @param val value to print aligned to the right side of the display
//!
//! @param val value to print aligned to the right side of the display
//!
//! Implementation comments:
//! The text needs to come with a colon ":", this function does not append it anymore.
//! That resulted in a much shorter implementation (234628B -> 234476B)
//! There are similar functions around which may be shortened in a similar way
void menu_draw_float31(const char* str, float val)
{
lcd_printf_P(menu_fmt_float31, str, val);
lcd_printf_P(menu_fmt_float31, str, val);
}
//! @brief Draw up to 14 chars of text and a float number in format +1.234
//!
//!
//! @param str string label to print
//! @param val value to print aligned to the right side of the display
//!
//! @param val value to print aligned to the right side of the display
//!
//! Implementation comments:
//! This function uses similar optimization principles as menu_draw_float31
//! (i.e. str must include a ':' at its end)
@ -461,66 +506,53 @@ void menu_draw_float13(const char* str, float val)
lcd_printf_P(menu_fmt_float13, ' ', str, val);
}
static void _menu_edit_P()
template <typename T>
static void _menu_edit_P(void)
{
menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]);
if (lcd_draw_update)
{
// handle initial value jumping
if (_md->minJumpValue && lcd_encoder) {
if (lcd_encoder > 0 && _md->currentValue == _md->minEditValue) {
_md->currentValue = _md->minJumpValue;
lcd_encoder = 0;
}
// disable after first use and/or if the initial value is not minEditValue
_md->minJumpValue = 0;
}
_md->currentValue += lcd_encoder;
lcd_encoder = 0; // Consume knob rotation event
// Constrain the value in case it's outside the allowed limits
_md->currentValue = constrain(_md->currentValue, _md->minEditValue, _md->maxEditValue);
if (lcd_encoder < _md->minEditValue) lcd_encoder = _md->minEditValue;
if (lcd_encoder > _md->maxEditValue) lcd_encoder = _md->maxEditValue;
lcd_set_cursor(0, 1);
menu_draw_P(' ', _md->editLabel, _md->currentValue);
menu_draw_P<T>(' ', _md->editLabel, (int)lcd_encoder);
}
if (lcd_clicked())
if (LCD_CLICKED)
{
if (_md->editValueBits == 8)
*((uint8_t*)(_md->editValuePtr)) = _md->currentValue;
else
*((int16_t*)(_md->editValuePtr)) = _md->currentValue;
*((T)(_md->editValue)) = lcd_encoder;
menu_back_no_reset();
}
}
void menu_item_edit_P(const char* str, void* pval, uint8_t pbits, int16_t min_val, int16_t max_val, int16_t jmp_val)
template <typename T>
uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_val)
{
menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]);
if (menu_item == menu_line)
{
int16_t cur_val = (pbits == 8 ? *((uint8_t*)pval) : *((int16_t*)pval));
if (lcd_draw_update)
if (lcd_draw_update)
{
lcd_set_cursor(0, menu_row);
menu_draw_P(menu_selection_mark(), str, cur_val);
menu_draw_P<T>(menu_selection_mark(), str, *pval);
}
if (menu_clicked && (lcd_encoder == menu_item))
{
menu_submenu_no_reset(_menu_edit_P);
menu_submenu_no_reset(_menu_edit_P<T>);
_md->editLabel = str;
_md->editValuePtr = pval;
_md->editValueBits = pbits;
_md->currentValue = cur_val;
_md->editValue = pval;
_md->minEditValue = min_val;
_md->maxEditValue = max_val;
_md->minJumpValue = jmp_val;
menu_item_ret();
return;
lcd_encoder = *pval;
return menu_item_ret();
}
}
menu_item++;
return 0;
}
template uint8_t menu_item_edit_P<int16_t*>(const char* str, int16_t *pval, int16_t min_val, int16_t max_val);
template uint8_t menu_item_edit_P<uint8_t*>(const char* str, uint8_t *pval, int16_t min_val, int16_t max_val);
static uint8_t progressbar_block_count = 0;
static uint16_t progressbar_total = 0;
void menu_progressbar_init(uint16_t total, const char* title)
@ -528,10 +560,9 @@ void menu_progressbar_init(uint16_t total, const char* title)
lcd_clear();
progressbar_block_count = 0;
progressbar_total = total;
lcd_set_cursor(0, 1);
lcd_print_pad_P(title, LCD_WIDTH);
lcd_set_cursor(0, 2);
lcd_printf_P(PSTR("%-20.20S\n"), title);
}
void menu_progressbar_update(uint16_t newVal)
@ -541,7 +572,7 @@ void menu_progressbar_update(uint16_t newVal)
newCnt = LCD_WIDTH;
while (newCnt > progressbar_block_count)
{
lcd_print(LCD_STR_SOLID_BLOCK[0]);
lcd_print('\xFF');
progressbar_block_count++;
}
}

View File

@ -10,7 +10,7 @@
//Function pointer to menu functions.
typedef void (*menu_func_t)(void);
typedef struct
typedef struct
{
menu_func_t menu;
int8_t position;
@ -20,40 +20,35 @@ typedef struct
{
//Variables used when editing values.
const char* editLabel;
uint8_t editValueBits; // 8 or 16
void* editValuePtr;
int16_t currentValue;
int16_t minEditValue;
int16_t maxEditValue;
int16_t minJumpValue;
void* editValue;
int32_t minEditValue;
int32_t maxEditValue;
} menu_data_edit_t;
extern uint8_t menu_data[MENU_DATA_SIZE];
extern uint8_t menu_depth;
//! definition of reasons blocking the main menu
//! definition of serious errors possibly blocking the main menu
//! Use them as bit mask, so that the code may set various errors at the same time
enum ESeriousErrors {
MENU_BLOCK_NONE = 0,
MENU_BLOCK_THERMAL_ERROR = 0x01,
#ifdef THERMAL_MODEL
MENU_BLOCK_THERMAL_MODEL_AUTOTUNE = 0x02,
#endif
MENU_BLOCK_STATUS_SCREEN_M0 = 0x04,
SERIOUS_ERR_NONE = 0,
SERIOUS_ERR_MINTEMP_HEATER = 0x01,
SERIOUS_ERR_MINTEMP_BED = 0x02
}; // and possibly others in the future.
//! this is a flag for disabling entering the main menu and longpress. If this is set to anything !=
//! 0, the only the main status screen will be shown on the LCD and the user will be prevented from
//! entering the menu.
extern uint8_t menu_block_mask;
//! this is a flag for disabling entering the main menu. If this is set
//! to anything != 0, the only the main status screen will be shown on the
//! LCD and the user will be prevented from entering the menu.
//! Now used only to block doing anything with the printer when there is
//! the infamous MINTEMP error (SERIOUS_ERR_MINTEMP).
extern uint8_t menu_block_entering_on_serious_errors;
//! a pair of macros for manipulating menu entry
//! a pair of macros for manipulating the serious errors
//! a c++ class would have been better
#define menu_set_block(x) menu_block_mask |= x;
#define menu_unset_block(x) menu_block_mask &= ~x;
#define menu_is_blocked(x) (menu_block_mask & x)
#define menu_is_any_block() (menu_block_mask != MENU_BLOCK_NONE)
#define menu_set_serious_error(x) menu_block_entering_on_serious_errors |= x;
#define menu_unset_serious_error(x) menu_block_entering_on_serious_errors &= ~x;
#define menu_is_serious_error(x) (menu_block_entering_on_serious_errors & x) != 0
extern uint8_t menu_line;
extern uint8_t menu_item;
@ -61,7 +56,9 @@ extern uint8_t menu_row;
//scroll offset in the current menu
extern uint8_t menu_top;
extern uint8_t menu_clicked;
extern uint8_t menu_leaving;
//function pointer to the currently active menu
@ -69,7 +66,7 @@ extern menu_func_t menu_menu;
extern void menu_data_reset(void);
extern void menu_goto(menu_func_t menu, const int16_t encoder, bool reset_menu_state, const bool feedback=false);
extern void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bool reset_menu_state);
#define MENU_BEGIN() menu_start(); for(menu_row = 0; menu_row < LCD_HEIGHT; menu_row++, menu_line++) { menu_item = 0;
void menu_start(void);
@ -83,10 +80,12 @@ extern void menu_back(uint8_t nLevel);
extern void menu_back_if_clicked(void);
extern void menu_submenu(menu_func_t submenu, const bool feedback=false);
extern void menu_submenu_no_reset(menu_func_t submenu, const bool feedback=false);
extern void menu_back_if_clicked_fb(void);
extern void menu_item_ret(void);
extern void menu_submenu(menu_func_t submenu);
extern void menu_submenu_no_reset(menu_func_t submenu);
extern uint8_t menu_item_ret(void);
//extern int menu_draw_item_printf_P(char type_char, const char* format, ...);
@ -96,37 +95,37 @@ extern void menu_item_ret(void);
#define MENU_ITEM_DUMMY() menu_item_dummy()
extern void menu_item_dummy(void);
#define MENU_ITEM_TEXT_P(str) do { menu_item_text_P(str); } while (0)
#define MENU_ITEM_TEXT_P(str) do { if (menu_item_text_P(str)) return; } while (0)
extern uint8_t menu_item_text_P(const char* str);
#define MENU_ITEM_SUBMENU_P(str, submenu) do { menu_item_submenu_P(str, submenu); } while (0)
extern void menu_item_submenu_P(const char* str, menu_func_t submenu);
#define MENU_ITEM_SUBMENU_P(str, submenu) do { if (menu_item_submenu_P(str, submenu)) return; } while (0)
extern uint8_t menu_item_submenu_P(const char* str, menu_func_t submenu);
#define MENU_ITEM_SUBMENU_E(sheet, submenu) do { menu_item_submenu_E(sheet, submenu); } while (0)
extern void menu_item_submenu_E(const Sheet &sheet, menu_func_t submenu);
#define MENU_ITEM_SUBMENU_E(sheet, submenu) do { if (menu_item_submenu_E(sheet, submenu)) return; } while (0)
extern uint8_t menu_item_submenu_E(const Sheet &sheet, menu_func_t submenu);
#define MENU_ITEM_FUNCTION_E(sheet, submenu) do { menu_item_function_E(sheet, submenu); } while (0)
extern void menu_item_function_E(const Sheet &sheet, menu_func_t func);
#define MENU_ITEM_FUNCTION_E(sheet, submenu) do { if (menu_item_function_E(sheet, submenu)) return; } while (0)
extern uint8_t menu_item_function_E(const Sheet &sheet, menu_func_t func);
#define MENU_ITEM_BACK_P(str) do { menu_item_back_P(str); } while (0)
extern void menu_item_back_P(const char* str);
#define MENU_ITEM_BACK_P(str) do { if (menu_item_back_P(str)) return; } while (0)
extern uint8_t menu_item_back_P(const char* str);
// leaving menu - this condition must be immediately before MENU_ITEM_BACK_P
#define ON_MENU_LEAVE(func) do { if (menu_item_leave()){ func } } while (0)
extern bool menu_item_leave();
#define MENU_ITEM_FUNCTION_P(str, func) do { menu_item_function_P(str, func); } while (0)
extern void menu_item_function_P(const char* str, menu_func_t func);
#define MENU_ITEM_FUNCTION_P(str, func) do { if (menu_item_function_P(str, func)) return; } while (0)
extern uint8_t menu_item_function_P(const char* str, menu_func_t func);
#define MENU_ITEM_FUNCTION_NR_P(str, number, func, fn_par) do { menu_item_function_P(str, number, func, fn_par); } while (0)
extern void menu_item_function_P(const char* str, char number, void (*func)(uint8_t), uint8_t fn_par);
#define MENU_ITEM_FUNCTION_NR_P(str, number, func, fn_par) do { if (menu_item_function_P(str, number, func, fn_par)) return; } while (0)
extern uint8_t menu_item_function_P(const char* str, char number, void (*func)(uint8_t), uint8_t fn_par);
#define MENU_ITEM_TOGGLE_P(str, toggle, func) do { menu_item_toggle_P(str, toggle, func, 0x02); } while (0)
#define MENU_ITEM_TOGGLE(str, toggle, func) do { menu_item_toggle_P(str, toggle, func, 0x00); } while (0)
extern void menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, const uint8_t settings);
#define MENU_ITEM_TOGGLE_P(str, toggle, func) do { if (menu_item_toggle_P(str, toggle, func, 0x02)) return; } while (0)
#define MENU_ITEM_TOGGLE(str, toggle, func) do { if (menu_item_toggle_P(str, toggle, func, 0x00)) return; } while (0)
extern uint8_t menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, const uint8_t settings);
#define MENU_ITEM_GCODE_P(str, str_gcode) do { menu_item_gcode_P(str, str_gcode); } while (0)
extern void menu_item_gcode_P(const char* str, const char* str_gcode);
#define MENU_ITEM_GCODE_P(str, str_gcode) do { if (menu_item_gcode_P(str, str_gcode)) return; } while (0)
extern uint8_t menu_item_gcode_P(const char* str, const char* str_gcode);
extern const char menu_fmt_int3[];
@ -145,9 +144,11 @@ struct SheetFormatBuffer
extern void menu_format_sheet_E(const Sheet &sheet_E, SheetFormatBuffer &buffer);
#define MENU_ITEM_EDIT_int3_P(str, pval, minval, maxval) do { menu_item_edit_P(str, pval, sizeof(*pval)*8, minval, maxval, 0); } while (0)
#define MENU_ITEM_EDIT_int3_jmp_P(str, pval, minval, maxval, jmpval) do { menu_item_edit_P(str, pval, sizeof(*pval)*8, minval, maxval, jmpval); } while (0)
extern void menu_item_edit_P(const char* str, void* pval, uint8_t pbits, int16_t min_val, int16_t max_val, int16_t jmp_val);
#define MENU_ITEM_EDIT_int3_P(str, pval, minval, maxval) do { if (menu_item_edit_P(str, pval, minval, maxval)) return; } while (0)
//#define MENU_ITEM_EDIT_int3_P(str, pval, minval, maxval) MENU_ITEM_EDIT(int3, str, pval, minval, maxval)
template <typename T>
extern uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_val);
extern void menu_progressbar_init(uint16_t total, const char* title);
extern void menu_progressbar_update(uint16_t newVal);

View File

@ -1,8 +1,6 @@
#include "Configuration.h"
#include "ConfigurationStore.h"
#include "util.h"
#include "language.h"
#include "lcd.h"
#include "mesh_bed_calibration.h"
#include "mesh_bed_leveling.h"
#include "stepper.h"
@ -263,26 +261,26 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
for (uint8_t i = 0; i < npts; ++i) {
// First for the residuum in the x axis:
if (r != 1 && c != 1) {
float a =
float a =
(r == 0) ? 1.f :
((r == 2) ? (-s1 * measured_pts[2 * i]) :
(-c2 * measured_pts[2 * i + 1]));
float b =
float b =
(c == 0) ? 1.f :
((c == 2) ? (-s1 * measured_pts[2 * i]) :
(-c2 * measured_pts[2 * i + 1]));
float w = point_weight_x(i, measured_pts[2 * i + 1]);
acc += a * b * w;
}
// Second for the residuum in the y axis.
// Second for the residuum in the y axis.
// The first row of the points have a low weight, because their position may not be known
// with a sufficient accuracy.
if (r != 0 && c != 0) {
float a =
float a =
(r == 1) ? 1.f :
((r == 2) ? ( c1 * measured_pts[2 * i]) :
(-s2 * measured_pts[2 * i + 1]));
float b =
float b =
(c == 1) ? 1.f :
((c == 2) ? ( c1 * measured_pts[2 * i]) :
(-s2 * measured_pts[2 * i + 1]));
@ -296,7 +294,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
acc = 0.f;
for (uint8_t i = 0; i < npts; ++i) {
{
float j =
float j =
(r == 0) ? 1.f :
((r == 1) ? 0.f :
((r == 2) ? (-s1 * measured_pts[2 * i]) :
@ -306,7 +304,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
acc += j * fx * w;
}
{
float j =
float j =
(r == 0) ? 0.f :
((r == 1) ? 1.f :
((r == 2) ? ( c1 * measured_pts[2 * i]) :
@ -374,7 +372,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
angleDiff = fabs(a2 - a1);
/// XY skew and Y-bed skew
DBG(_n("Measured skews: %f %f\n"), degrees(a2 - a1), degrees(a2));
eeprom_update_float_notify((float *)(EEPROM_XYZ_CAL_SKEW), angleDiff); //storing xyz cal. skew to be able to show in support menu later
eeprom_update_float((float *)(EEPROM_XYZ_CAL_SKEW), angleDiff); //storing xyz cal. skew to be able to show in support menu later
if (angleDiff > bed_skew_angle_mild)
result = (angleDiff > bed_skew_angle_extreme) ?
BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME :
@ -420,9 +418,9 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
for (uint8_t i = 0; i < npts; ++i) {
float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0];
float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1] + cntr[1];
float errX = pgm_read_float(true_pts + i * 2) - x;
float errY = pgm_read_float(true_pts + i * 2 + 1) - y;
float err = hypot(errX, errY);
float errX = sqr(pgm_read_float(true_pts + i * 2) - x);
float errY = sqr(pgm_read_float(true_pts + i * 2 + 1) - y);
float err = sqrt(errX + errY);
#ifdef SUPPORT_VERBOSITY
if (verbosity_level >= 10) {
SERIAL_ECHOPGM("point #");
@ -436,15 +434,15 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
if(verbosity_level >= 20) SERIAL_ECHOPGM("Point on first row");
#endif // SUPPORT_VERBOSITY
float w = point_weight_y(i, measured_pts[2 * i + 1]);
if (errX > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X ||
(w != 0.f && errY > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) {
if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X ||
(w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) {
result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
#ifdef SUPPORT_VERBOSITY
if (verbosity_level >= 20) {
SERIAL_ECHOPGM(", weigth Y: ");
MYSERIAL.print(w);
if (errX > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X) SERIAL_ECHOPGM(", error X > max. error X");
if (w != 0.f && errY > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y) SERIAL_ECHOPGM(", error Y > max. error Y");
if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X) SERIAL_ECHOPGM(", error X > max. error X");
if (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y) SERIAL_ECHOPGM(", error Y > max. error Y");
}
#endif // SUPPORT_VERBOSITY
}
@ -456,7 +454,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN) {
result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
#ifdef SUPPORT_VERBOSITY
if(verbosity_level >= 20) SERIAL_ECHOPGM(", error > max. error euclidian");
if(verbosity_level >= 20) SERIAL_ECHOPGM(", error > max. error euclidian");
#endif // SUPPORT_VERBOSITY
}
}
@ -479,9 +477,9 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
SERIAL_ECHOPGM("error: ");
MYSERIAL.print(err);
SERIAL_ECHOPGM(", error X: ");
MYSERIAL.print(errX);
MYSERIAL.print(sqrt(errX));
SERIAL_ECHOPGM(", error Y: ");
MYSERIAL.print(errY);
MYSERIAL.print(sqrt(errY));
SERIAL_ECHOLNPGM("");
SERIAL_ECHOLNPGM("");
}
@ -500,6 +498,19 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
}
#endif // SUPPORT_VERBOSITY
#if 0
if (result == BED_SKEW_OFFSET_DETECTION_PERFECT && fabs(a1) < bed_skew_angle_mild && fabs(a2) < bed_skew_angle_mild) {
#ifdef SUPPORT_VERBOSITY
if (verbosity_level > 0)
SERIAL_ECHOLNPGM("Very little skew detected. Disabling skew correction.");
#endif // SUPPORT_VERBOSITY
// Just disable the skew correction.
vec_x[0] = MACHINE_AXIS_SCALE_X;
vec_x[1] = 0.f;
vec_y[0] = 0.f;
vec_y[1] = MACHINE_AXIS_SCALE_Y;
}
#else
if (result == BED_SKEW_OFFSET_DETECTION_PERFECT) {
#ifdef SUPPORT_VERBOSITY
if (verbosity_level > 0)
@ -571,6 +582,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
}
#endif // SUPPORT_VERBOSITY
}
#endif
// Invert the transformation matrix made of vec_x, vec_y and cntr.
{
@ -633,7 +645,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
SERIAL_ECHOPGM(", ");
MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5);
SERIAL_ECHOPGM("), error: ");
MYSERIAL.print( hypot(measured_pts[i * 2] - x, measured_pts[i * 2 + 1] - y) );
MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y)));
SERIAL_ECHOLNPGM("");
}
if (verbosity_level >= 20) {
@ -656,27 +668,27 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
*/
void reset_bed_offset_and_skew()
{
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF);
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+4), 0x0FFFFFFFF);
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +0), 0x0FFFFFFFF);
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +4), 0x0FFFFFFFF);
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +0), 0x0FFFFFFFF);
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +4), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+4), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +0), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +4), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +0), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +4), 0x0FFFFFFFF);
// Reset the 8 16bit offsets.
for (int8_t i = 0; i < 4; ++ i)
eeprom_update_dword_notify((uint32_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*4), 0x0FFFFFFFF);
eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*4), 0x0FFFFFFFF);
}
bool is_bed_z_jitter_data_valid()
// offsets of the Z heiths of the calibration points from the first point are saved as 16bit signed int, scaled to tenths of microns
// if at least one 16bit integer has different value then -1 (0x0FFFF), data are considered valid and function returns true, otherwise it returns false
{
{
bool data_valid = false;
for (int8_t i = 0; i < 8; ++i) {
if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + i * 2)) != 0x0FFFF)
return true;
if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + i * 2)) != 0x0FFFF) data_valid = true;
}
return false;
return data_valid;
}
static void world2machine_update(const float vec_x[2], const float vec_y[2], const float cntr[2])
@ -763,7 +775,7 @@ void world2machine_revert_to_uncorrected()
static inline bool vec_undef(const float v[2])
{
const uint32_t *vx = (const uint32_t*)v;
return vx[0] == 0xFFFFFFFF || vx[1] == 0xFFFFFFFF;
return vx[0] == 0x0FFFFFFFF || vx[1] == 0x0FFFFFFFF;
}
@ -780,9 +792,12 @@ static inline bool vec_undef(const float v[2])
*/
void world2machine_read_valid(float vec_x[2], float vec_y[2], float cntr[2])
{
eeprom_read_block(&vec_x[0], (float*)(EEPROM_BED_CALIBRATION_VEC_X), 8);
eeprom_read_block(&vec_y[0], (float*)(EEPROM_BED_CALIBRATION_VEC_Y), 8);
eeprom_read_block(&cntr[0], (float*)(EEPROM_BED_CALIBRATION_CENTER), 8);
vec_x[0] = eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0));
vec_x[1] = eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4));
vec_y[0] = eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0));
vec_y[1] = eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4));
cntr[0] = eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0));
cntr[1] = eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4));
bool reset = false;
if (vec_undef(cntr) || vec_undef(vec_x) || vec_undef(vec_y))
@ -795,7 +810,7 @@ void world2machine_read_valid(float vec_x[2], float vec_y[2], float cntr[2])
else
{
// Length of the vec_x shall be close to unity.
float l = hypot(vec_x[0], vec_x[1]);
float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
if (l < 0.9 || l > 1.1)
{
#if 0
@ -806,7 +821,7 @@ void world2machine_read_valid(float vec_x[2], float vec_y[2], float cntr[2])
reset = true;
}
// Length of the vec_y shall be close to unity.
l = hypot(vec_y[0], vec_y[1]);
l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
if (l < 0.9 || l > 1.1)
{
#if 0
@ -817,7 +832,7 @@ void world2machine_read_valid(float vec_x[2], float vec_y[2], float cntr[2])
reset = true;
}
// Correction of the zero point shall be reasonably small.
l = hypot(cntr[0], cntr[1]);
l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
if (l > 15.f)
{
#if 0
@ -896,13 +911,13 @@ void world2machine_update_current()
static inline void go_xyz(float x, float y, float z, float fr)
{
plan_buffer_line(x, y, z, current_position[E_AXIS], fr);
plan_buffer_line(x, y, z, current_position[E_AXIS], fr, active_extruder);
st_synchronize();
}
static inline void go_xy(float x, float y, float fr)
{
plan_buffer_line(x, y, current_position[Z_AXIS], current_position[E_AXIS], fr);
plan_buffer_line(x, y, current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder);
st_synchronize();
}
@ -934,15 +949,10 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
#endif //SUPPORT_VERBOSITY
)
{
bool high_deviation_occured = false;
bool high_deviation_occured = false;
bedPWMDisabled = 1;
#ifdef TMC2130
bool bHighPowerForced = false;
if (tmc2130_mode == TMC2130_MODE_SILENT)
{
FORCE_HIGH_POWER_START;
bHighPowerForced = true;
}
FORCE_HIGH_POWER_START;
#endif
//printf_P(PSTR("Min. Z: %f\n"), minimum_z);
#ifdef SUPPORT_VERBOSITY
@ -964,7 +974,7 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
goto error;
}
#ifdef TMC2130
if (!READ(Z_TMC2130_DIAG))
if (READ(Z_TMC2130_DIAG) != 0)
{
//printf_P(PSTR("crash detected 1, current_pos[Z]: %f \n"), current_position[Z_AXIS]);
goto error; //crash Z detected
@ -972,7 +982,7 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
#endif //TMC2130
for (uint8_t i = 0; i < n_iter; ++ i)
{
current_position[Z_AXIS] += high_deviation_occured ? 0.5 : 0.2;
float z_bckp = current_position[Z_AXIS];
go_to_current(homing_feedrate[Z_AXIS]/60);
@ -983,9 +993,10 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
// we have to let the planner know where we are right now as it is not where we said to go.
update_current_position_z();
//printf_P(PSTR("Zs: %f, Z: %f, delta Z: %f"), z_bckp, current_position[Z_AXIS], (z_bckp - current_position[Z_AXIS]));
if (fabs(current_position[Z_AXIS] - z_bckp) < 0.025) {
//printf_P(PSTR("PINDA triggered immediately, move Z higher and repeat measurement\n"));
raise_z(0.5);
if (abs(current_position[Z_AXIS] - z_bckp) < 0.025) {
//printf_P(PSTR("PINDA triggered immediately, move Z higher and repeat measurement\n"));
current_position[Z_AXIS] += 0.5;
go_to_current(homing_feedrate[Z_AXIS]/60);
current_position[Z_AXIS] = minimum_z;
go_to_current(homing_feedrate[Z_AXIS]/(4*60));
// we have to let the planner know where we are right now as it is not where we said to go.
@ -1000,7 +1011,7 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
goto error;
}
#ifdef TMC2130
if (!READ(Z_TMC2130_DIAG)) {
if (READ(Z_TMC2130_DIAG) != 0) {
//printf_P(PSTR("crash detected 2, current_pos[Z]: %f \n"), current_position[Z_AXIS]);
goto error; //crash Z detected
}
@ -1008,17 +1019,17 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
// SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: ");
// MYSERIAL.print(current_position[Z_AXIS], 5);
// SERIAL_ECHOLNPGM("");
float dz = i?fabs(current_position[Z_AXIS] - (z / i)):0;
float dz = i?abs(current_position[Z_AXIS] - (z / i)):0;
z += current_position[Z_AXIS];
//printf_P(PSTR("Z[%d] = %d, dz=%d\n"), i, (int)(current_position[Z_AXIS] * 1000), (int)(dz * 1000));
//printf_P(PSTR("Z- measurement deviation from avg value %f um\n"), dz);
if (dz > 0.05) { //deviation > 50um
if (high_deviation_occured == false) { //first occurence may be caused in some cases by mechanic resonance probably especially if printer is placed on unstable surface
if (high_deviation_occured == false) { //first occurence may be caused in some cases by mechanic resonance probably especially if printer is placed on unstable surface
//printf_P(PSTR("high dev. first occurence\n"));
delay_keep_alive(500); //damping
//start measurement from the begining, but this time with higher movements in Z axis which should help to reduce mechanical resonance
high_deviation_occured = true;
i = -1;
i = -1;
z = 0;
}
else {
@ -1036,7 +1047,7 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
enable_z_endstop(endstop_z_enabled);
// SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 3");
#ifdef TMC2130
if (bHighPowerForced) FORCE_HIGH_POWER_END;
FORCE_HIGH_POWER_END;
#endif
bedPWMDisabled = 0;
return true;
@ -1046,7 +1057,7 @@ error:
enable_endstops(endstops_enabled);
enable_z_endstop(endstop_z_enabled);
#ifdef TMC2130
if (bHighPowerForced) FORCE_HIGH_POWER_END;
FORCE_HIGH_POWER_END;
#endif
bedPWMDisabled = 0;
return false;
@ -1186,6 +1197,8 @@ BedSkewOffsetDetectionResultType find_bed_induction_sensor_point_xy(int
MYSERIAL.println(current_position[Z_AXIS]);
}
#endif //SUPPORT_VERBOSITY
//lcd_show_fullscreen_message_and_wait_P(PSTR("First hit"));
//lcd_update_enable(true);
float init_x_position = current_position[X_AXIS];
float init_y_position = current_position[Y_AXIS];
@ -1193,7 +1206,7 @@ BedSkewOffsetDetectionResultType find_bed_induction_sensor_point_xy(int
// we have to let the planner know where we are right now as it is not where we said to go.
update_current_position_xyz();
enable_z_endstop(false);
for (int8_t iter = 0; iter < 2; ++iter) {
/*SERIAL_ECHOPGM("iter: ");
MYSERIAL.println(iter);
@ -1212,7 +1225,7 @@ BedSkewOffsetDetectionResultType find_bed_induction_sensor_point_xy(int
invert_z_endstop(true);
for (int iteration = 0; iteration < 8; iteration++) {
found = false;
found = false;
enable_z_endstop(true);
go_xy(init_x_position + 16.0f, current_position[Y_AXIS], feedrate / 5);
update_current_position_xyz();
@ -1238,7 +1251,7 @@ BedSkewOffsetDetectionResultType find_bed_induction_sensor_point_xy(int
current_position[X_AXIS] = 0.5f * (a + b);
go_xy(current_position[X_AXIS], init_y_position, feedrate / 5);
found = true;
// Search in the Y direction along a cross.
found = false;
enable_z_endstop(true);
@ -1314,7 +1327,7 @@ BedSkewOffsetDetectionResultType find_bed_induction_sensor_point_xy(int
break;
}
}
enable_z_endstop(false);
invert_z_endstop(false);
return found;
@ -1566,7 +1579,7 @@ inline bool improve_bed_induction_sensor_point()
// Trim the vector from center_old_[x,y] to destination[x,y] by the bed dimensions.
float vx = destination[X_AXIS] - center_old_x;
float vy = destination[Y_AXIS] - center_old_y;
float l = hypot(vx, vy);
float l = sqrt(vx*vx+vy*vy);
float t;
if (destination[X_AXIS] < X_MIN_POS) {
// Exiting the bed at xmin.
@ -1802,7 +1815,7 @@ canceled:
#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (8.f)
#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f)
inline bool improve_bed_induction_sensor_point3(int verbosity_level)
{
{
float center_old_x = current_position[X_AXIS];
float center_old_y = current_position[Y_AXIS];
float a, b;
@ -2166,18 +2179,8 @@ inline void scan_bed_induction_sensor_point()
#define MESH_BED_CALIBRATION_SHOW_LCD
float __attribute__((noinline)) BED_X(const uint8_t col)
{
return ((float)col * x_mesh_density + BED_X0);
}
float __attribute__((noinline)) BED_Y(const uint8_t row)
{
return ((float)row * y_mesh_density + BED_Y0);
}
BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask)
{
{
// Don't let the manage_inactivity() function remove power from the motors.
refresh_cmd_timeout();
@ -2188,13 +2191,13 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
float *vec_y = vec_x + 2;
float *cntr = vec_y + 2;
memset(pts, 0, sizeof(float) * 7 * 7);
uint8_t iteration = 0;
uint8_t iteration = 0;
BedSkewOffsetDetectionResultType result;
// SERIAL_ECHOLNPGM("find_bed_offset_and_skew verbosity level: ");
// SERIAL_ECHO(int(verbosity_level));
// SERIAL_ECHOPGM("");
#ifdef NEW_XYZCAL
{
#else //NEW_XYZCAL
@ -2206,7 +2209,7 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
#ifdef SUPPORT_VERBOSITY
if (verbosity_level >= 20) {
SERIAL_ECHOLNPGM("Vectors: ");
SERIAL_ECHOPGM("vec_x[0]:");
MYSERIAL.print(vec_x[0], 5);
SERIAL_ECHOLNPGM("");
@ -2237,7 +2240,7 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
/// Retry point scanning if a point with bad data appears.
/// Bad data could be cause by "cold" sensor.
/// This behavior vanishes after few point scans so retry will help.
for (uint8_t retries = 0; retries <= 1; ++retries) {
for (int retries = 0; retries <= 1; ++retries) {
bool retry = false;
for (int k = 0; k < 4; ++k) {
// Don't let the manage_inactivity() function remove power from the motors.
@ -2275,7 +2278,7 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
else {
// if first iteration failed, count corrected point coordinates as initial
// Use the corrected coordinate, which is a result of find_bed_offset_and_skew().
current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[0] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[0];
current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[1];
@ -2318,7 +2321,7 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
#ifndef NEW_XYZCAL
#ifndef HEATBED_V2
if (k == 0 || k == 1) {
// Improve the position of the 1st row sensor points by a zig-zag movement.
find_bed_induction_sensor_point_z();
@ -2357,11 +2360,11 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
pt[0] += (current_position[X_AXIS]/(iteration + 1)); //count average
pt[1] = (pt[1] * iteration) / (iteration + 1);
pt[1] += (current_position[Y_AXIS] / (iteration + 1));
//pt[0] += current_position[X_AXIS];
//if(iteration > 0) pt[0] = pt[0] / 2;
//pt[1] += current_position[Y_AXIS];
//if (iteration > 0) pt[1] = pt[1] / 2;
@ -2395,7 +2398,7 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
}
DBG(_n("All 4 calibration points found.\n"));
delay_keep_alive(0); //manage_heater, reset watchdog, manage inactivity
#ifdef SUPPORT_VERBOSITY
if (verbosity_level >= 20) {
// Test the positions. Are the positions reproducible? Now the calibration is active in the planner.
@ -2422,29 +2425,32 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
}
result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level);
delay_keep_alive(0); //manage_heater, reset watchdog, manage inactivity
if (result >= 0) {
DBG(_n("Calibration success.\n"));
world2machine_update(vec_x, vec_y, cntr);
#if 1
// Fearlessly store the calibration values into the eeprom.
eeprom_update_block_notify(&cntr[0], (float*)(EEPROM_BED_CALIBRATION_CENTER), 8);
eeprom_update_block_notify(&vec_x[0], (float*)(EEPROM_BED_CALIBRATION_VEC_X), 8);
eeprom_update_block_notify(&vec_y[0], (float*)(EEPROM_BED_CALIBRATION_VEC_Y), 8);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0), cntr[0]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4), cntr[1]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0), vec_x[0]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4), vec_x[1]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0), vec_y[0]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4), vec_y[1]);
#endif
#ifdef SUPPORT_VERBOSITY
if (verbosity_level >= 10) {
// Length of the vec_x
float l = hypot(vec_x[0], vec_x[1]);
float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
SERIAL_ECHOLNPGM("X vector length:");
MYSERIAL.println(l);
// Length of the vec_y
l = hypot(vec_y[0], vec_y[1]);
l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
SERIAL_ECHOLNPGM("Y vector length:");
MYSERIAL.println(l);
// Zero point correction
l = hypot(cntr[0], cntr[1]);
l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
SERIAL_ECHOLNPGM("Zero point correction:");
MYSERIAL.println(l);
@ -2470,8 +2476,8 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix;
current_position[X_AXIS] = BED_X(ix * 3);
current_position[Y_AXIS] = BED_Y(iy * 3);
current_position[X_AXIS] = BED_X(ix, MESH_MEAS_NUM_X_POINTS);
current_position[Y_AXIS] = BED_Y(iy, MESH_MEAS_NUM_Y_POINTS);
go_to_current(homing_feedrate[X_AXIS] / 60);
delay_keep_alive(3000);
}
@ -2485,7 +2491,7 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
}
iteration++;
}
return result;
return result;
}
#ifndef NEW_XYZCAL
@ -2522,7 +2528,7 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8
bool endstop_z_enabled = enable_z_endstop(false);
#ifdef MESH_BED_CALIBRATION_SHOW_LCD
lcd_display_message_fullscreen_P(_T(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1));
lcd_display_message_fullscreen_P(_i("Improving bed calibration point"));////MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1 c=60
#endif /* MESH_BED_CALIBRATION_SHOW_LCD */
// Collect a matrix of 9x9 points.
@ -2714,11 +2720,15 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8
}
world2machine_update(vec_x, vec_y, cntr);
#if 1
// Fearlessly store the calibration values into the eeprom.
eeprom_update_block_notify(&cntr[0], (float*)(EEPROM_BED_CALIBRATION_CENTER), 8);
eeprom_update_block_notify(&vec_x[0], (float*)(EEPROM_BED_CALIBRATION_VEC_X), 8);
eeprom_update_block_notify(&vec_y[0], (float*)(EEPROM_BED_CALIBRATION_VEC_Y), 8);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]);
eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]);
#endif
// Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set.
world2machine_update_current();
@ -2780,22 +2790,19 @@ canceled:
#endif //NEW_XYZCAL
bool sample_z() {
bool sampled = true;
// make some space for the sheet
// Avoid calling raise_z(), because a false triggering stallguard may prevent the Z from moving.
// The extruder then may ram the sheet hard if not going down from some ~150mm height
current_position[Z_AXIS] = 0.F;
destination[Z_AXIS] = 150.F;
plan_buffer_line_destinationXYZE(homing_feedrate[Z_AXIS] / 60);
bool sampled = true;
//make space
current_position[Z_AXIS] += 150;
go_to_current(homing_feedrate[Z_AXIS] / 60);
//plan_buffer_line_curposXYZE(feedrate, active_extruder););
lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET));
lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET));
// Sample Z heights for the mesh bed leveling.
// In addition, store the results into an eeprom, to be used later for verification of the bed leveling process.
if (!sample_mesh_and_store_reference())
sampled = false;
// Sample Z heights for the mesh bed leveling.
// In addition, store the results into an eeprom, to be used later for verification of the bed leveling process.
if (!sample_mesh_and_store_reference()) sampled = false;
return sampled;
return sampled;
}
void go_home_with_z_lift()
@ -2805,16 +2812,16 @@ void go_home_with_z_lift()
// Go home.
// First move up to a safe height.
current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
go_to_current(homing_feedrate[Z_AXIS] / 60);
go_to_current(homing_feedrate[Z_AXIS]/60);
// Second move to XY [0, 0].
current_position[X_AXIS] = X_MIN_POS + 0.2;
current_position[Y_AXIS] = Y_MIN_POS + 0.2;
current_position[X_AXIS] = X_MIN_POS+0.2;
current_position[Y_AXIS] = Y_MIN_POS+0.2;
// Clamp to the physical coordinates.
world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
go_to_current((3 * homing_feedrate[X_AXIS]) / 60);
go_to_current(homing_feedrate[X_AXIS]/20);
// Third move up to a safe height.
current_position[Z_AXIS] = Z_MIN_POS;
go_to_current(homing_feedrate[Z_AXIS] / 60);
go_to_current(homing_feedrate[Z_AXIS]/60);
}
// Sample the 9 points of the bed and store them into the EEPROM as a reference.
@ -2823,10 +2830,6 @@ void go_home_with_z_lift()
// Returns false if the reference values are more than 3mm far away.
bool sample_mesh_and_store_reference()
{
bool result = false;
#ifdef TMC2130
tmc2130_home_enter(Z_AXIS_MASK);
#endif
bool endstops_enabled = enable_endstops(false);
bool endstop_z_enabled = enable_z_endstop(false);
@ -2842,40 +2845,44 @@ bool sample_mesh_and_store_reference()
// Sample Z heights for the mesh bed leveling.
// In addition, store the results into an eeprom, to be used later for verification of the bed leveling process.
{
// Lower Z to the mesh search height with stall detection
enable_endstops(true);
// The first point defines the reference.
current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
go_to_current(homing_feedrate[Z_AXIS]/60);
#ifdef TMC2130
check_Z_crash();
#endif
enable_endstops(false);
// Move XY to first point
current_position[X_AXIS] = BED_X0;
current_position[Y_AXIS] = BED_Y0;
world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
go_to_current(homing_feedrate[X_AXIS]/60);
set_destination_to_current();
memcpy(destination, current_position, sizeof(destination));
enable_endstops(true);
homeaxis(Z_AXIS);
#ifdef TMC2130
if (!axis_known_position[Z_AXIS] && (READ(Z_TMC2130_DIAG) != 0)) //Z crash
{
kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW));
return false;
}
#endif //TMC2130
enable_endstops(false);
if (!find_bed_induction_sensor_point_z()) //Z crash or deviation > 50um
{
kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW));
return false;
}
mbl.set_z(0, 0, current_position[Z_AXIS]);
}
static_assert(MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS <= 255, "overflow.....");
for (uint8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) {
for (int8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) {
// Don't let the manage_inactivity() function remove power from the motors.
refresh_cmd_timeout();
// Print the decrasing ID of the measurement point.
current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
go_to_current(homing_feedrate[Z_AXIS]/60);
uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS;
uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
int8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS;
int8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag
current_position[X_AXIS] = BED_X(ix * 3);
current_position[Y_AXIS] = BED_Y(iy * 3);
current_position[X_AXIS] = BED_X(ix, MESH_MEAS_NUM_X_POINTS);
current_position[Y_AXIS] = BED_Y(iy, MESH_MEAS_NUM_Y_POINTS);
world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
go_to_current(homing_feedrate[X_AXIS]/60);
#ifdef MESH_BED_CALIBRATION_SHOW_LCD
@ -2886,9 +2893,10 @@ bool sample_mesh_and_store_reference()
if (!find_bed_induction_sensor_point_z()) //Z crash or deviation > 50um
{
kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW));
return false;
}
// Get cords of measuring point
mbl.set_z(ix, iy, current_position[Z_AXIS]);
}
{
@ -2904,7 +2912,7 @@ bool sample_mesh_and_store_reference()
// The span of the Z offsets is extreme. Give up.
// Homing failed on some of the points.
SERIAL_PROTOCOLLNPGM("Exreme span of the Z values!");
goto end;
return false;
}
}
@ -2919,7 +2927,7 @@ bool sample_mesh_and_store_reference()
continue;
float dif = mbl.z_values[j][i] - mbl.z_values[0][0];
int16_t dif_quantized = int16_t(floor(dif * 100.f + 0.5f));
eeprom_update_word_notify((uint16_t*)addr, *reinterpret_cast<uint16_t*>(&dif_quantized));
eeprom_update_word((uint16_t*)addr, *reinterpret_cast<uint16_t*>(&dif_quantized));
#if 0
{
uint16_t z_offset_u = eeprom_read_word((uint16_t*)addr);
@ -2940,18 +2948,14 @@ bool sample_mesh_and_store_reference()
}
}
mbl.reset();
mbl.upsample_3x3();
mbl.active = true;
go_home_with_z_lift();
result = true;
end:
enable_endstops(endstops_enabled);
enable_z_endstop(endstop_z_enabled);
#ifdef TMC2130
tmc2130_home_exit();
#endif
return result;
return true;
}
#ifndef NEW_XYZCAL
@ -2997,8 +3001,8 @@ bool scan_bed_induction_points(int8_t verbosity_level)
uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS;
if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix;
float bedX = BED_X(ix * 3);
float bedY = BED_Y(iy * 3);
float bedX = BED_X(ix, MESH_MEAS_NUM_X_POINTS);
float bedY = BED_Y(iy, MESH_MEAS_NUM_Y_POINTS);
current_position[X_AXIS] = vec_x[0] * bedX + vec_y[0] * bedY + cntr[0];
current_position[Y_AXIS] = vec_x[1] * bedX + vec_y[1] * bedY + cntr[1];
// The calibration points are very close to the min Y.
@ -3027,12 +3031,9 @@ bool scan_bed_induction_points(int8_t verbosity_level)
// To replace loading of the babystep correction.
static void shift_z(float delta)
{
const float curpos_z = current_position[Z_AXIS];
current_position[Z_AXIS] -= delta;
plan_buffer_line_curposXYZE(homing_feedrate[Z_AXIS] / 60);
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - delta, current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder);
st_synchronize();
current_position[Z_AXIS] = curpos_z;
plan_set_z_position(curpos_z);
plan_set_z_position(current_position[Z_AXIS]);
}
// Number of baby steps applied
@ -3042,21 +3043,21 @@ void babystep_load()
{
babystepLoadZ = 0;
// Apply Z height correction aka baby stepping before mesh bed leveling gets activated.
if (calibration_status_get(CALIBRATION_STATUS_LIVE_ADJUST))
if (calibration_status() < CALIBRATION_STATUS_LIVE_ADJUST)
{
check_babystep(); //checking if babystep is in allowed range, otherwise setting babystep to 0
// End of G80: Apply the baby stepping value.
babystepLoadZ = eeprom_read_word(reinterpret_cast<uint16_t *>(&(EEPROM_Sheets_base->
s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].z_offset)));
#if 0
SERIAL_ECHO("Z baby step: ");
SERIAL_ECHO(babystepLoadZ);
SERIAL_ECHO(", current Z: ");
SERIAL_ECHO(current_position[Z_AXIS]);
SERIAL_ECHO("correction: ");
SERIAL_ECHO(float(babystepLoadZ) / float(axis_steps_per_mm[Z_AXIS]));
SERIAL_ECHO(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS]));
SERIAL_ECHOLN("");
#endif
}
@ -3065,52 +3066,90 @@ void babystep_load()
void babystep_apply()
{
babystep_load();
shift_z(- float(babystepLoadZ) / float(cs.axis_steps_per_mm[Z_AXIS]));
shift_z(- float(babystepLoadZ) / float(cs.axis_steps_per_unit[Z_AXIS]));
}
void babystep_undo()
{
shift_z(float(babystepLoadZ) / float(cs.axis_steps_per_mm[Z_AXIS]));
shift_z(float(babystepLoadZ) / float(cs.axis_steps_per_unit[Z_AXIS]));
babystepLoadZ = 0;
}
void babystep_reset()
{
babystepLoadZ = 0;
babystepLoadZ = 0;
}
void count_xyz_details(float (&distanceMin)[2]) {
float cntr[2];
float vec_x[2];
float vec_y[2];
eeprom_read_block(&cntr[0], (float*)(EEPROM_BED_CALIBRATION_CENTER), 8);
eeprom_read_block(&vec_x[0], (float*)(EEPROM_BED_CALIBRATION_VEC_X), 8);
eeprom_read_block(&vec_y[0], (float*)(EEPROM_BED_CALIBRATION_VEC_Y), 8);
float cntr[2] = {
eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0)),
eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4))
};
float vec_x[2] = {
eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0)),
eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4))
};
float vec_y[2] = {
eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0)),
eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4))
};
#if 0
a2 = -1 * asin(vec_y[0] / MACHINE_AXIS_SCALE_Y);
a1 = asin(vec_x[1] / MACHINE_AXIS_SCALE_X);
angleDiff = fabs(a2 - a1);
#endif
for (uint8_t mesh_point = 0; mesh_point < 2; ++mesh_point) {
float y = vec_x[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2 + 1) + cntr[1];
distanceMin[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH);
}
}
/*
e_MBL_TYPE e_mbl_type = e_MBL_OPTIMAL;
void mbl_mode_set() {
switch (e_mbl_type) {
case e_MBL_OPTIMAL: e_mbl_type = e_MBL_PREC; break;
case e_MBL_PREC: e_mbl_type = e_MBL_FAST; break;
case e_MBL_FAST: e_mbl_type = e_MBL_OPTIMAL; break;
default: e_mbl_type = e_MBL_OPTIMAL; break;
}
eeprom_update_byte((uint8_t*)EEPROM_MBL_TYPE,(uint8_t)e_mbl_type);
}
void mbl_mode_init() {
uint8_t mbl_type = eeprom_read_byte((uint8_t*)EEPROM_MBL_TYPE);
if (mbl_type == 0xFF) e_mbl_type = e_MBL_OPTIMAL;
else e_mbl_type = mbl_type;
}
*/
void mbl_settings_init() {
//3x3 mesh; 3 Z-probes on each point, magnet elimination on
//magnet elimination: use aaproximate Z-coordinate instead of measured values for points which are near magnets
eeprom_init_default_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION, 1);
eeprom_init_default_byte((uint8_t*)EEPROM_MBL_POINTS_NR, 3);
eeprom_init_default_byte((uint8_t*)EEPROM_MBL_PROBE_NR, 3);
if (eeprom_read_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION) == 0xFF) {
eeprom_update_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION, 1);
}
if (eeprom_read_byte((uint8_t*)EEPROM_MBL_POINTS_NR) == 0xFF) {
eeprom_update_byte((uint8_t*)EEPROM_MBL_POINTS_NR, 3);
}
mbl_z_probe_nr = eeprom_read_byte((uint8_t*)EEPROM_MBL_PROBE_NR);
if (mbl_z_probe_nr == 0xFF) {
mbl_z_probe_nr = 3;
eeprom_update_byte((uint8_t*)EEPROM_MBL_PROBE_NR, mbl_z_probe_nr);
}
}
//parameter ix: index of mesh bed leveling point in X-axis (for meas_points == 7 is valid range from 0 to 6; for meas_points == 3 is valid range from 0 to 2 )
//parameter iy: index of mesh bed leveling point in Y-axis (for meas_points == 7 is valid range from 0 to 6; for meas_points == 3 is valid range from 0 to 2 )
//parameter ix: index of mesh bed leveling point in X-axis (for meas_points == 7 is valid range from 0 to 6; for meas_points == 3 is valid range from 0 to 2 )
//parameter iy: index of mesh bed leveling point in Y-axis (for meas_points == 7 is valid range from 0 to 6; for meas_points == 3 is valid range from 0 to 2 )
//parameter meas_points: number of mesh bed leveling points in one axis; currently designed and tested for values 3 and 7
//parameter zigzag: false if ix is considered 0 on left side of bed and ix rises with rising X coordinate; true if ix is considered 0 on the right side of heatbed for odd iy values (zig zag mesh bed leveling movements)
//function returns true if point is considered valid (typicaly in safe distance from magnet or another object which inflences PINDA measurements)
bool mbl_point_measurement_valid(uint8_t ix, uint8_t iy) {
bool mbl_point_measurement_valid(uint8_t ix, uint8_t iy, uint8_t meas_points, bool zigzag) {
//"human readable" heatbed plan
//magnet proximity influence Z coordinate measurements significantly (40 - 100 um)
//0 - measurement point is above magnet and Z coordinate can be influenced negatively
//1 - we should be in safe distance from magnets, measurement should be accurate
if ((ix >= MESH_NUM_X_POINTS) || (iy >= MESH_NUM_Y_POINTS))
return false;
if ((ix >= meas_points) || (iy >= meas_points)) return false;
uint8_t valid_points_mask[7] = {
//[X_MAX,Y_MAX]
@ -3124,26 +3163,36 @@ bool mbl_point_measurement_valid(uint8_t ix, uint8_t iy) {
0b1111111,//0
//[0,0]
};
return (valid_points_mask[6 - iy] & (1 << (6 - ix)));
if (meas_points == 3) {
ix *= 3;
iy *= 3;
}
if (zigzag) {
if ((iy % 2) == 0) return (valid_points_mask[6 - iy] & (1 << (6 - ix)));
else return (valid_points_mask[6 - iy] & (1 << ix));
}
else {
return (valid_points_mask[6 - iy] & (1 << (6 - ix)));
}
}
void mbl_single_point_interpolation(uint8_t x, uint8_t y) {
void mbl_single_point_interpolation(uint8_t x, uint8_t y, uint8_t meas_points) {
//printf_P(PSTR("x = %d; y = %d \n"), x, y);
uint8_t count = 0;
float z = 0;
if (mbl_point_measurement_valid(x, y + 1)) { z += mbl.z_values[y + 1][x]; /*printf_P(PSTR("x; y+1: Z = %f \n"), mbl.z_values[y + 1][x]);*/ count++; }
if (mbl_point_measurement_valid(x, y - 1)) { z += mbl.z_values[y - 1][x]; /*printf_P(PSTR("x; y-1: Z = %f \n"), mbl.z_values[y - 1][x]);*/ count++; }
if (mbl_point_measurement_valid(x + 1, y)) { z += mbl.z_values[y][x + 1]; /*printf_P(PSTR("x+1; y: Z = %f \n"), mbl.z_values[y][x + 1]);*/ count++; }
if (mbl_point_measurement_valid(x - 1, y)) { z += mbl.z_values[y][x - 1]; /*printf_P(PSTR("x-1; y: Z = %f \n"), mbl.z_values[y][x - 1]);*/ count++; }
if (mbl_point_measurement_valid(x, y + 1, meas_points, false)) { z += mbl.z_values[y + 1][x]; /*printf_P(PSTR("x; y+1: Z = %f \n"), mbl.z_values[y + 1][x]);*/ count++; }
if (mbl_point_measurement_valid(x, y - 1, meas_points, false)) { z += mbl.z_values[y - 1][x]; /*printf_P(PSTR("x; y-1: Z = %f \n"), mbl.z_values[y - 1][x]);*/ count++; }
if (mbl_point_measurement_valid(x + 1, y, meas_points, false)) { z += mbl.z_values[y][x + 1]; /*printf_P(PSTR("x+1; y: Z = %f \n"), mbl.z_values[y][x + 1]);*/ count++; }
if (mbl_point_measurement_valid(x - 1, y, meas_points, false)) { z += mbl.z_values[y][x - 1]; /*printf_P(PSTR("x-1; y: Z = %f \n"), mbl.z_values[y][x - 1]);*/ count++; }
if(count != 0) mbl.z_values[y][x] = z / count; //if we have at least one valid point in surrounding area use average value, otherwise use inaccurately measured Z-coordinate
//printf_P(PSTR("result: Z = %f \n\n"), mbl.z_values[y][x]);
}
void mbl_magnet_elimination() {
for (uint8_t y = 0; y < MESH_NUM_Y_POINTS; y++) {
for (uint8_t x = 0; x < MESH_NUM_X_POINTS; x++) {
if (!mbl_point_measurement_valid(x, y)) {
mbl_single_point_interpolation(x, y);
void mbl_interpolation(uint8_t meas_points) {
for (uint8_t x = 0; x < meas_points; x++) {
for (uint8_t y = 0; y < meas_points; y++) {
if (!mbl_point_measurement_valid(x, y, meas_points, false)) {
mbl_single_point_interpolation(x, y, meas_points);
}
}
}

Some files were not shown because too many files have changed in this diff Show More