├── .clang-format
├── .github
└── workflows
│ ├── buildFluidDial.yml
│ └── buildRelease.yml
├── .gitignore
├── LICENSE
├── README.md
├── assets
├── ATTRIBUTION
├── FilesBG.svg
├── JogBG.svg
├── PCBackground.svg
├── Run.svg
└── jogbg.xcf
├── build_merged.py
├── data
├── PCBackground.png
├── abouttp.png
├── disabled_button.png
├── filesbg.png
├── filestp.png
├── fluid_dial.png
├── green_button.png
├── hometp.png
├── jogbg.png
├── jogtp.png
├── macrostp.png
├── orange_button.png
├── powertp.png
├── probetp.png
├── red_button.png
├── statustp.png
└── toolchangetp.png
├── git-version.py
├── include
└── README
├── manifest.py
├── part_files
├── CYD_Dial_Bottom.stl
├── CYD_Dial_JC2432W328C.FCStd
├── CYD_Dial_JC2432W328C_bottom.3mf
├── CYD_Dial_JC2432W328C_top.3mf
├── CYD_Dial_Top.stl
├── FluidDialBottom.step
├── FluidDialLabel.pdf
└── FluidDialTop.step
├── platformio.ini
├── src
├── AboutScene.cpp
├── AboutScene.h
├── Config.h
├── ConfigItem.cpp
├── ConfigItem.h
├── ConfirmScene.cpp
├── ConfirmScene.h
├── Drawing.cpp
├── Drawing.h
├── Encoder.cpp
├── Encoder.h
├── FileLinesParser.h
├── FileListParser,h
├── FileListParser2.h
├── FileMenu.cpp
├── FileMenu.h
├── FileParser.cpp
├── FileParser.h
├── FileParser2.cpp
├── FileParser2.h
├── FilePreviewScene.cpp
├── FileSelectScene.cpp
├── FilesLinesParser.cx
├── FluidNCModel.cpp
├── FluidNCModel.h
├── Hardware2432.cpp
├── Hardware2432.hpp
├── HardwareM5Dial.cpp
├── HardwareM5Dial.hpp
├── HelpScene.cpp
├── HomingScene.cpp
├── HomingScene.h
├── LGFX_SDL.hppx
├── MacroItem.h
├── MacroMenu.cpp
├── MacroMenu.cppxx
├── Menu.cpp
├── Menu.h
├── MenuScene.cpp
├── MultiJogScene.cpp
├── NVS.h
├── PieMenu.cpp
├── PieMenu.h
├── Point.cpp
├── Point.h
├── ProbingScene.cpp
├── Scene.cpp
├── Scene.h
├── StatusScene.cpp
├── System.cpp
├── System.h
├── SystemArduino.cpp
├── SystemWindows.cpp
├── Text.cpp
├── Text.h
├── ToolChangeScene.cpp
├── Touch_Class.cpp
├── Touch_Class.hpp
├── ardmain.cpp
├── polar.c
├── polar.h
└── sdlmain.c
└── test
├── M5_test.yaml
└── README
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | AccessModifierOffset: '-4'
3 | AlignAfterOpenBracket: Align
4 | AlignConsecutiveAssignments: 'true'
5 | AlignConsecutiveDeclarations: 'true'
6 | AlignEscapedNewlines: Right
7 | AlignOperands: 'true'
8 | AlignTrailingComments: 'true'
9 | AllowShortBlocksOnASingleLine: 'true'
10 | AllowShortCaseLabelsOnASingleLine: 'false'
11 | AllowShortFunctionsOnASingleLine: Inline
12 | AllowShortIfStatementsOnASingleLine: 'false'
13 | AllowShortLoopsOnASingleLine: 'false'
14 | AlwaysBreakBeforeMultilineStrings: 'false'
15 | AlwaysBreakTemplateDeclarations: 'true'
16 | BinPackArguments: 'false'
17 | BinPackParameters: 'false'
18 | BreakBeforeBinaryOperators: None
19 | BraceWrapping:
20 | AfterClass: 'true'
21 | AfterControlStatement: 'true'
22 | AfterEnum: 'true'
23 | AfterFunction: 'true'
24 | AfterNamespace: 'true'
25 | AfterObjCDeclaration: 'true'
26 | AfterStruct: 'true'
27 | AfterUnion: 'true'
28 | AfterExternBlock: 'true'
29 | BeforeCatch: 'true'
30 | BeforeElse: 'true'
31 | SplitEmptyFunction: 'false'
32 | SplitEmptyRecord: 'false'
33 | SplitEmptyNamespace: 'false'
34 | BreakBeforeInheritanceComma: 'true'
35 | BreakBeforeTernaryOperators: 'false'
36 | BreakConstructorInitializers: AfterColon
37 | BreakInheritanceList: AfterColon
38 | ColumnLimit: '140'
39 | CommentPragmas: '^ :: '
40 | CompactNamespaces: 'false'
41 | Cpp11BracedListStyle: 'false'
42 | FixNamespaceComments: 'false'
43 | IncludeCategories:
44 | - Regex: '^".*'
45 | Priority: 1
46 | - Regex: '^"(.*)/'
47 | Priority: 2
48 | - Regex: '^<(.*)/'
49 | Priority: 3
50 | - Regex: '.*'
51 | Priority: 4
52 | IncludeBlocks: Regroup
53 | IndentCaseLabels: 'true'
54 | IndentPPDirectives: AfterHash
55 | IndentWidth: '4'
56 | IndentWrappedFunctionNames: 'true'
57 | JavaScriptQuotes: Leave
58 | KeepEmptyLinesAtTheStartOfBlocks: 'false'
59 | Language: Cpp
60 | MaxEmptyLinesToKeep: '1'
61 | NamespaceIndentation: All
62 | PenaltyBreakBeforeFirstCallParameter: 7
63 | PenaltyBreakAssignment: 8
64 | PenaltyBreakComment: 200
65 | PenaltyBreakFirstLessLess: 50
66 | PenaltyBreakString: 100
67 | PenaltyBreakTemplateDeclaration: 10
68 | PenaltyExcessCharacter: 10
69 | PenaltyReturnTypeOnItsOwnLine: 1000000
70 | PointerAlignment: Left
71 | ReflowComments: 'false'
72 | SortIncludes: 'false'
73 | SortUsingDeclarations: 'true'
74 | SpaceAfterTemplateKeyword: 'true'
75 | SpaceBeforeAssignmentOperators: 'true'
76 | SpaceBeforeCpp11BracedList: 'true'
77 | SpaceBeforeCtorInitializerColon: 'true'
78 | SpaceBeforeInheritanceColon: 'true'
79 | SpaceBeforeParens: ControlStatements
80 | SpaceBeforeRangeBasedForLoopColon: 'true'
81 | SpaceInEmptyParentheses: 'false'
82 | SpacesBeforeTrailingComments: '2'
83 | SpacesInAngles: 'false'
84 | SpacesInCStyleCastParentheses: 'false'
85 | SpacesInContainerLiterals: 'false'
86 | SpacesInParentheses: 'false'
87 | SpacesInSquareBrackets: 'false'
88 | Standard: Cpp11
89 | TabWidth: '4'
90 | UseTab: Never
91 |
92 | ...
93 |
--------------------------------------------------------------------------------
/.github/workflows/buildFluidDial.yml:
--------------------------------------------------------------------------------
1 | name: Build FluidDial
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v4
12 | - uses: actions/cache@v4
13 | with:
14 | path: |
15 | ~/.cache/pip
16 | ~/.platformio/.cache
17 | key: ${{ runner.os }}-pio
18 | - uses: actions/setup-python@v5
19 | with:
20 | python-version: '3.11'
21 | - name: Install PlatformIO Core
22 | run: pip install --upgrade platformio
23 |
24 | - name: Build PlatformIO Project
25 | run: pio run && pio run -t buildfs && pio run -t build_merged
26 | - name: Upload binaries
27 | uses: actions/upload-artifact@v4
28 | with:
29 | name: FluidDial
30 | path: .pio/build/*/*.bin
31 |
32 |
--------------------------------------------------------------------------------
/.github/workflows/buildRelease.yml:
--------------------------------------------------------------------------------
1 | name: Build FluidDial Release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | tag:
7 | description: 'Release version'
8 | required: true
9 |
10 | permissions:
11 | contents: write
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | - name: Cache pip
19 | uses: actions/cache@v4
20 | with:
21 | path: ~/.cache/pip
22 | key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
23 | restore-keys: |
24 | ${{ runner.os }}-pip-
25 | - name: Cache PlatformIO
26 | uses: actions/cache@v4
27 | with:
28 | path: ~/.platformio
29 | key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
30 | - name: Set up Python
31 | uses: actions/setup-python@v5
32 | with:
33 | python-version: '3.11'
34 | - name: Install PlatformIO
35 | run: |
36 | python -m pip install --upgrade pip
37 | pip install --upgrade platformio
38 | - name: Set release version
39 | run: |
40 | git config user.email "wmb@firmworks.com"
41 | git config user.name "Mitch Bradley"
42 | git tag "${{ github.event.inputs.tag }}" -a -m "Release test"
43 | - name: Create release directory
44 | run: |
45 | mkdir -p release
46 | rm -f release/*
47 | - name: Build
48 | run: |
49 | for env in m5dial cyddial; do
50 | pio run -e $env
51 | pio run -e $env -t build_merged
52 | done
53 | python manifest.py
54 | ls release/*
55 | #- name: Upload binaries
56 | # uses: actions/upload-artifact@v4
57 | # with:
58 | # name: FluidDial_firmware
59 | # path: release/*
60 | - name: Create release
61 | uses: softprops/action-gh-release@v1
62 | with:
63 | tag_name: ${{ github.event.inputs.tag }}
64 | files: release/*
65 | draft: True
66 | - name: Deploy to fluidnc-releases
67 | uses: datalbry/copy_folder_to_another_repo_action@1.0.0
68 | env:
69 | API_TOKEN_GITHUB: ${{ secrets.FLUIDDIAL_RELEASE_COPY_TOKEN }}
70 | with:
71 | source_folder: 'release'
72 | destination_repo: 'bdring/fluiddial-releases'
73 | destination_branch: 'main'
74 | destination_folder: releases/${{ github.event.inputs.tag }}
75 | user_email: bdring@buildlog.net
76 | user_name: 'Bart Dring'
77 | commit_msg: Release ${{ github.event.inputs.tag }}
78 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | prefs
2 | .pio
3 | .vscode
4 | src/version.*
5 | *~
6 | junk
7 | release
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FluidDial: A CNC Pendant for FluidNC Firmware.
2 |
3 | 
4 |
5 | Wiki pages for more information: [M5 FluidDial Pendant (left image)](http://wiki.fluidnc.com/en/hardware/official/M5Dial_Pendant) and [CYD Dial Pendant (right image)](http://wiki.fluidnc.com/en/hardware/official/CYD_Dial_Pendant).
6 |
7 | Both have similar functionality and similar cost, using different hardware.
8 |
--------------------------------------------------------------------------------
/assets/ATTRIBUTION:
--------------------------------------------------------------------------------
1 | run by Eko Sofiantono from Noun Project (CC BY 3.0)
2 |
--------------------------------------------------------------------------------
/assets/FilesBG.svg:
--------------------------------------------------------------------------------
1 |
2 |
77 |
--------------------------------------------------------------------------------
/assets/JogBG.svg:
--------------------------------------------------------------------------------
1 |
2 |
263 |
--------------------------------------------------------------------------------
/assets/Run.svg:
--------------------------------------------------------------------------------
1 |
2 |
113 |
--------------------------------------------------------------------------------
/assets/jogbg.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/assets/jogbg.xcf
--------------------------------------------------------------------------------
/build_merged.py:
--------------------------------------------------------------------------------
1 | # This script adds a "build_merged" target, used like "pio run -e cyd -t build_merged",
2 | # that creates a combined image with both the firmware and the filesystem images
3 | # The two smaller images must be built first, with "pio run" and "pio run -t buildfs"
4 | Import("env")
5 |
6 | flash_size = env.BoardConfig().get("upload.flash_size", "detect")
7 |
8 | cmd = '$PYTHONEXE $UPLOADER --chip $BOARD_MCU merge_bin --output $BUILD_DIR/merged-flash.bin --flash_mode dio --flash_size ' + flash_size + " "
9 |
10 | for image in env.get("FLASH_EXTRA_IMAGES", []):
11 | cmd += image[0] + " " + env.subst(image[1]) + " "
12 |
13 | filesystem_start = env.GetProjectOption("custom_filesystem_start", "Missing_custom_filesystem_start_variable")
14 |
15 | cmd += " 0x10000 $BUILD_DIR/firmware.bin " + filesystem_start + " $BUILD_DIR/littlefs.bin"
16 |
17 | env.AddCustomTarget(
18 | name="build_merged",
19 | dependencies=["$BUILD_DIR/bootloader.bin", "$BUILD_DIR/firmware.bin"],
20 | actions=["pio run -e $PIOENV -t buildfs", cmd],
21 | title="Build Merged",
22 | description="Build combined image with program and filesystem"
23 | )
24 |
--------------------------------------------------------------------------------
/data/PCBackground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/PCBackground.png
--------------------------------------------------------------------------------
/data/abouttp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/abouttp.png
--------------------------------------------------------------------------------
/data/disabled_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/disabled_button.png
--------------------------------------------------------------------------------
/data/filesbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/filesbg.png
--------------------------------------------------------------------------------
/data/filestp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/filestp.png
--------------------------------------------------------------------------------
/data/fluid_dial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/fluid_dial.png
--------------------------------------------------------------------------------
/data/green_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/green_button.png
--------------------------------------------------------------------------------
/data/hometp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/hometp.png
--------------------------------------------------------------------------------
/data/jogbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/jogbg.png
--------------------------------------------------------------------------------
/data/jogtp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/jogtp.png
--------------------------------------------------------------------------------
/data/macrostp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/macrostp.png
--------------------------------------------------------------------------------
/data/orange_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/orange_button.png
--------------------------------------------------------------------------------
/data/powertp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/powertp.png
--------------------------------------------------------------------------------
/data/probetp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/probetp.png
--------------------------------------------------------------------------------
/data/red_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/red_button.png
--------------------------------------------------------------------------------
/data/statustp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/statustp.png
--------------------------------------------------------------------------------
/data/toolchangetp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/data/toolchangetp.png
--------------------------------------------------------------------------------
/git-version.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import filecmp, tempfile, shutil, os
3 |
4 | # Thank you https://docs.platformio.org/en/latest/projectconf/section_env_build.html !
5 |
6 | gitFail = False
7 | try:
8 | subprocess.check_call(["git", "status"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
9 | except:
10 | gitFail = True
11 |
12 | if gitFail:
13 | tag = "v0.0.x"
14 | rev = " (noGit)"
15 | url = " (noGit)"
16 | else:
17 | try:
18 | tag = (
19 | subprocess.check_output(["git", "describe", "--tags", "--abbrev=0"], stderr=subprocess.DEVNULL)
20 | .strip()
21 | .decode("utf-8")
22 | )
23 | except:
24 | tag = "v0.0.x"
25 |
26 | # Check to see if the head commit exactly matches a tag.
27 | # If so, the revision is "release", otherwise it is BRANCH-COMMIT
28 | try:
29 | subprocess.check_call(["git", "describe", "--tags", "--exact"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
30 | rev = ''
31 | except:
32 | branchname = (
33 | subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
34 | .strip()
35 | .decode("utf-8")
36 | )
37 | revision = (
38 | subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
39 | .strip()
40 | .decode("utf-8")
41 | )
42 | modified = (
43 | subprocess.check_output(["git", "status", "-uno", "-s"])
44 | .strip()
45 | .decode("utf-8")
46 | )
47 | if modified:
48 | dirty = "-dirty"
49 | else:
50 | dirty = ""
51 | rev = "%s-%s%s" % (branchname, revision, dirty)
52 |
53 | try:
54 | url = (
55 | subprocess.check_output(["git", "config", "--get", "remote.origin.url"])
56 | .strip()
57 | .decode("utf-8")
58 | )
59 | except:
60 | url = "None"
61 |
62 | git_info = '%s%s' % (tag, rev)
63 | git_url = url
64 |
65 | provisional = "src/version.cxx"
66 | final = "src/version.cpp"
67 | with open(provisional, "w") as fp:
68 | fp.write('const char* git_info = \"' + git_info + '\";\n')
69 | fp.write('const char* git_url = \"' + git_url + '\";\n')
70 |
71 | if not os.path.exists(final):
72 | # No version.cpp so rename version.cxx to version.cpp
73 | os.rename(provisional, final)
74 | elif not filecmp.cmp(provisional, final):
75 | # version.cxx differs from version.cpp so get rid of the
76 | # old .cpp and rename .cxx to .cpp
77 | os.remove(final)
78 | os.rename(provisional, final)
79 | else:
80 | # The existing version.cpp is the same as the new version.cxx
81 | # so we can just leave the old version.cpp in place and get
82 | # rid of version.cxx
83 | os.remove(provisional)
84 |
--------------------------------------------------------------------------------
/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/manifest.py:
--------------------------------------------------------------------------------
1 | import subprocess, os, sys, shutil
2 | import hashlib
3 |
4 | relPath = os.path.join('release')
5 |
6 | tag = (
7 | subprocess.check_output(["git", "describe", "--tags", "--abbrev=0"])
8 | .strip()
9 | .decode("utf-8")
10 | )
11 |
12 | manifestRelPath = relPath
13 |
14 | manifest = {
15 | "name": "FluidDial",
16 | "version": tag,
17 | "source_url": "https://github.com/bdring/FluidDial/tree/" + tag,
18 | "release_url": "https://github.com/bdring/FluidDial/releases/tag/" + tag,
19 | "funding_url": "https://www.paypal.com/donate/?hosted_button_id=8DYLB6ZYYDG7Y",
20 | "images": {},
21 | "files": {},
22 | # "upload": {
23 | # "name": "upload",
24 | # "description": "Things you can upload to the file system",
25 | # "choice-name": "Upload group",
26 | # "choices": []
27 | # },
28 | "installable": {
29 | "name": "installable",
30 | "description": "Things you can install",
31 | "choice-name": "Dial type",
32 | "choices": []
33 | },
34 | }
35 |
36 | def addImage(name, offset, srcfilename, srcpath, dstpath):
37 | dstFilename = name + '.bin'
38 | fulldstfile = os.path.join(dstpath, dstFilename)
39 |
40 | print(fulldstfile)
41 | shutil.copy(os.path.join(srcpath, srcfilename), fulldstfile)
42 |
43 | with open(fulldstfile, "rb") as f:
44 | data = f.read()
45 | image = {
46 | # "name": name,
47 | "size": os.path.getsize(fulldstfile),
48 | "offset": offset,
49 | "path": dstFilename,
50 | "signature": {
51 | "algorithm": "SHA2-256",
52 | "value": hashlib.sha256(data).hexdigest()
53 | }
54 | }
55 | if manifest['images'].get(name) != None:
56 | print("Duplicate image name", name)
57 | sys.exit(1)
58 | manifest['images'][name] = image
59 |
60 | for envName in ['m5dial', 'cyddial']:
61 | buildDir = os.path.join('.pio', 'build', envName)
62 | # shutil.copy(os.path.join(buildDir, 'merged-flash.bin'), os.path.join(relPath, envName + '.bin'))
63 | addImage(envName, '0x0000', 'merged-flash.bin', buildDir, manifestRelPath)
64 |
65 | def addSection(node, name, description, choice):
66 | section = {
67 | "name": name,
68 | "description": description,
69 | }
70 | if choice != None:
71 | section['choice-name'] = choice
72 | section['choices'] = []
73 | node.append(section)
74 |
75 | def addDialType(name, description, choice=None):
76 | addSection(manifest['installable']['choices'], name, description, choice)
77 |
78 | def addInstallable(install_type, erase, images):
79 | for image in images:
80 | if manifest['images'].get(image) == None:
81 | print("Missing image", image)
82 | sys.exit(1)
83 |
84 | node1 = manifest['installable']['choices']
85 | installable = {
86 | "name": install_type["name"],
87 | "description": install_type["description"],
88 | "erase": erase,
89 | "images": images
90 | }
91 | node1[len(node1)-1]['choices'].append(installable)
92 |
93 | fresh_install = { "name": "install", "description": "Complete FluidDial installation"}
94 |
95 | def makeManifest():
96 | addDialType("FluidDial for M5Dial", "FluidDial for M5Dial", "FluidDial type")
97 | addInstallable(fresh_install, True, ["m5dial"])
98 |
99 | addDialType("FluidDial for CYD", "FluidDial for CYD Dial", "FluidDial type")
100 | addInstallable(fresh_install, True, ["cyddial"])
101 |
102 |
103 | makeManifest()
104 |
105 | import json
106 | def printManifest():
107 | print(json.dumps(manifest, indent=2))
108 |
109 | with open(os.path.join(manifestRelPath, "manifest.json"), "w") as manifest_file:
110 | json.dump(manifest, manifest_file, indent=2)
111 |
112 | sys.exit(0)
113 |
--------------------------------------------------------------------------------
/part_files/CYD_Dial_Bottom.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/part_files/CYD_Dial_Bottom.stl
--------------------------------------------------------------------------------
/part_files/CYD_Dial_JC2432W328C.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/part_files/CYD_Dial_JC2432W328C.FCStd
--------------------------------------------------------------------------------
/part_files/CYD_Dial_JC2432W328C_bottom.3mf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/part_files/CYD_Dial_JC2432W328C_bottom.3mf
--------------------------------------------------------------------------------
/part_files/CYD_Dial_JC2432W328C_top.3mf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/part_files/CYD_Dial_JC2432W328C_top.3mf
--------------------------------------------------------------------------------
/part_files/CYD_Dial_Top.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/part_files/CYD_Dial_Top.stl
--------------------------------------------------------------------------------
/part_files/FluidDialLabel.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdring/FluidDial/b021b32dbe1ada60f89908047785d5c06cd91ae7/part_files/FluidDialLabel.pdf
--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [platformio]
12 | default_envs = m5dial, cyddial
13 |
14 | [common]
15 | build_flags =
16 | !python ./git-version.py
17 | -DJSP_USE_CHARP
18 | -DE4_POS_T
19 | -DVERBATIM_GCODE_MODES
20 | lib_deps =
21 | https://github.com/MitchBradley/json-streaming-parser#charp-1.0.2
22 | https://github.com/MitchBradley/GrblParser#9108f54
23 | build_src_filter = +<*.c> +<*.h> +<*.cpp> +<*.hpp> - - + -
24 |
25 | [env:m5dial]
26 | ; Pendant based on M5Dial
27 | ; http://wiki.fluidnc.com/en/hardware/official/M5Dial_Pendant
28 | platform = espressif32
29 | board = m5stack-stamps3
30 | framework = arduino
31 | platform_packages =
32 | platformio/framework-arduinoespressif32@3.20017.0
33 | monitor_filters=esp32_exception_decoder
34 | board_build.filesystem = littlefs
35 | upload_flags=--no-stub
36 | lib_deps =
37 | ${common.lib_deps}
38 | m5stack/M5Unified
39 | m5stack/M5Dial
40 | build_flags =
41 | ${common.build_flags}
42 | -DUSE_M5
43 | -DFNC_BAUD=1000000
44 | -DDEBUG_TO_USB
45 | custom_filesystem_start=0x670000
46 | extra_scripts = ./build_merged.py
47 | build_src_filter = ${common.build_src_filter} + +
48 |
49 | [env:cyd_base]
50 | ; Pendant based on a 2432S028 "Cheap Yellow Display" and a hand wheel pulse encoder
51 | ; http://wiki.fluidnc.com/en/hardware/official/CYD_Dial_Pendant
52 | platform = espressif32
53 | board = esp32dev
54 | framework = arduino
55 | platform_packages =
56 | platformio/framework-arduinoespressif32@^3.20016.0
57 | monitor_filters=esp32_exception_decoder
58 | monitor_speed=115200
59 | upload_speed=921600
60 | board_build.filesystem = littlefs
61 | upload_flags=--no-stub
62 | lib_deps =
63 | ${common.lib_deps}
64 | ; m5stack/M5Unified
65 | LovyanGFX=https://github.com/lovyan03/LovyanGFX#develop
66 | build_flags =
67 | ${common.build_flags}
68 | -DUSE_LOVYANGFX
69 | -DFNC_BAUD=1000000
70 | ;-DCORE_DEBUG_LEVEL=5
71 | -DCYD_BUTTONS
72 | custom_filesystem_start=0x290000
73 | extra_scripts = ./build_merged.py
74 | build_src_filter = ${common.build_src_filter} + + + -
75 |
76 | # This works for both resistive and capacitive CYDs, chosen at initial startup
77 | [env:cyddial]
78 | extends = env:cyd_base
79 | build_flags =
80 | ${env:cyd_nodebug.build_flags}
81 | -DCYD_BUTTONS
82 | -DRESISTIVE_CYD
83 | -DCAPACITIVE_CYD
84 |
85 | # This is the original CYD build for a resistive CYD
86 | [env:cyd_resistive]
87 | extends = env:cyd_base
88 | build_flags =
89 | ${env:cyd_base.build_flags}
90 | -DDEBUG_TO_USB
91 | -DRESISTIVE_CYD
92 |
93 | # This is for a capacitive CYD without buttons or lockout
94 | [env:cyd_nodebug]
95 | extends = env:cyd_base
96 | build_flags =
97 | ${env:cyd_base.build_flags}
98 | -DCAPACITIVE_CYD
99 |
100 | # This is for a capacitive CYD with physical buttons
101 | [env:cyd_buttons]
102 | extends = env:cyd_nodebug
103 | build_flags =
104 | ${env:cyd_nodebug.build_flags}
105 | -DCYD_BUTTONS
106 |
107 | # This is for a capacitive CYD with physical buttons and a lockout switch
108 | [env:cyd_lockable]
109 | extends = env:cyd_buttons
110 | build_flags =
111 | ${env:cyd_buttons.build_flags}
112 | -DLOCKOUT_PIN=GPIO_NUM_34
113 |
114 | [env:windows]
115 | ; Runs the code under Windows, useful for development
116 | lib_deps =
117 | ${common.lib_deps}
118 | m5stack/M5Unified@^0.1.10
119 | platform = native
120 | build_type = release
121 | build_flags = -O0 -xc++ -std=c++17 -lSDL2
122 | ${common.build_flags}
123 | -DWINDOWS
124 | -DUSE_M5
125 | -DM5GFX_BOARD=board_M5Dial
126 | -I"C:/msys64/mingw32/include/SDL2" ; for Windows SDL2
127 | -L"C:/msys64/mingw32/lib" ; for Windows SDL2
128 | build_src_filter = ${common.build_src_filter} + -
129 |
--------------------------------------------------------------------------------
/src/AboutScene.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 - Barton Dring
2 | // Use of this source code is governed by a GPLv3 license that can be found in the LICENSE file.
3 |
4 | #include "Scene.h"
5 | #include "FileParser.h"
6 | #include "AboutScene.h"
7 |
8 | extern Scene menuScene;
9 |
10 | extern const char* git_info; // auto generated version.cpp
11 |
12 | static const int MIN_BRIGHTNESS = 8;
13 |
14 | void AboutScene::onEntry(void* arg) {
15 | getBrightness();
16 |
17 | if (state != Disconnected) {
18 | send_line("$G");
19 | send_line("$I");
20 | }
21 | }
22 |
23 | void AboutScene::onDialButtonPress() {
24 | activate_scene(&menuScene);
25 | }
26 | void AboutScene::onGreenButtonPress() {
27 | #ifdef ARDUINO
28 | esp_restart();
29 | #endif
30 | }
31 | void AboutScene::onRedButtonPress() {
32 | #ifdef USE_M5
33 | set_disconnected_state();
34 | # ifdef ARDUINO
35 | centered_text("Use red button to wakeup", 118, RED, TINY);
36 | refreshDisplay();
37 | delay_ms(2000);
38 |
39 | deep_sleep(0);
40 | # else
41 | dbg_println("Sleep");
42 | # endif
43 | #else
44 | next_layout(1);
45 | reDisplay();
46 | #endif
47 | }
48 |
49 | void AboutScene::onTouchClick() {
50 | fnc_realtime(StatusReport);
51 | if (state == Idle) {
52 | send_line("$G");
53 | send_line("$I");
54 | }
55 | }
56 |
57 | void AboutScene::onEncoder(int delta) {
58 | if (delta > 0 && _brightness < 255) {
59 | display.setBrightness(++_brightness);
60 | setPref("brightness", _brightness);
61 | }
62 | if (delta < 0 && _brightness > MIN_BRIGHTNESS) {
63 | display.setBrightness(--_brightness);
64 | setPref("brightness", _brightness);
65 | }
66 | reDisplay();
67 | }
68 | void AboutScene::onStateChange(state_t old_state) {
69 | reDisplay();
70 | }
71 | void AboutScene::reDisplay() {
72 | background();
73 | drawStatus();
74 |
75 | const int key_x = 118;
76 | const int val_x = 122;
77 | const int y_spacing = 20;
78 | int y = 80;
79 |
80 | std::string version_str = "Ver ";
81 | version_str += git_info;
82 | centered_text(version_str.c_str(), y, LIGHTGREY, TINY);
83 | refreshDisplay();
84 | y += 10;
85 | #ifdef FNC_BAUD // FNC_BAUD might not be defined for Windows
86 | text("FNC baud:", key_x, y += y_spacing, LIGHTGREY, TINY, bottom_right);
87 | text(intToCStr(FNC_BAUD), val_x, y, GREEN, TINY, bottom_left);
88 | #endif
89 |
90 | #ifndef DEBUG_TO_USB // backlight shares a pin with this.
91 | text("Brightness:", key_x, y += y_spacing, LIGHTGREY, TINY, bottom_right);
92 | text(intToCStr(_brightness), val_x, y, GREEN, TINY, bottom_left);
93 | #endif
94 |
95 | if (wifi_ssid.length()) {
96 | std::string wifi_str = wifi_mode;
97 | if (wifi_mode == "No Wifi") {
98 | centered_text(wifi_str.c_str(), y += y_spacing, LIGHTGREY, TINY);
99 | } else {
100 | wifi_str += " ";
101 | wifi_str += wifi_ssid;
102 | centered_text(wifi_str.c_str(), y += y_spacing, LIGHTGREY, TINY);
103 | if (wifi_mode == "STA" && wifi_connected == "Not connected") {
104 | centered_text(wifi_connected.c_str(), y += y_spacing, RED, TINY);
105 | } else {
106 | wifi_str = "IP ";
107 | wifi_str += wifi_ip;
108 | centered_text(wifi_str.c_str(), y += y_spacing, LIGHTGREY, TINY);
109 | }
110 | }
111 | }
112 |
113 | #ifdef ARDUINO
114 | const char* greenLegend = "Restart";
115 | #else
116 | const char* greenLegend = "";
117 | #endif
118 |
119 | //drawOptionButton("Tool Menu", enable_tool_menu, 40, 135, 160);
120 |
121 | drawMenuTitle(current_scene->name());
122 |
123 | #ifdef USE_M5
124 | drawButtonLegends("Sleep", greenLegend, "Menu");
125 | #else
126 | drawButtonLegends("Layout", greenLegend, "Menu");
127 | #endif
128 | drawError(); // if there is one
129 | refreshDisplay();
130 | }
131 |
132 | int AboutScene::getBrightness() {
133 | if (initPrefs()) {
134 | getPref("brightness", &_brightness);
135 | }
136 | return _brightness;
137 | }
138 |
139 | AboutScene aboutScene;
140 |
--------------------------------------------------------------------------------
/src/AboutScene.h:
--------------------------------------------------------------------------------
1 | #include "Scene.h"
2 |
3 | class AboutScene : public Scene {
4 | private:
5 | int _brightness = 255;
6 |
7 | public:
8 | AboutScene() : Scene("About", 4) {}
9 |
10 | void onEntry(void* arg);
11 |
12 | void onDialButtonPress();
13 | void onGreenButtonPress();
14 | void onRedButtonPress();
15 |
16 | void onTouchClick() override;
17 |
18 | void onEncoder(int delta);
19 | void onStateChange(state_t old_state);
20 | void reDisplay();
21 | int getBrightness();
22 | };
23 |
--------------------------------------------------------------------------------
/src/Config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Instead of editing this file, consider adding -D lines in platformio.ini
4 |
5 | // System Interface
6 |
7 | // #define ECHO_FNC_TO_DEBUG
8 |
9 | // #define UART_ON_PORT_B // Not recommended, see comment in System.h
10 |
11 | // Automatically go to Jog Scene when first connected
12 | // #define AUTO_JOG_SCENE
13 |
14 | // Automatically go to Homing Scene when unhomed alarm is present
15 | // #define AUTO_HOMING_SCENE
16 |
17 | // Automatically leave Homing Scene after homing is finished
18 | // #define AUTO_HOMING_RETURN
19 |
--------------------------------------------------------------------------------
/src/ConfigItem.cpp:
--------------------------------------------------------------------------------
1 | #include "ConfigItem.h"
2 | #include "Scene.h"
3 |
4 | std::vector configRequests;
5 |
6 | void parse_dollar(const char* line) {
7 | for (auto it = configRequests.begin(); it != configRequests.end(); ++it) {
8 | auto item = *it;
9 |
10 | size_t cmdlen = strlen(item->name());
11 |
12 | if (strncmp(line, item->name(), cmdlen) == 0 && line[cmdlen] == '=') {
13 | line += cmdlen + 1;
14 | item->got(line);
15 |
16 | current_scene->reDisplay();
17 | configRequests.erase(it);
18 | break;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/ConfigItem.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "FluidNCModel.h"
5 |
6 | class ConfigItem;
7 | extern std::vector configRequests;
8 |
9 | class ConfigItem {
10 | private:
11 | const char* _name;
12 | bool _known;
13 |
14 | public:
15 | ConfigItem(const char* name) : _name(name), _known(false) {}
16 |
17 | virtual void set(const char* s) = 0;
18 | const char* name() { return _name; }
19 | bool known() { return _known; }
20 | void init() {
21 | _known = false;
22 | configRequests.push_back(this);
23 | send_line(_name);
24 | }
25 | void got(const char* s) {
26 | _known = true;
27 | set(s);
28 | }
29 | };
30 |
31 | class IntConfigItem : public ConfigItem {
32 | private:
33 | int _value;
34 |
35 | public:
36 | IntConfigItem(const char* name) : ConfigItem(name) {}
37 | int get() { return _value; }
38 | void set(const char* s) { _value = atoi(s); }
39 | };
40 |
41 | class PosConfigItem : public ConfigItem {
42 | private:
43 | pos_t _value;
44 |
45 | public:
46 | PosConfigItem(const char* name) : ConfigItem(name) {}
47 | pos_t get() { return _value; }
48 | void set(const char* s) { _value = atopos(s); }
49 | };
50 |
51 | class StringConfigItem : public ConfigItem {
52 | private:
53 | std::string _value;
54 |
55 | public:
56 | StringConfigItem(const char* name) : ConfigItem(name) {}
57 | std::string get() { return _value; }
58 | void set(const char* s) { _value = s; }
59 | };
60 |
61 | class BoolConfigItem : public ConfigItem {
62 | private:
63 | bool _value;
64 |
65 | public:
66 | BoolConfigItem(const char* name) : ConfigItem(name) {}
67 | bool get() { return _value; }
68 | void set(const char* s) { _value = strcmp(s, "true") == 0; }
69 | };
70 |
71 | void parse_dollar(const char* line);
72 |
--------------------------------------------------------------------------------
/src/ConfirmScene.cpp:
--------------------------------------------------------------------------------
1 | #include "Menu.h"
2 | #include
3 |
4 | // Confirm scene needs a string to display. It displays the string on
5 | // a background depicting the red and green buttons.
6 | // It pops when one of those buttons is pressed, or on back and flick back,
7 | // setting a variable to true iff the green button was pressed
8 |
9 | class ConfirmScene : public Scene {
10 | std::string _msg;
11 |
12 | public:
13 | ConfirmScene() : Scene("Confirm") {}
14 | void onEntry(void* arg) { _msg = (const char*)arg; }
15 | void reDisplay() {
16 | background();
17 | canvas.fillRoundRect(10, 90, 220, 60, 15, YELLOW);
18 | centered_text(_msg.c_str(), 120, BLACK, MEDIUM);
19 |
20 | drawButtonLegends("No", "Yes", "Back");
21 |
22 | refreshDisplay();
23 | }
24 | void onRedButtonPress() { pop_scene(nullptr); }
25 | void onGreenButtonPress() { pop_scene((void*)"Confirmed"); }
26 | void onDialButtonPress() { pop_scene(nullptr); }
27 | };
28 | ConfirmScene confirmScene;
29 |
--------------------------------------------------------------------------------
/src/ConfirmScene.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Menu.h"
4 |
5 | extern Scene confirmScene;
6 |
--------------------------------------------------------------------------------
/src/Drawing.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Mitch Bradley
2 | // Use of this source code is governed by a GPLv3 license that can be found in the LICENSE file.
3 |
4 | #include "System.h"
5 | #include "Drawing.h"
6 | #include "alarm.h"
7 | #include