mirror of
https://github.com/technik-gegg/SMuFF-1.1.git
synced 2026-02-19 17:31:25 +01:00
Recent changes
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.pio
|
||||
.pioenvs
|
||||
.piolibdeps
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
67
.travis.yml
Normal file
67
.travis.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
# Continuous Integration (CI) is the practice, in software
|
||||
# engineering, of merging all developer working copies with a shared mainline
|
||||
# several times a day < https://docs.platformio.org/page/ci/index.html >
|
||||
#
|
||||
# Documentation:
|
||||
#
|
||||
# * Travis CI Embedded Builds with PlatformIO
|
||||
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
||||
#
|
||||
# * PlatformIO integration with Travis CI
|
||||
# < https://docs.platformio.org/page/ci/travis.html >
|
||||
#
|
||||
# * User Guide for `platformio ci` command
|
||||
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
|
||||
#
|
||||
#
|
||||
# Please choose one of the following templates (proposed below) and uncomment
|
||||
# it (remove "# " before each line) or use own configuration according to the
|
||||
# Travis CI documentation (see above).
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# Template #1: General project. Test it using existing `platformio.ini`.
|
||||
#
|
||||
|
||||
# language: python
|
||||
# python:
|
||||
# - "2.7"
|
||||
#
|
||||
# sudo: false
|
||||
# cache:
|
||||
# directories:
|
||||
# - "~/.platformio"
|
||||
#
|
||||
# install:
|
||||
# - pip install -U platformio
|
||||
# - platformio update
|
||||
#
|
||||
# script:
|
||||
# - platformio run
|
||||
|
||||
|
||||
#
|
||||
# Template #2: The project is intended to be used as a library with examples.
|
||||
#
|
||||
|
||||
# language: python
|
||||
# python:
|
||||
# - "2.7"
|
||||
#
|
||||
# sudo: false
|
||||
# cache:
|
||||
# directories:
|
||||
# - "~/.platformio"
|
||||
#
|
||||
# env:
|
||||
# - PLATFORMIO_CI_SRC=path/to/test/file.c
|
||||
# - PLATFORMIO_CI_SRC=examples/file.ino
|
||||
# - PLATFORMIO_CI_SRC=path/to/test/directory
|
||||
#
|
||||
# install:
|
||||
# - pip install -U platformio
|
||||
# - platformio update
|
||||
#
|
||||
# script:
|
||||
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
|
||||
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
BIN
.vscode/ipch/6778f8c2b29c5d8a/CONFIG.ipch
vendored
Normal file
BIN
.vscode/ipch/6778f8c2b29c5d8a/CONFIG.ipch
vendored
Normal file
Binary file not shown.
16
SMuFF.code-workspace
Normal file
16
SMuFF.code-workspace
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "D:\\Data\\PlatformIO\\SMuFF-Ifc\\SMuFF-Ifc"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"terminal.integrated.env.windows": {
|
||||
"PATH": "C:\\Users\\Zoran\\.platformio\\penv\\Scripts;C:\\Users\\Zoran\\.platformio\\penv;C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Program Files (x86)\\Intel\\iCLS Client\\;C:\\Program Files\\Intel\\iCLS Client\\;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\;C:\\Program Files (x86)\\Windows Kits\\8.1\\Windows Performance Toolkit\\;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Program Files (x86)\\Microsoft SDKs\\TypeScript\\1.0\\;C:\\Program Files\\Microsoft SQL Server\\120\\Tools\\Binn\\;C:\\Program Files\\Microsoft\\Web Platform Installer\\;C:\\CODEGEAR\\INTERBASE\\BIN;C:\\Program Files (x86)\\QuickTime\\QTSystem\\;C:\\Program Files (x86)\\Common Files\\Acronis\\SnapAPI\\;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\Users\\Zoran\\AppData\\Local\\Android\\sdk\\platform-tools;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\Java\\jdk1.8.0_45\\bin;C:\\Program Files (x86)\\Android\\android-sdk\\tools;C:\\Program Files (x86)\\Android\\android-sdk\\platform-tools;C:\\apache-ant-1.9.3\\bin;C:\\Program Files (x86)\\nodejs\\;C:\\Program Files (x86)\\Git\\cmd;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files (x86)\\Langmeier Software\\Langmeier Backup\\;C:\\Program Files (x86)\\Langmeier Software\\Langmeier Backup\\tools\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Microsoft Network Monitor 3\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd;C:\\Program Files\\dotnet\\;C:\\Program Files (x86)\\SSH Communications Security\\SSH Secure Shell;C:\\Users\\Zoran\\AppData\\Roaming\\npm;C:\\Program Files (x86)\\Pstools;;C:\\Users\\Zoran\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Program Files (x86)\\Nmap;C:\\Users\\Zoran\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Program Files (x86)\\Intel\\iCLS Client\\;C:\\Program Files\\Intel\\iCLS Client\\;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\;C:\\Program Files (x86)\\Windows Kits\\8.1\\Windows Performance Toolkit\\;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Program Files (x86)\\Microsoft SDKs\\TypeScript\\1.0\\;C:\\Program Files\\Microsoft SQL Server\\120\\Tools\\Binn\\;C:\\Program Files\\Microsoft\\Web Platform Installer\\;C:\\CODEGEAR\\INTERBASE\\BIN;C:\\Program Files (x86)\\QuickTime\\QTSystem\\;C:\\Program Files (x86)\\Common Files\\Acronis\\SnapAPI\\;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\Users\\Zoran\\AppData\\Local\\Android\\sdk\\platform-tools;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\Java\\jdk1.8.0_45\\bin;C:\\Program Files (x86)\\Android\\android-sdk\\tools;C:\\Program Files (x86)\\Android\\android-sdk\\platform-tools;C:\\apache-ant-1.9.3\\bin;C:\\Program Files (x86)\\nodejs\\;C:\\Program Files (x86)\\Git\\cmd;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files (x86)\\Langmeier Software\\Langmeier Backup\\;C:\\Program Files (x86)\\Langmeier Software\\Langmeier Backup\\tools\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Microsoft Network Monitor 3\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd;C:\\Program Files\\dotnet\\;C:\\Program Files (x86)\\SSH Communications Security\\SSH Secure Shell;C:\\Users\\Zoran\\AppData\\Roaming\\npm;C:\\Program Files (x86)\\Pstools;;C:\\Users\\Zoran\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Program Files (x86)\\Nmap;C:\\Users\\Zoran\\AppData\\Local\\Programs\\Microsoft VS Code\\bin",
|
||||
"PLATFORMIO_CALLER": "vscode"
|
||||
}
|
||||
}
|
||||
}
|
||||
39
include/README
Normal file
39
include/README
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
46
lib/README
Normal file
46
lib/README
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
31
platformio.ini
Normal file
31
platformio.ini
Normal file
@@ -0,0 +1,31 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
[platformio]
|
||||
home_dir = D:/data/PlatformIO/
|
||||
|
||||
[env:megaatmega2560]
|
||||
build_unflags = -Wunused-variable
|
||||
platform = atmelavr
|
||||
board = megaatmega2560
|
||||
framework = arduino
|
||||
upload_port = COM35
|
||||
monitor_speed = 250000
|
||||
lib_deps =
|
||||
SPI
|
||||
Wire
|
||||
SD
|
||||
# JSON library for the configuration file
|
||||
ArduinoJson@6.10.1
|
||||
# LC-Display library
|
||||
U8g2@2.26.1
|
||||
# Rotary-Encoder library
|
||||
Encoder@1.4.1
|
||||
#Free memory library
|
||||
https://github.com/McNeight/MemoryFree
|
||||
156
src/Config.cpp
Normal file
156
src/Config.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module for reading configuration file (JSON-Format) from SD-Card
|
||||
*/
|
||||
|
||||
#include "SMuFF.h"
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
|
||||
const size_t capacity = 1200;
|
||||
|
||||
void readConfig()
|
||||
{
|
||||
|
||||
DynamicJsonDocument jsonDoc(capacity);
|
||||
|
||||
pinMode(SD_SS_PIN, OUTPUT);
|
||||
digitalWrite(SD_SS_PIN, HIGH);
|
||||
|
||||
/*
|
||||
if (card.init(SPI_FULL_SPEED, SD_SS_PIN)) {
|
||||
uint32_t cardSize = card.cardSize();
|
||||
__debug("Card type: ");
|
||||
switch (card.type()) {
|
||||
case SD_CARD_TYPE_SD1: __debug("SD"); break;
|
||||
case SD_CARD_TYPE_SD2: __debug("SD2"); break;
|
||||
case SD_CARD_TYPE_SDHC: __debug("SD%SC", cardSize < 70000000 ? "H" : "X"); break;
|
||||
default: __debug("Unknown");
|
||||
}
|
||||
__debug("Card size: %u MB", cardSize);
|
||||
if (volume.init(card)) {
|
||||
__debug("Volume is FAT%d", volume.fatType());
|
||||
root.openRoot(volume);
|
||||
if(!root.isOpen()) {
|
||||
__debug("Can't open root.");
|
||||
}
|
||||
else
|
||||
root.ls(LS_R | LS_DATE | LS_SIZE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!SD.begin(SD_SS_PIN)) {
|
||||
drawSDStatus(SD_ERR_INIT);
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
__debug("Trying to open config file '%s'", CONFIG_FILE);
|
||||
File cfg = SD.open(CONFIG_FILE);
|
||||
if (cfg) {
|
||||
size_t fsize = cfg.size();
|
||||
__debug("File size: %u", fsize);
|
||||
|
||||
if(fsize > capacity) {
|
||||
showDialog(P_TitleConfigError, P_ConfigFail1, P_ConfigFail3, P_OkButtonOnly);
|
||||
cfg.close();
|
||||
return;
|
||||
}
|
||||
|
||||
auto error = deserializeJson(jsonDoc, cfg);
|
||||
if (error) {
|
||||
__debug("deserializeJson() failed with code %s", error.c_str());
|
||||
showDialog(P_TitleConfigError, P_ConfigFail1, P_ConfigFail2, P_OkButtonOnly);
|
||||
}
|
||||
else {
|
||||
const char* selector = "Selector";
|
||||
const char* revolver = "Revolver";
|
||||
const char* feeder = "Feeder";
|
||||
const char* maxSpeed = "MaxSpeed";
|
||||
const char* invertDir = "InvertDir";
|
||||
drawSDStatus(SD_READING_CONFIG);
|
||||
int toolCnt = jsonDoc["ToolCount"];
|
||||
smuffConfig.toolCount = (toolCnt > MIN_TOOLS && toolCnt < MAX_TOOLS) ? toolCnt : 5;
|
||||
smuffConfig.firstToolOffset = jsonDoc[selector]["Offset"];
|
||||
smuffConfig.toolSpacing = jsonDoc[selector]["Spacing"];
|
||||
smuffConfig.stepsPerMM_X = jsonDoc[selector]["StepsPerMillimeter"];
|
||||
smuffConfig.maxSteps_X = ((smuffConfig.toolCount-1)*smuffConfig.toolSpacing+smuffConfig.firstToolOffset) * smuffConfig.stepsPerMM_X;
|
||||
smuffConfig.maxSpeed_X = jsonDoc[selector][maxSpeed];
|
||||
smuffConfig.acceleration_X = jsonDoc[selector]["Acceleration"];
|
||||
smuffConfig.invertDir_X = jsonDoc[selector][invertDir];
|
||||
smuffConfig.endstopTrigger_X = jsonDoc[selector]["EndstopTrigger"];
|
||||
smuffConfig.stepsPerRevolution_Y= jsonDoc[revolver]["StepsPerRevolution"];
|
||||
smuffConfig.firstRevolverOffset = jsonDoc[revolver]["Offset"];
|
||||
smuffConfig.revolverSpacing = smuffConfig.stepsPerRevolution_Y / 10;
|
||||
smuffConfig.maxSpeed_Y = jsonDoc[revolver][maxSpeed];
|
||||
smuffConfig.acceleration_Y = jsonDoc[revolver]["Acceleration"];
|
||||
smuffConfig.resetBeforeFeed_Y = jsonDoc[revolver]["ResetBeforeFeed"];
|
||||
smuffConfig.homeAfterFeed = jsonDoc[revolver]["HomeAfterFeed"];
|
||||
smuffConfig.invertDir_Y = jsonDoc[revolver][invertDir];
|
||||
smuffConfig.endstopTrigger_Y = jsonDoc[revolver]["EndstopTrigger"];
|
||||
smuffConfig.externalControl_Z = jsonDoc[feeder]["ExternalControl"];
|
||||
smuffConfig.stepsPerMM_Z = jsonDoc[feeder]["StepsPerMillimeter"];
|
||||
smuffConfig.acceleration_Z = jsonDoc[feeder]["Acceleration"];
|
||||
smuffConfig.maxSpeed_Z = jsonDoc[feeder][maxSpeed];
|
||||
smuffConfig.insertSpeed_Z = jsonDoc[feeder]["InsertSpeed"];
|
||||
smuffConfig.invertDir_Z = jsonDoc[feeder][invertDir];
|
||||
smuffConfig.endstopTrigger_Z = jsonDoc[feeder]["EndstopTrigger"];
|
||||
smuffConfig.reinforceLength = jsonDoc[feeder]["ReinforceLength"];
|
||||
smuffConfig.unloadRetract = jsonDoc[feeder]["UnloadRetract"];
|
||||
smuffConfig.unloadPushback = jsonDoc[feeder]["UnloadPushback"];
|
||||
smuffConfig.pushbackDelay = jsonDoc[feeder]["PushbackDelay"];
|
||||
int contrast = jsonDoc["LCDContrast"];
|
||||
smuffConfig.lcdContrast = (contrast > MIN_CONTRAST && contrast < MAX_CONTRAST) ? contrast : DSP_CONTRAST;
|
||||
smuffConfig.bowdenLength = jsonDoc["BowdenLength"];
|
||||
int i2cAdr = jsonDoc["I2CAddress"];
|
||||
smuffConfig.i2cAddress = (i2cAdr > 0 && i2cAdr < 255) ? i2cAdr : I2C_SLAVE_ADDRESS;
|
||||
smuffConfig.menuAutoClose = jsonDoc["MenuAutoClose"];
|
||||
smuffConfig.delayBetweenPulses = jsonDoc["DelayBetweenPulses"];
|
||||
smuffConfig.serial1Baudrate = jsonDoc["Serial1Baudrate"];
|
||||
smuffConfig.serial2Baudrate = jsonDoc["Serial2Baudrate"];
|
||||
smuffConfig.serialDueBaudrate = jsonDoc["SerialDueBaudrate"];
|
||||
smuffConfig.fanSpeed = jsonDoc["FanSpeed"];
|
||||
smuffConfig.powerSaveTimeout = jsonDoc["PowerSaveTimeout"];
|
||||
smuffConfig.duetDirect = jsonDoc["Duet3DDirect"];
|
||||
char* p = jsonDoc["UnloadCommand"];
|
||||
if(p != NULL && strlen(p) > 0)
|
||||
strlcpy(smuffConfig.unloadCommand, p, sizeof(smuffConfig.unloadCommand));
|
||||
|
||||
for(int i=0; i < smuffConfig.toolCount; i++) {
|
||||
char tmp[10];
|
||||
sprintf(tmp,"Tool%d", i);
|
||||
memset(smuffConfig.materials[i], 0, sizeof(smuffConfig.materials[i]));
|
||||
strlcpy(smuffConfig.materials[i], jsonDoc["Materials"][tmp], sizeof(smuffConfig.materials[i]));
|
||||
}
|
||||
//__debug("DONE reading config");
|
||||
}
|
||||
cfg.close();
|
||||
}
|
||||
else {
|
||||
__debug("Open config file failed: handle = %s", !cfg ? "FALSE" : "TRUE");
|
||||
drawSDStatus(SD_ERR_NOCONFIG);
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
122
src/Config.h
Normal file
122
src/Config.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SMUFF_CONFIG_H
|
||||
#define _SMUFF_CONFIG_H
|
||||
|
||||
#define VERSION_STRING "V1.1"
|
||||
#define VERSION_DATE "2019-05-12"
|
||||
#define CONFIG_FILE "SMUFF.CFG"
|
||||
|
||||
#define SELECTOR 0
|
||||
#define REVOLVER 1
|
||||
#define FEEDER 2
|
||||
|
||||
#define NUM_STEPPERS 3
|
||||
|
||||
#define MIN_TOOLS 2
|
||||
#define MAX_TOOLS 9
|
||||
|
||||
#define STEP_HIGH_X PORTA |= 0b00000001;
|
||||
#define STEP_LOW_X PORTA &= ~0b00000001;
|
||||
#define X_STEP_PIN 22
|
||||
#define X_DIR_PIN 23
|
||||
#define X_ENABLE_PIN 57
|
||||
#define X_END_PIN 19
|
||||
#define X_STEPS_PER_MM 800
|
||||
|
||||
#define STEP_HIGH_Y PORTA |= 0b00001000;
|
||||
#define STEP_LOW_Y PORTA &= ~0b00001000;
|
||||
#define Y_STEP_PIN 25
|
||||
#define Y_DIR_PIN 26
|
||||
#define Y_ENABLE_PIN 24
|
||||
#define Y_END_PIN 18
|
||||
|
||||
#define STEP_HIGH_Z PORTA |= 0b10000000;
|
||||
#define STEP_LOW_Z PORTA &= ~0b10000000;
|
||||
#define Z_STEP_PIN 29
|
||||
#define Z_DIR_PIN 39
|
||||
#define Z_ENABLE_PIN 28
|
||||
#define Z_END_PIN 38
|
||||
#define Z_STEPS_PER_MM 136
|
||||
|
||||
#define BEEPER_PIN 37
|
||||
#define BEEPER_FREQUENCY 1760
|
||||
#define BEEPER_DURATION 90
|
||||
#define BEEPER_UFREQUENCY 440
|
||||
#define BEEPER_UDURATION 90
|
||||
|
||||
#define SERVO1_PIN 44
|
||||
#define SERVO2_PIN 14
|
||||
#define SD_SS_PIN 53
|
||||
#define FAN_PIN 12
|
||||
#define HEATER0_PIN 4
|
||||
|
||||
#define ENCODER1_PIN 2
|
||||
#define ENCODER2_PIN 3
|
||||
#define ENCODER_BUTTON_PIN 5
|
||||
#define ENCODER_DELAY 4
|
||||
#define ENCODER_DELAY_MENU 2
|
||||
#define ENCODER_DELAY_OFS 1
|
||||
|
||||
#define DSP_CLOCK_PIN 52
|
||||
#define DSP_DATA_PIN 51
|
||||
#define DSP_CS_PIN 41
|
||||
#define DSP_DC_PIN 40
|
||||
#define DSP_RESET_PIN 27
|
||||
#define DSP_BACKLIGHT_PIN 65
|
||||
#define DSP_CONTRAST 200
|
||||
#define MIN_CONTRAST 60
|
||||
#define MAX_CONTRAST 250
|
||||
|
||||
#define TX2_PIN 16
|
||||
#define RX2_PIN 17
|
||||
#define I2C_SLAVE_ADDRESS 0x88
|
||||
|
||||
#define TX3_PIN 67
|
||||
#define RX3_PIN 44
|
||||
|
||||
#define FIRST_TOOL_OFFSET 1.2 // values in millimeter
|
||||
#define TOOL_SPACING 21.0 // values im millimeter
|
||||
#define FIRST_REVOLVER_OFFSET 320 // values in steps
|
||||
#define REVOLVER_SPACING 320 // values im steps
|
||||
#define USER_MESSAGE_RESET 15 // value in seconds
|
||||
#define MAX_LINES 5
|
||||
#define MAX_LINE_LENGTH 80
|
||||
#define POWER_SAVE_TIMEOUT 15 // value in seconds
|
||||
|
||||
#define BASE_FONT u8g2_font_6x12_t_symbols
|
||||
#define BASE_FONT_BIG u8g2_font_7x14B_tf
|
||||
#define SMALL_FONT u8g2_font_6x10_mr
|
||||
#define STATUS_FONT u8g2_font_7x14_tf
|
||||
#define LOGO_FONT u8g2_font_helvR08_tf
|
||||
#define ICONIC_FONT u8g2_font_open_iconic_check_2x_t
|
||||
|
||||
#define EEPROM_SELECTOR_POS SELECTOR*sizeof(long)
|
||||
#define EEPROM_REVOLVER_POS REVOLVER*sizeof(long)
|
||||
#define EEPROM_FEEDER_POS FEEDER*sizeof(long)
|
||||
#define EEPROM_TOOL 20
|
||||
#define EEPROM_CONTRAST 22
|
||||
#define EEPROM_TOOL_COUNT 24
|
||||
#define EEPROM_FEED_LENGTH 26
|
||||
#define EEPROM_1ST_TOOL_OFS 30
|
||||
#define EEPROM_TOOL_SPACING 34
|
||||
#define EEPROM_1ST_REV_OFS 38
|
||||
#define EEPROM_REV_SPACING 42
|
||||
#endif
|
||||
583
src/GCodes.cpp
Normal file
583
src/GCodes.cpp
Normal file
@@ -0,0 +1,583 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module for handling all the G-Codes supported
|
||||
*/
|
||||
|
||||
#include "SMuFF.h"
|
||||
#include "ZTimerLib.h"
|
||||
#include "ZStepperLib.h"
|
||||
#include "ZServo.h"
|
||||
#include "GCodes.h"
|
||||
|
||||
extern ZStepper steppers[NUM_STEPPERS];
|
||||
extern ZServo servo;
|
||||
|
||||
char* S_Param = (char*)"S";
|
||||
char* P_Param = (char*)"P";
|
||||
char* X_Param = (char*)"X";
|
||||
char* Y_Param = (char*)"Y";
|
||||
char* Z_Param = (char*)"Z";
|
||||
char* E_Param = (char*)"E";
|
||||
char* F_Param = (char*)"F";
|
||||
char* C_Param = (char*)"C";
|
||||
char* T_Param = (char*)"T";
|
||||
char* N_Param = (char*)"N";
|
||||
char* I_Param = (char*)"I";
|
||||
char* J_Param = (char*)"J";
|
||||
char* K_Param = (char*)"K";
|
||||
char* R_Param = (char*)"R";
|
||||
|
||||
GCodeFunctions gCodeFuncsM[] = {
|
||||
{ 80, dummy },
|
||||
{ 81, dummy },
|
||||
{ 104, dummy },
|
||||
{ 105, dummy },
|
||||
{ 108, dummy },
|
||||
{ 109, dummy },
|
||||
{ 220, dummy },
|
||||
{ 221, dummy },
|
||||
|
||||
{ 18, M18 },
|
||||
{ 20, M20 },
|
||||
{ 42, M42 },
|
||||
{ 84, M18 },
|
||||
{ 106, M106 },
|
||||
{ 107, M107 },
|
||||
{ 110, M110 },
|
||||
{ 111, M111 },
|
||||
{ 114, M114 },
|
||||
{ 115, M115 },
|
||||
{ 117, M117 },
|
||||
{ 119, M119 },
|
||||
{ 201, M201 },
|
||||
{ 203, M203 },
|
||||
{ 206, M206 },
|
||||
{ 250, M250 },
|
||||
{ 280, M280 },
|
||||
{ 300, M300 },
|
||||
{ 500, M500 },
|
||||
{ 503, M503 },
|
||||
{ 700, M700 },
|
||||
{ 701, M701 },
|
||||
{ 999, M999 },
|
||||
{ 2000, M2000 },
|
||||
{ 2001, M2001 },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
GCodeFunctions gCodeFuncsG[] = {
|
||||
{ 0, G0 },
|
||||
{ 1, G1 },
|
||||
{ 4, G4 },
|
||||
{ 12, G12 },
|
||||
{ 28, G28 },
|
||||
{ 90, G90 },
|
||||
{ 91, G91 },
|
||||
{ -1, NULL},
|
||||
};
|
||||
|
||||
int param;
|
||||
extern char tmp[128];
|
||||
|
||||
/*========================================================
|
||||
* Class G
|
||||
========================================================*/
|
||||
bool dummy(const char* msg, String buf, int serial) {
|
||||
int code = buf.toInt();
|
||||
__debug("Ignored M-Code: M%d", code);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M18(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if(buf.length()==0) {
|
||||
steppers[SELECTOR].setEnabled(false);
|
||||
steppers[REVOLVER].setEnabled(false);
|
||||
steppers[FEEDER].setEnabled(false);
|
||||
}
|
||||
else {
|
||||
if(buf.indexOf(X_Param) != -1) {
|
||||
steppers[SELECTOR].setEnabled(false);
|
||||
}
|
||||
else if(buf.indexOf(Y_Param) != -1) {
|
||||
steppers[REVOLVER].setEnabled(false);
|
||||
}
|
||||
else if(buf.indexOf(Z_Param) != -1) {
|
||||
steppers[FEEDER].setEnabled(false);
|
||||
}
|
||||
else {
|
||||
stat = false;
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M20(const char* msg, String buf, int serial) {
|
||||
|
||||
if(!getParamString(buf, S_Param, tmp, sizeof(tmp))){
|
||||
sprintf(tmp,"/");
|
||||
}
|
||||
if (SD.begin(SD_SS_PIN)) {
|
||||
File root = SD.open(tmp);
|
||||
listDir(root, 1, serial);
|
||||
root.close();
|
||||
return true;
|
||||
}
|
||||
sprintf_P(tmp, P_SD_InitError);
|
||||
printResponse(tmp, serial);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool M42(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
int pin;
|
||||
printResponse(msg, serial);
|
||||
if((pin = getParam(buf, P_Param)) == -1) {
|
||||
pinMode(pin, OUTPUT);
|
||||
if((param = getParam(buf, S_Param)) == -1) {
|
||||
if(param >= 0 && param <= 255)
|
||||
analogWrite(pin, param);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M106(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, S_Param)) == -1) {
|
||||
param = 255;
|
||||
}
|
||||
analogWrite(FAN_PIN, param);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M107(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
analogWrite(FAN_PIN, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M110(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, N_Param)) != -1) {
|
||||
currentLine = param;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M111(const char* msg, String buf, int serial) {
|
||||
if((param = getParam(buf, S_Param)) != -1) {
|
||||
testMode = param == 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M114(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
sprintf_P(tmp, P_AccelSpeed,
|
||||
String(steppers[SELECTOR].getStepPositionMM()).c_str(),
|
||||
String(steppers[REVOLVER].getStepPosition()).c_str(),
|
||||
String(steppers[FEEDER].getStepPositionMM()).c_str());
|
||||
printResponse(tmp, serial);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M115(const char* msg, String buf, int serial) {
|
||||
sprintf_P(tmp, P_GVersion, VERSION_STRING, VERSION_DATE);
|
||||
printResponse(tmp, serial);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M117(const char* msg, String buf, int serial) {
|
||||
String umsg = buf;
|
||||
umsg.replace("_", " ");
|
||||
beep(1);
|
||||
drawUserMessage(umsg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M119(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, Z_Param)) != -1) {
|
||||
steppers[FEEDER].setEndstopHit(param);
|
||||
}
|
||||
printEndstopState(serial);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M201(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if(buf.length()==0) {
|
||||
printAcceleration(serial);
|
||||
return stat;
|
||||
}
|
||||
if((param = getParam(buf, X_Param)) != -1) {
|
||||
if(param >= 200 && param <= 15000)
|
||||
steppers[SELECTOR].setAcceleration(param);
|
||||
else stat = false;
|
||||
}
|
||||
if((param = getParam(buf, Y_Param)) != -1) {
|
||||
if(param >= 200 && param <= 15000)
|
||||
steppers[REVOLVER].setAcceleration(param);
|
||||
else stat = false;
|
||||
}
|
||||
if((param = getParam(buf, Z_Param)) != -1) {
|
||||
if(param >= 200 && param <= 15000)
|
||||
steppers[FEEDER].setAcceleration(param);
|
||||
else stat = false;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M203(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if(buf.length()==0) {
|
||||
printSpeeds(serial);
|
||||
return stat;
|
||||
}
|
||||
if((param = getParam(buf, X_Param)) != -1) {
|
||||
if(param > 0 && param <= 10000)
|
||||
steppers[SELECTOR].setMaxSpeed(param);
|
||||
else stat = false;
|
||||
}
|
||||
if((param = getParam(buf, Y_Param)) != -1) {
|
||||
if(param > 0 && param <= 10000) {
|
||||
steppers[REVOLVER].setMaxSpeed(param);
|
||||
//__debug("Revolver max speed: %d", steppers[REVOLVER].getMaxSpeed());
|
||||
}
|
||||
else stat = false;
|
||||
}
|
||||
if((param = getParam(buf, Z_Param)) != -1) {
|
||||
if(param > 0 && param <= 10000)
|
||||
steppers[FEEDER].setMaxSpeed(param);
|
||||
else stat = false;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M206(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if(buf.length()==0) {
|
||||
printOffsets(serial);
|
||||
return stat;
|
||||
}
|
||||
if((param = getParam(buf, X_Param)) != -1) {
|
||||
if(param > 0 && param <= 10000)
|
||||
smuffConfig.firstToolOffset = (float)param/10;
|
||||
else stat = false;
|
||||
}
|
||||
if((param = getParam(buf, Y_Param)) != -1) {
|
||||
if(param > 0 && param <= 8640) {
|
||||
smuffConfig.firstRevolverOffset = param;
|
||||
}
|
||||
else stat = false;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M250(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
if((param = getParam(buf, C_Param)) != -1) {
|
||||
if(param >= 60 && param < 256) {
|
||||
display.setContrast(param);
|
||||
EEPROM.put(EEPROM_CONTRAST, param);
|
||||
printResponse(msg, serial);
|
||||
}
|
||||
else
|
||||
stat = false;
|
||||
}
|
||||
else {
|
||||
printResponse(msg, serial);
|
||||
char tmp[50];
|
||||
sprintf_P(tmp, P_M250Response, smuffConfig.lcdContrast);
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M280(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, S_Param)) != -1) {
|
||||
if(!setServoPos(param))
|
||||
stat = false;
|
||||
}
|
||||
else stat = false;
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M300(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, S_Param)) != -1) {
|
||||
int frequency = param;
|
||||
if((param = getParam(buf, P_Param)) != -1) {
|
||||
tone(BEEPER_PIN, frequency, param);
|
||||
}
|
||||
else
|
||||
stat = false;
|
||||
}
|
||||
else
|
||||
stat = false;
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M500(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
saveSettings(serial);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M503(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
reportSettings(serial);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M700(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if(toolSelected > 0 && toolSelected <= MAX_TOOLS) {
|
||||
getParamString(buf, S_Param, smuffConfig.materials[toolSelected], sizeof(smuffConfig.materials[0]));
|
||||
//__debug("Material: %s\n",smuffConfig.materials[toolSelected]);
|
||||
return loadFilament();
|
||||
}
|
||||
else
|
||||
stat = false;
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool M701(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
return unloadFilament();
|
||||
}
|
||||
|
||||
bool M999(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
delay(500);
|
||||
__asm__ volatile ("jmp 0x0000");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M2000(const char* msg, String buf, int serial) {
|
||||
char s[80];
|
||||
printResponse(msg, serial);
|
||||
getParamString(buf, S_Param, tmp, sizeof(tmp));
|
||||
if(strlen(tmp)>0) {
|
||||
printResponse("B", serial);
|
||||
for(unsigned i=0; i< strlen(tmp); i++) {
|
||||
sprintf(s,"%d:", (char)tmp[i]);
|
||||
printResponse(s, serial);
|
||||
}
|
||||
printResponse("10\n", serial);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M2001(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
getParamString(buf, S_Param, tmp, sizeof(tmp));
|
||||
String data = String(tmp);
|
||||
data.trim();
|
||||
if(data.length() > 0) {
|
||||
int ndx = 0;
|
||||
int pos = 0;
|
||||
if(data.startsWith("B")) {
|
||||
printResponse(">>", serial);
|
||||
ndx++;
|
||||
do {
|
||||
pos = data.indexOf(":", ndx);
|
||||
int c;
|
||||
if(pos != -1) {
|
||||
c = data.substring(ndx, pos).toInt();
|
||||
}
|
||||
else {
|
||||
c = data.substring(ndx).toInt();
|
||||
}
|
||||
if(c == 10) {
|
||||
printResponse("\\n", serial);
|
||||
}
|
||||
else {
|
||||
sprintf(tmp, "%c", c);
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
ndx = pos + 1;
|
||||
} while(pos != -1);
|
||||
printResponse("<<\n", serial);
|
||||
}
|
||||
else {
|
||||
printResponseP(P_WrongFormat, serial);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*========================================================
|
||||
* Class G
|
||||
========================================================*/
|
||||
bool G0(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, Y_Param)) != -1) {
|
||||
steppers[REVOLVER].setEnabled(true);
|
||||
prepSteppingAbs(REVOLVER, smuffConfig.firstRevolverOffset + ((param)*smuffConfig.revolverSpacing), true);
|
||||
runAndWait(REVOLVER);
|
||||
}
|
||||
if((param = getParam(buf, X_Param)) != -1) {
|
||||
steppers[SELECTOR].setEnabled(true);
|
||||
prepSteppingAbsMillimeter(SELECTOR, smuffConfig.firstToolOffset + (param * smuffConfig.toolSpacing));
|
||||
runAndWait(SELECTOR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool G1(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
bool isMill = true;
|
||||
if((param = getParam(buf, T_Param)) != -1) {
|
||||
isMill = (param == 1);
|
||||
}
|
||||
if((param = getParam(buf, Y_Param)) != -1) {
|
||||
//__debug("G1 moving Y: %d", param);
|
||||
steppers[REVOLVER].setEnabled(true);
|
||||
prepStepping(REVOLVER, (long)param, isMill);
|
||||
}
|
||||
if((param = getParam(buf, X_Param)) != -1) {
|
||||
//__debug("G1 moving X: %d", param);
|
||||
steppers[SELECTOR].setEnabled(true);
|
||||
prepStepping(SELECTOR, (long)param, isMill, true);
|
||||
}
|
||||
if((param = getParam(buf, Z_Param)) != -1) {
|
||||
//__debug("G1 moving Z: %d", param);
|
||||
steppers[FEEDER].setEnabled(true);
|
||||
prepStepping(FEEDER, (long)param, isMill);
|
||||
}
|
||||
runAndWait(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool G4(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if((param = getParam(buf, S_Param)) != -1) {
|
||||
if(param > 0 && param < 500)
|
||||
delay(param*1000);
|
||||
}
|
||||
else if((param = getParam(buf, P_Param)) != -1) {
|
||||
delay(param);
|
||||
}
|
||||
else {
|
||||
stat = false;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool G12(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
int wait = 500;
|
||||
int pos1 = 20;
|
||||
int pos2 = 45;
|
||||
int pos0 = 110;
|
||||
unsigned repeat = 0;
|
||||
if((param = getParam(buf, S_Param)) != -1) {
|
||||
wait = param;
|
||||
}
|
||||
if((param = getParam(buf, I_Param)) != -1) {
|
||||
pos1 = param;
|
||||
}
|
||||
if((param = getParam(buf, J_Param)) != -1) {
|
||||
pos2 = param;
|
||||
}
|
||||
if((param = getParam(buf, P_Param)) != -1) {
|
||||
pos0 = param;
|
||||
}
|
||||
if((param = getParam(buf, R_Param)) != -1) {
|
||||
repeat = param;
|
||||
}
|
||||
if(smuffConfig.wipeSequence[0] > 0) {
|
||||
unsigned n = 1;
|
||||
if(repeat > 0) {
|
||||
for(n=0; n < repeat; n++) {
|
||||
servo.write(pos1);
|
||||
delay(wait);
|
||||
servo.write(pos2);
|
||||
delay(wait);
|
||||
}
|
||||
servo.write(pos0);
|
||||
delay(100);
|
||||
servo.stop();
|
||||
}
|
||||
else {
|
||||
while(n < sizeof(smuffConfig.wipeSequence)) {
|
||||
if(smuffConfig.wipeSequence[n] == -1)
|
||||
break;
|
||||
servo.write(smuffConfig.wipeSequence[n]);
|
||||
delay(wait);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
setServoPos(10);
|
||||
delay(wait);
|
||||
setServoPos(110);
|
||||
delay(100);
|
||||
servo.stop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool G28(const char* msg, String buf, int serial) {
|
||||
bool stat = true;
|
||||
printResponse(msg, serial);
|
||||
if(buf.length()==0) {
|
||||
stat = moveHome(SELECTOR, false, true);
|
||||
if(stat)
|
||||
moveHome(REVOLVER, false, false);
|
||||
}
|
||||
else {
|
||||
if(buf.indexOf(X_Param) != -1) {
|
||||
stat = moveHome(SELECTOR, false, false);
|
||||
}
|
||||
if(buf.indexOf(Y_Param) != -1) {
|
||||
stat = moveHome(REVOLVER, false, false);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool G90(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
positionMode = ABSOLUTE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool G91(const char* msg, String buf, int serial) {
|
||||
printResponse(msg, serial);
|
||||
positionMode = RELATIVE;
|
||||
return true;
|
||||
}
|
||||
67
src/Gcodes.h
Normal file
67
src/Gcodes.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GCODES_H
|
||||
#define _GCODES_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
typedef struct {
|
||||
int code;
|
||||
bool (*func)(const char* msg, String buf, int serial);
|
||||
} GCodeFunctions;
|
||||
|
||||
extern unsigned int currentLine;
|
||||
|
||||
extern bool dummy(const char* msg, String buf, int serial);
|
||||
extern bool M18(const char* msg, String buf, int serial);
|
||||
extern bool M20(const char* msg, String buf, int serial);
|
||||
extern bool M42(const char* msg, String buf, int serial);
|
||||
extern bool M106(const char* msg, String buf, int serial);
|
||||
extern bool M107(const char* msg, String buf, int serial);
|
||||
extern bool M110(const char* msg, String buf, int serial);
|
||||
extern bool M111(const char* msg, String buf, int serial);
|
||||
extern bool M114(const char* msg, String buf, int serial);
|
||||
extern bool M115(const char* msg, String buf, int serial);
|
||||
extern bool M117(const char* msg, String buf, int serial);
|
||||
extern bool M119(const char* msg, String buf, int serial);
|
||||
extern bool M201(const char* msg, String buf, int serial);
|
||||
extern bool M203(const char* msg, String buf, int serial);
|
||||
extern bool M206(const char* msg, String buf, int serial);
|
||||
extern bool M250(const char* msg, String buf, int serial);
|
||||
extern bool M280(const char* msg, String buf, int serial);
|
||||
extern bool M300(const char* msg, String buf, int serial);
|
||||
extern bool M500(const char* msg, String buf, int serial);
|
||||
extern bool M503(const char* msg, String buf, int serial);
|
||||
extern bool M700(const char* msg, String buf, int serial);
|
||||
extern bool M701(const char* msg, String buf, int serial);
|
||||
extern bool M999(const char* msg, String buf, int serial);
|
||||
extern bool M2000(const char* msg, String buf, int serial);
|
||||
extern bool M2001(const char* msg, String buf, int serial);
|
||||
|
||||
extern bool G0(const char* msg, String buf, int serial);
|
||||
extern bool G1(const char* msg, String buf, int serial);
|
||||
extern bool G4(const char* msg, String buf, int serial);
|
||||
extern bool G12(const char* msg, String buf, int serial);
|
||||
extern bool G28(const char* msg, String buf, int serial);
|
||||
extern bool G90(const char* msg, String buf, int serial);
|
||||
extern bool G91(const char* msg, String buf, int serial);
|
||||
|
||||
#endif
|
||||
55
src/SMUFF.CFG
Normal file
55
src/SMUFF.CFG
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"Serial1Baudrate": 250000,
|
||||
"Serial2Baudrate": 38400,
|
||||
"SerialDueBaudrate": 56700,
|
||||
"ToolCount": 5,
|
||||
"BowdenLength": 620.0,
|
||||
"LCDContrast": 190,
|
||||
"I2CAddress": 0x88,
|
||||
"MenuAutoClose": 20,
|
||||
"FanSpeed": 50,
|
||||
"DelayBetweenPulses": false,
|
||||
"PowerSaveTimeout": 300,
|
||||
"DuetDirect": true,
|
||||
|
||||
"Selector": {
|
||||
"Offset": 0.5,
|
||||
"Spacing": 21.0,
|
||||
"StepsPerMillimeter": 800,
|
||||
"Acceleration": 900,
|
||||
"MaxSpeed": 100,
|
||||
"InvertDir": false,
|
||||
"EndstopTrigger": 1
|
||||
},
|
||||
"Revolver": {
|
||||
"StepsPerRevolution": 9600,
|
||||
"Offset": 1275,
|
||||
"Acceleration": 6000,
|
||||
"MaxSpeed": 1000,
|
||||
"ResetBeforeFeed": true,
|
||||
"HomeAfterFeed": true,
|
||||
"InvertDir": false,
|
||||
"EndstopTrigger": 1
|
||||
},
|
||||
"Feeder": {
|
||||
"ExternalControl": true,
|
||||
"StepsPerMillimeter": 410,
|
||||
"Acceleration": 1000,
|
||||
"MaxSpeed": 50,
|
||||
"InsertSpeed": 1000,
|
||||
"ReinforceLength": 2.0,
|
||||
"UnloadRetract": 0,
|
||||
"UnloadPushback": 0,
|
||||
"PushbackDelay": 2.0,
|
||||
"InvertDir": true,
|
||||
"EndstopTrigger": 1
|
||||
},
|
||||
"Materials": {
|
||||
"Tool0": "PLA Green",
|
||||
"Tool1": "PLA White",
|
||||
"Tool2": "PLA Red",
|
||||
"Tool3": "PLA Black",
|
||||
"Tool4": "PLA Silver"
|
||||
}
|
||||
}
|
||||
|
||||
659
src/SMuFF.cpp
Normal file
659
src/SMuFF.cpp
Normal file
@@ -0,0 +1,659 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "SMuFF.h"
|
||||
#include "Config.h"
|
||||
#include "ZTimerLib.h"
|
||||
#include "ZStepperLib.h"
|
||||
#include "ZServo.h"
|
||||
|
||||
ZStepper steppers[NUM_STEPPERS];
|
||||
ZTimer stepperTimer;
|
||||
ZServo servo;
|
||||
U8G2_ST7565_64128N_F_4W_HW_SPI display(U8G2_R2, /* cs=*/ DSP_CS_PIN, /* dc=*/ DSP_DC_PIN, /* reset=*/ DSP_RESET_PIN);
|
||||
Encoder encoder(ENCODER1_PIN, ENCODER2_PIN);
|
||||
|
||||
volatile byte nextStepperFlag = 0;
|
||||
volatile byte remainingSteppersFlag = 0;
|
||||
volatile unsigned long lastEncoderButtonTime = 0;
|
||||
bool testMode = false;
|
||||
int toolSelections[MAX_TOOLS];
|
||||
unsigned long pwrSaveTime;
|
||||
bool isPwrSave = false;
|
||||
|
||||
String serialBuffer0, serialBuffer2, serialBuffer9;
|
||||
String mainList;
|
||||
String toolsList;
|
||||
String offsetsList;
|
||||
String swapList;
|
||||
String traceSerial2;
|
||||
char tmp[128];
|
||||
|
||||
extern char _title[128];
|
||||
extern int swapTools[MAX_TOOLS];
|
||||
|
||||
void isrTimerHandler(); // forward declarations ... make every compiler happy
|
||||
void setPwrSave(int state);
|
||||
bool checkUserMessage();
|
||||
void showMainMenu();
|
||||
void showToolsMenu();
|
||||
void showOffsetsMenu();
|
||||
void showSwapMenu();
|
||||
void changeOffset(int index);
|
||||
void drawOffsetPosition(int index);
|
||||
void drawSwapTool(int from, int with);
|
||||
uint8_t swapTool(uint8_t index);
|
||||
|
||||
void overrideStepX() {
|
||||
STEP_HIGH_X
|
||||
// if(smuffConfig.delayBetweenPulses) __asm__ volatile ("nop");
|
||||
STEP_LOW_X
|
||||
}
|
||||
|
||||
void overrideStepY() {
|
||||
STEP_HIGH_Y
|
||||
// if(smuffConfig.delayBetweenPulses) __asm__ volatile ("nop");
|
||||
STEP_LOW_Y
|
||||
}
|
||||
|
||||
void overrideStepZ() {
|
||||
STEP_HIGH_Z
|
||||
// if(smuffConfig.delayBetweenPulses) __asm__ volatile ("nop");
|
||||
STEP_LOW_Z
|
||||
}
|
||||
|
||||
void endstopYevent() {
|
||||
//__debug("Endstop Revolver: %d", steppers[REVOLVER].getStepPosition());
|
||||
}
|
||||
|
||||
void endstopZevent() {
|
||||
//__debug("Endstop Revolver: %d", steppers[REVOLVER].getStepPosition());
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
serialBuffer0.reserve(80);
|
||||
serialBuffer2.reserve(80);
|
||||
serialBuffer9.reserve(80);
|
||||
|
||||
Serial.begin(57600); // set fixed baudrate until config file was read
|
||||
setupDisplay();
|
||||
readConfig();
|
||||
|
||||
Serial.begin(smuffConfig.serial1Baudrate);
|
||||
Serial2.begin(smuffConfig.serial2Baudrate);
|
||||
|
||||
steppers[SELECTOR] = ZStepper(SELECTOR, (char*)"Selector", X_STEP_PIN, X_DIR_PIN, X_ENABLE_PIN, smuffConfig.acceleration_X, smuffConfig.maxSpeed_X);
|
||||
steppers[SELECTOR].setEndstop(X_END_PIN, smuffConfig.endstopTrigger_X, ZStepper::MIN);
|
||||
steppers[SELECTOR].stepFunc = overrideStepX;
|
||||
steppers[SELECTOR].setMaxStepCount(smuffConfig.maxSteps_X);
|
||||
steppers[SELECTOR].setStepsPerMM(smuffConfig.stepsPerMM_X);
|
||||
steppers[SELECTOR].setInvertDir(smuffConfig.invertDir_X);
|
||||
|
||||
steppers[REVOLVER] = ZStepper(REVOLVER, (char*)"Revolver", Y_STEP_PIN, Y_DIR_PIN, Y_ENABLE_PIN, smuffConfig.acceleration_Y, smuffConfig.maxSpeed_Y);
|
||||
steppers[REVOLVER].setEndstop(Y_END_PIN, smuffConfig.endstopTrigger_Y, ZStepper::ORBITAL);
|
||||
steppers[REVOLVER].stepFunc = overrideStepY;
|
||||
steppers[REVOLVER].setMaxStepCount(smuffConfig.stepsPerRevolution_Y);
|
||||
steppers[REVOLVER].endstopFunc = endstopYevent;
|
||||
steppers[REVOLVER].setInvertDir(smuffConfig.invertDir_Y);
|
||||
|
||||
steppers[FEEDER] = ZStepper(FEEDER, (char*)"Feeder", Z_STEP_PIN, Z_DIR_PIN, Z_ENABLE_PIN, smuffConfig.acceleration_Z, smuffConfig.maxSpeed_Z);
|
||||
steppers[FEEDER].setEndstop(Z_END_PIN, smuffConfig.endstopTrigger_Z, ZStepper::MIN);
|
||||
steppers[FEEDER].stepFunc = overrideStepZ;
|
||||
steppers[FEEDER].setStepsPerMM(smuffConfig.stepsPerMM_Z);
|
||||
steppers[FEEDER].endstopFunc = endstopZevent;
|
||||
steppers[FEEDER].setInvertDir(smuffConfig.invertDir_Z);
|
||||
|
||||
stepperTimer.setupTimer(ZTimer::TIMER4, ZTimer::PRESCALER1);
|
||||
stepperTimer.setupTimerHook(isrTimerHandler);
|
||||
|
||||
getEepromData();
|
||||
//__debug("DONE reading EEPROM");
|
||||
|
||||
char menu[256];
|
||||
sprintf_P(menu, P_MenuItemBack);
|
||||
strcat_P(menu, P_MenuItems);
|
||||
mainList = String(menu);
|
||||
//__debug("DONE setting Main menu");
|
||||
sprintf_P(menu, P_MenuItemBack);
|
||||
strcat_P(menu, P_OfsMenuItems);
|
||||
offsetsList = String(menu);
|
||||
|
||||
|
||||
for(int i=0; i < NUM_STEPPERS; i++) {
|
||||
steppers[i].runAndWaitFunc = runAndWait;
|
||||
steppers[i].runNoWaitFunc = runNoWait;
|
||||
steppers[i].setEnabled(true);
|
||||
}
|
||||
//__debug("DONE enabling steppers");
|
||||
|
||||
for(int i=0; i < MAX_TOOLS; i++) {
|
||||
swapTools[i] = i;
|
||||
}
|
||||
|
||||
servo.attach(SERVO1_PIN);
|
||||
pinMode(FAN_PIN, OUTPUT);
|
||||
if(smuffConfig.fanSpeed > 0 && smuffConfig.fanSpeed <= 255)
|
||||
analogWrite(FAN_PIN, smuffConfig.fanSpeed);
|
||||
|
||||
if(smuffConfig.i2cAddress != 0) {
|
||||
Wire.begin(smuffConfig.i2cAddress);
|
||||
Wire.onReceive(wireReceiveEvent);
|
||||
}
|
||||
//__debug("DONE I2C init");
|
||||
|
||||
resetRevolver();
|
||||
//__debug("DONE reset Revolver");
|
||||
|
||||
//servo.setServoPos(0);
|
||||
sendStartResponse(0);
|
||||
//sendStartResponse(2);
|
||||
pwrSaveTime = millis();
|
||||
}
|
||||
|
||||
void setupToolsMenu() {
|
||||
char menu[256];
|
||||
sprintf_P(menu, P_MenuItemBack);
|
||||
memset(toolSelections, 0, sizeof(int)*MAX_TOOLS);
|
||||
int n = 0;
|
||||
for(int i=0; i< smuffConfig.toolCount; i++) {
|
||||
if(i == toolSelected)
|
||||
continue;
|
||||
toolSelections[n] = i;
|
||||
sprintf_P(tmp, P_ToolMenu, i);
|
||||
strcat(menu, tmp);
|
||||
strcat(menu, (char*)"\n");
|
||||
n++;
|
||||
}
|
||||
menu[strlen(menu)-1] = '\0';
|
||||
toolsList = String(menu);
|
||||
}
|
||||
|
||||
void setupSwapMenu() {
|
||||
char menu[256];
|
||||
sprintf_P(menu, P_MenuItemBack);
|
||||
sprintf_P(tmp, P_SwapReset);
|
||||
strcat(menu, tmp);
|
||||
for(int i=0; i< smuffConfig.toolCount; i++) {
|
||||
sprintf_P(tmp, P_SwapMenu, i, swapTools[i]);
|
||||
strcat(menu, tmp);
|
||||
strcat(menu, (char*)"\n");
|
||||
}
|
||||
menu[strlen(menu)-1] = '\0';
|
||||
swapList = String(menu);
|
||||
}
|
||||
|
||||
void setNextInterruptInterval() {
|
||||
|
||||
unsigned int minDuration = 65535;
|
||||
for(int i = 0; i < NUM_STEPPERS; i++) {
|
||||
if((_BV(i) & remainingSteppersFlag) && steppers[i].getDuration() < minDuration ) {
|
||||
minDuration = steppers[i].getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
nextStepperFlag = 0;
|
||||
for(int i = 0; i < NUM_STEPPERS; i++) {
|
||||
|
||||
if ( (_BV(i) & remainingSteppersFlag) && steppers[i].getDuration() == minDuration )
|
||||
nextStepperFlag |= _BV(i);
|
||||
}
|
||||
|
||||
if (remainingSteppersFlag == 0) {
|
||||
stepperTimer.setOCRxA(65500);
|
||||
}
|
||||
//__debug("minDuration: %d", minDuration);
|
||||
stepperTimer.setNextInterruptInterval(minDuration);
|
||||
}
|
||||
|
||||
|
||||
void isrTimerHandler() {
|
||||
unsigned int tmp = stepperTimer.getOCRxA();
|
||||
stepperTimer.setOCRxA(65500);
|
||||
|
||||
for (int i = 0; i < NUM_STEPPERS; i++) {
|
||||
if(!(_BV(i) & remainingSteppersFlag))
|
||||
continue;
|
||||
|
||||
if(!(nextStepperFlag & _BV(i))) {
|
||||
steppers[i].setDuration(steppers[i].getDuration() - tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
steppers[i].handleISR();
|
||||
if(steppers[i].getMovementDone())
|
||||
remainingSteppersFlag &= ~_BV(i);
|
||||
}
|
||||
//__debug("ISR(): %d", remainingSteppersFlag);
|
||||
setNextInterruptInterval();
|
||||
}
|
||||
|
||||
void runNoWait(int index) {
|
||||
if(index != -1)
|
||||
remainingSteppersFlag |= _BV(index);
|
||||
setNextInterruptInterval();
|
||||
}
|
||||
|
||||
void runAndWait(int index) {
|
||||
runNoWait(index);
|
||||
while(remainingSteppersFlag);
|
||||
}
|
||||
|
||||
static int lastTurn;
|
||||
static bool showMenu = false;
|
||||
static bool lastZEndstopState = 0;
|
||||
static unsigned long lastDisplayRefresh = 0;
|
||||
|
||||
void loop() {
|
||||
|
||||
if(feederEndstop() != lastZEndstopState) {
|
||||
lastZEndstopState = feederEndstop();
|
||||
bool state = feederEndstop();
|
||||
setSignalPort(FEEDER_SIGNAL, state);
|
||||
delay(200);
|
||||
setSignalPort(FEEDER_SIGNAL, !state);
|
||||
delay(200);
|
||||
setSignalPort(FEEDER_SIGNAL, state);
|
||||
}
|
||||
//__debug("Mem: %d", freeMemory());
|
||||
|
||||
if(!checkUserMessage()) {
|
||||
if(!isPwrSave) {
|
||||
if(millis()-lastDisplayRefresh > 500) { // refresh display every 500ms
|
||||
display.firstPage();
|
||||
do {
|
||||
drawLogo();
|
||||
drawStatus();
|
||||
} while(display.nextPage());
|
||||
lastDisplayRefresh = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(millis()-userMessageTime > USER_MESSAGE_RESET*1000) {
|
||||
displayingUserMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
int button = digitalRead(ENCODER_BUTTON_PIN);
|
||||
if(button == LOW && isPwrSave) {
|
||||
setPwrSave(0);
|
||||
}
|
||||
else {
|
||||
int turn = encoder.read();
|
||||
if(turn % ENCODER_DELAY_MENU == 0) {
|
||||
if(!showMenu && turn != lastTurn) {
|
||||
if(isPwrSave) {
|
||||
setPwrSave(0);
|
||||
}
|
||||
else {
|
||||
displayingUserMessage = false;
|
||||
showMenu = true;
|
||||
if(turn < lastTurn) {
|
||||
showMainMenu();
|
||||
}
|
||||
else {
|
||||
showToolsMenu();
|
||||
}
|
||||
turn = encoder.read();
|
||||
showMenu = false;
|
||||
}
|
||||
}
|
||||
lastTurn = turn;
|
||||
}
|
||||
}
|
||||
delay(10);
|
||||
if((millis() - pwrSaveTime)/1000 >= (unsigned long)smuffConfig.powerSaveTimeout && !isPwrSave) {
|
||||
//__debug("Power save mode after %d seconds (%d)", (millis() - pwrSaveTime)/1000, smuffConfig.powerSaveTimeout);
|
||||
setPwrSave(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setPwrSave(int state) {
|
||||
display.setPowerSave(state);
|
||||
isPwrSave = state == 1;
|
||||
if(!isPwrSave) {
|
||||
delay(2000);
|
||||
pwrSaveTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
bool checkUserMessage() {
|
||||
int button = digitalRead(ENCODER_BUTTON_PIN);
|
||||
if(button == LOW && displayingUserMessage) {
|
||||
displayingUserMessage = false;
|
||||
}
|
||||
if(millis()-userMessageTime > USER_MESSAGE_RESET*1000) {
|
||||
displayingUserMessage = false;
|
||||
//__debug("%ld", (millis()-userMessageTime)/1000);
|
||||
}
|
||||
return displayingUserMessage;
|
||||
}
|
||||
|
||||
void showMainMenu() {
|
||||
|
||||
bool stopMenu = false;
|
||||
unsigned int startTime = millis();
|
||||
uint8_t current_selection = 0;
|
||||
sprintf_P(_title, P_TitleMainMenu);
|
||||
do {
|
||||
resetAutoClose();
|
||||
while(checkUserMessage());
|
||||
current_selection = display.userInterfaceSelectionList(_title, current_selection, mainList.c_str());
|
||||
|
||||
if(current_selection == 0)
|
||||
return;
|
||||
|
||||
else {
|
||||
switch(current_selection) {
|
||||
case 1:
|
||||
stopMenu = true;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
moveHome(SELECTOR);
|
||||
moveHome(REVOLVER, true, false);
|
||||
startTime = millis();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
steppers[SELECTOR].setEnabled(false);
|
||||
steppers[REVOLVER].setEnabled(false);
|
||||
steppers[FEEDER].setEnabled(false);
|
||||
startTime = millis();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
showOffsetsMenu();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
loadFilament();
|
||||
startTime = millis();
|
||||
break;
|
||||
|
||||
case 6:
|
||||
unloadFilament();
|
||||
startTime = millis();
|
||||
break;
|
||||
|
||||
case 7:
|
||||
showSwapMenu();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (millis() - startTime > (unsigned long)smuffConfig.menuAutoClose * 1000) {
|
||||
stopMenu = true;
|
||||
}
|
||||
} while(!stopMenu);
|
||||
}
|
||||
|
||||
void drawSwapTool(int from, int with) {
|
||||
sprintf_P(tmp, P_SwapToolDialog, from, with);
|
||||
drawUserMessage(String(tmp));
|
||||
}
|
||||
|
||||
uint8_t swapTool(uint8_t index) {
|
||||
int turn = encoder.read();
|
||||
int lastTurn = 0;
|
||||
int lastButton = HIGH;
|
||||
int button;
|
||||
uint8_t ndx = 0;
|
||||
|
||||
while((button = digitalRead(ENCODER_BUTTON_PIN)) == LOW)
|
||||
delay(20);
|
||||
|
||||
drawSwapTool(index, ndx);
|
||||
|
||||
while(1) {
|
||||
|
||||
lastButton = button;
|
||||
button = digitalRead(ENCODER_BUTTON_PIN);
|
||||
if(button == LOW && lastButton == HIGH)
|
||||
break;
|
||||
turn = encoder.read();
|
||||
if(turn % ENCODER_DELAY_MENU == 0) {
|
||||
if(turn == lastTurn)
|
||||
continue;
|
||||
if(turn < lastTurn)
|
||||
ndx -= 1;
|
||||
else
|
||||
ndx += 1;
|
||||
|
||||
if(ndx >= smuffConfig.toolCount)
|
||||
ndx = 0;
|
||||
if(ndx < 0)
|
||||
ndx = smuffConfig.toolCount-1;
|
||||
lastTurn = turn;
|
||||
drawSwapTool(index, ndx);
|
||||
}
|
||||
}
|
||||
return ndx;
|
||||
}
|
||||
|
||||
void showSwapMenu() {
|
||||
bool stopMenu = false;
|
||||
uint8_t current_selection = 0;
|
||||
sprintf_P(_title, P_TitleSwapMenu);
|
||||
|
||||
do {
|
||||
setupSwapMenu();
|
||||
resetAutoClose();
|
||||
while(checkUserMessage());
|
||||
current_selection = display.userInterfaceSelectionList(_title, current_selection, swapList.c_str());
|
||||
|
||||
if(current_selection == 0)
|
||||
return;
|
||||
else if(current_selection == 1) {
|
||||
stopMenu = true;
|
||||
}
|
||||
else if(current_selection == 2) {
|
||||
for(int i=0; i < MAX_TOOLS; i++) {
|
||||
swapTools[i] = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint8_t tool = swapTool(current_selection-3);
|
||||
uint8_t tmp = swapTools[current_selection-3];
|
||||
swapTools[current_selection-3] = tool;
|
||||
swapTools[tool] = tmp;
|
||||
}
|
||||
} while(!stopMenu);
|
||||
}
|
||||
|
||||
|
||||
void showOffsetsMenu() {
|
||||
bool stopMenu = false;
|
||||
unsigned int startTime = millis();
|
||||
uint8_t current_selection = 0;
|
||||
sprintf_P(_title, P_TitleOffsetsMenu);
|
||||
|
||||
do {
|
||||
resetAutoClose();
|
||||
while(checkUserMessage());
|
||||
current_selection = display.userInterfaceSelectionList(_title, current_selection, offsetsList.c_str());
|
||||
|
||||
if(current_selection == 0)
|
||||
return;
|
||||
|
||||
else {
|
||||
switch(current_selection) {
|
||||
case 1:
|
||||
stopMenu = true;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
changeOffset(SELECTOR);
|
||||
startTime = millis();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
changeOffset(REVOLVER);
|
||||
startTime = millis();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (millis() - startTime > (unsigned long)smuffConfig.menuAutoClose * 1000) {
|
||||
stopMenu = true;
|
||||
}
|
||||
} while(!stopMenu);
|
||||
}
|
||||
|
||||
void changeOffset(int index) {
|
||||
int turn = encoder.read();
|
||||
int lastTurn = 0;
|
||||
int lastButton = HIGH;
|
||||
int button;
|
||||
int steps = (smuffConfig.stepsPerRevolution_Y / 360);
|
||||
float stepsF = 0.1f;
|
||||
|
||||
while((button = digitalRead(ENCODER_BUTTON_PIN)) == LOW)
|
||||
delay(20);
|
||||
|
||||
moveHome(index);
|
||||
long pos = steppers[index].getStepPosition();
|
||||
float posF = steppers[index].getStepPositionMM();
|
||||
|
||||
drawOffsetPosition(index);
|
||||
|
||||
while(1) {
|
||||
lastButton = button;
|
||||
button = digitalRead(ENCODER_BUTTON_PIN);
|
||||
if(button == LOW && lastButton == HIGH)
|
||||
break;
|
||||
turn = encoder.read();
|
||||
if(turn == lastTurn)
|
||||
continue;
|
||||
if(turn < lastTurn) {
|
||||
pos = -steps;
|
||||
posF = -stepsF;
|
||||
}
|
||||
else {
|
||||
pos = steps;
|
||||
posF = stepsF;
|
||||
}
|
||||
lastTurn = turn;
|
||||
if(index == REVOLVER) {
|
||||
prepSteppingRel(index, pos, true);
|
||||
}
|
||||
if(index == SELECTOR) {
|
||||
prepSteppingRelMillimeter(SELECTOR, posF, true);
|
||||
}
|
||||
runAndWait(index);
|
||||
drawOffsetPosition(index);
|
||||
}
|
||||
}
|
||||
|
||||
void drawOffsetPosition(int index) {
|
||||
if(index == REVOLVER) {
|
||||
sprintf(tmp, "%s\n%ld", steppers[index].getDescriptor(), steppers[index].getStepPosition());
|
||||
}
|
||||
if(index == SELECTOR) {
|
||||
sprintf(tmp, "%s\n%s", steppers[index].getDescriptor(), String(steppers[index].getStepPositionMM()).c_str());
|
||||
}
|
||||
drawUserMessage(String(tmp));
|
||||
}
|
||||
|
||||
void showToolsMenu() {
|
||||
|
||||
bool stopMenu = false;
|
||||
unsigned int startTime = millis();
|
||||
uint8_t current_selection = 0;
|
||||
sprintf_P(_title, P_TitleToolsMenu);
|
||||
do {
|
||||
setupToolsMenu();
|
||||
resetAutoClose();
|
||||
while(checkUserMessage());
|
||||
uint8_t startPos = toolSelected == 255 ? 0 : toolSelected+1;
|
||||
current_selection = display.userInterfaceSelectionList(_title, startPos, toolsList.c_str());
|
||||
|
||||
if(current_selection <= 1)
|
||||
stopMenu = true;
|
||||
else {
|
||||
int tool = toolSelections[current_selection-2];
|
||||
if(!smuffConfig.duetDirect) {
|
||||
selectTool(tool);
|
||||
}
|
||||
else {
|
||||
selectTool(tool);
|
||||
// TODO: do tool change using Duet3D
|
||||
// not yet possible due to Duet3D is being blocked waiting for endstop
|
||||
/*
|
||||
sprintf(tmp, "T%d\n", tool);
|
||||
Serial2.print(tmp);
|
||||
*/
|
||||
}
|
||||
startTime = millis();
|
||||
}
|
||||
if (millis() - startTime > (unsigned long)smuffConfig.menuAutoClose * 1000) {
|
||||
stopMenu = true;
|
||||
}
|
||||
} while(!stopMenu);
|
||||
}
|
||||
|
||||
void resetAutoClose() {
|
||||
lastEncoderButtonTime = millis();
|
||||
}
|
||||
|
||||
bool checkAutoClose() {
|
||||
//__debug("Home: %ld", millis()-lastEncoderButtonTime);
|
||||
if (millis() - lastEncoderButtonTime >= (unsigned long)smuffConfig.menuAutoClose*1000) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void serialEvent() {
|
||||
while (Serial.available()) {
|
||||
char in = (char)Serial.read();
|
||||
if (in == '\n') {
|
||||
//__debug("Received: %s", serialBuffer0.c_str());
|
||||
parseGcode(serialBuffer0, 0);
|
||||
serialBuffer0 = "";
|
||||
}
|
||||
else
|
||||
serialBuffer0 += in;
|
||||
}
|
||||
}
|
||||
|
||||
void serialEvent2() {
|
||||
while (Serial2.available()) {
|
||||
char in = (char)Serial2.read();
|
||||
Serial.write(in);
|
||||
if (in == '\n') {
|
||||
parseGcode(serialBuffer2, 2);
|
||||
traceSerial2 = String(serialBuffer2);
|
||||
serialBuffer2 = "";
|
||||
}
|
||||
else
|
||||
serialBuffer2 += in;
|
||||
}
|
||||
}
|
||||
|
||||
void wireReceiveEvent(int numBytes) {
|
||||
while (Wire.available()) {
|
||||
char in = (char)Wire.read();
|
||||
if (in == '\n') {
|
||||
parseGcode(serialBuffer9, 9);
|
||||
serialBuffer9 = "";
|
||||
}
|
||||
else
|
||||
serialBuffer9 += in;
|
||||
}
|
||||
}
|
||||
188
src/SMuFF.h
Normal file
188
src/SMuFF.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SMUFF_H
|
||||
#define _SMUFF_H
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
#include "Config.h"
|
||||
#include "Strings.h"
|
||||
#include "GCodes.h"
|
||||
#include "Encoder.h"
|
||||
#include <EEPROM.h>
|
||||
#include <Wire.h>
|
||||
#include <SD.h>
|
||||
#include "U8g2lib.h"
|
||||
#include "MemoryFree.h"
|
||||
|
||||
#define FEEDER_SIGNAL 1
|
||||
#define SELECTOR_SIGNAL 2
|
||||
#define REVOLVER_SIGNAL 3
|
||||
#define LED_SIGNAL 4
|
||||
|
||||
typedef enum {
|
||||
ABSOLUTE,
|
||||
RELATIVE
|
||||
} PositionMode;
|
||||
|
||||
typedef struct {
|
||||
int toolCount = 5;
|
||||
float firstToolOffset = FIRST_TOOL_OFFSET;
|
||||
float toolSpacing = TOOL_SPACING;
|
||||
int firstRevolverOffset = FIRST_REVOLVER_OFFSET;
|
||||
int revolverSpacing = REVOLVER_SPACING;
|
||||
long stepsPerMM_X = X_STEPS_PER_MM;
|
||||
long maxSteps_X = 68000;
|
||||
int maxSpeed_X = 10;
|
||||
int acceleration_X = 510;
|
||||
bool invertDir_X = false;
|
||||
int endstopTrigger_X = HIGH;
|
||||
|
||||
long stepsPerRevolution_Y= 9600;
|
||||
long maxSteps_Y = 9600;
|
||||
int maxSpeed_Y = 800;
|
||||
int acceleration_Y = 2000;
|
||||
bool resetBeforeFeed_Y = true;
|
||||
bool invertDir_Y = false;
|
||||
int endstopTrigger_Y = HIGH;
|
||||
|
||||
bool externalControl_Z = false;
|
||||
long stepsPerMM_Z = Z_STEPS_PER_MM;
|
||||
int maxSpeed_Z = 10;
|
||||
int insertSpeed_Z = 1000;
|
||||
int acceleration_Z = 300;
|
||||
bool invertDir_Z = false;
|
||||
int endstopTrigger_Z = LOW;
|
||||
|
||||
float unloadRetract = -20.0f;
|
||||
float unloadPushback = 5.0f;
|
||||
float pushbackDelay = 1.5f;
|
||||
float reinforceLength = 3.0f;
|
||||
bool homeAfterFeed = true;
|
||||
float bowdenLength = 400.0f;
|
||||
int i2cAddress = 0x58;
|
||||
int lcdContrast = DSP_CONTRAST;
|
||||
int menuAutoClose = 20;
|
||||
bool delayBetweenPulses = false;
|
||||
unsigned long serial1Baudrate = 57600;
|
||||
unsigned long serial2Baudrate = 57600;
|
||||
unsigned long serialDueBaudrate = 57600;
|
||||
bool duetDirect = false;
|
||||
int fanSpeed = 0;
|
||||
char materials[MAX_TOOLS][20];
|
||||
long powerSaveTimeout = 300;
|
||||
char unloadCommand[80] = {{ 0 }};
|
||||
int wipeSequence[20] = { 150,20,45,20,45,20,45,20,45,20,45,20,45,20,45,20,45,20,110,-1 };
|
||||
} SMuFFConfig;
|
||||
|
||||
extern U8G2_ST7565_64128N_F_4W_HW_SPI display;
|
||||
extern Encoder encoder;
|
||||
|
||||
extern SMuFFConfig smuffConfig;
|
||||
extern GCodeFunctions gCodeFuncsM[];
|
||||
extern GCodeFunctions gCodeFuncsG[];
|
||||
|
||||
extern const char brand[];
|
||||
extern volatile byte nextStepperFlag;
|
||||
extern volatile byte remainingSteppersFlag;
|
||||
extern volatile unsigned long lastEncoderButtonTime;
|
||||
extern char buf[];
|
||||
extern byte toolSelected;
|
||||
extern PositionMode positionMode;
|
||||
extern String serialBuffer0, serialBuffer2, serialBuffer3, serialBuffer9, traceSerial2;
|
||||
extern bool displayingUserMessage;
|
||||
extern unsigned int userMessageTime;
|
||||
extern bool testMode;
|
||||
extern bool feederJamed;
|
||||
extern bool parserBusy;
|
||||
extern bool isPwrSave;
|
||||
|
||||
extern void setupDisplay();
|
||||
extern void drawLogo();
|
||||
extern void drawStatus();
|
||||
extern void drawSelectingMessage();
|
||||
extern void drawUserMessage(String message);
|
||||
extern void drawSDStatus(int stat);
|
||||
extern void resetDisplay();
|
||||
extern bool selectorEndstop();
|
||||
extern bool revolverEndstop();
|
||||
extern bool feederEndstop();
|
||||
extern bool showFeederLoadedMessage();
|
||||
extern bool showFeederLoadMessage();
|
||||
extern bool showFeederFailedMessage(int state);
|
||||
extern int showDialog(PGM_P title, PGM_P message, PGM_P addMessage, PGM_P buttons);
|
||||
extern bool moveHome(int index, bool showMessage = true, bool checkFeeder = true);
|
||||
extern bool loadFilament(bool showMessage = true);
|
||||
extern bool unloadFilament();
|
||||
extern void runAndWait(int index);
|
||||
extern void runNoWait(int index);
|
||||
extern bool selectTool(int ndx, bool showMessage = true);
|
||||
extern void setStepperSteps(int index, long steps, bool ignoreEndstop);
|
||||
extern void prepSteppingAbs(int index, long steps, bool ignoreEndstop = false);
|
||||
extern void prepSteppingAbsMillimeter(int index, float millimeter, bool ignoreEndstop = false);
|
||||
extern void prepSteppingRel(int index, long steps, bool ignoreEndstop = false);
|
||||
extern void prepSteppingRelMillimeter(int index, float millimeter, bool ignoreEndstop = false);
|
||||
extern void resetRevolver();
|
||||
extern void serialEvent();
|
||||
extern void serialEvent2();
|
||||
extern void wireReceiveEvent(int numBytes);
|
||||
extern void beep(int count);
|
||||
extern void longBeep(int count);
|
||||
extern void userBeep();
|
||||
extern void setSignalPort(int port, bool state);
|
||||
extern void signalNoTool();
|
||||
extern void signalLoadFilament();
|
||||
extern void signalUnloadFilament();
|
||||
extern void signalSelectorBusy();
|
||||
extern void signalSelectorReady();
|
||||
extern bool setServoPos(int degree);
|
||||
extern void getEepromData();
|
||||
extern void readConfig();
|
||||
extern bool checkAutoClose();
|
||||
extern void resetAutoClose();
|
||||
extern void listDir(File root, int numTabs, int serial);
|
||||
extern void setPwrSave(int state);
|
||||
extern void __debug(const char* fmt, ...);
|
||||
|
||||
extern void printEndstopState(int serial);
|
||||
extern void printPos(int index, int serial);
|
||||
extern void printAcceleration(int serial);
|
||||
extern void printSpeeds(int serial);
|
||||
extern void sendGList(int serial);
|
||||
extern void sendMList(int serial);
|
||||
extern void sendToolResponse(int serial);
|
||||
extern void sendStartResponse(int serial);
|
||||
extern void sendOkResponse(int serial);
|
||||
extern void sendErrorResponse(int serial, const char* msg = NULL);
|
||||
extern void sendErrorResponseP(int serial, const char* msg = NULL);
|
||||
extern void parseGcode(String serialBuffer, int serial);
|
||||
extern bool parse_G(String buf, int serial);
|
||||
extern bool parse_M(String buf, int serial);
|
||||
extern bool parse_T(String buf, int serial);
|
||||
extern int getParam(String buf, char* token);
|
||||
extern bool getParamString(String buf, char* token, char* dest, int bufLen);
|
||||
extern void prepStepping(int index, long param, bool Millimeter = true, bool ignoreEndstop = false);
|
||||
extern void saveSettings(int serial);
|
||||
extern void reportSettings(int serial);
|
||||
extern void printResponse(const char* response, int serial);
|
||||
extern void printResponseP(const char* response, int serial);
|
||||
extern void printOffsets(int serial);
|
||||
|
||||
#endif
|
||||
113
src/SMuFFBitmaps.h
Normal file
113
src/SMuFFBitmaps.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SMUFF_BITMAPS_H
|
||||
#define _SMUFF_BITMAPS_H
|
||||
|
||||
#define logo_width 128
|
||||
#define logo_height 64
|
||||
static const unsigned char logo_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0xE0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x1F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xE0, 0x07, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0xC0, 0x07, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
|
||||
0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
|
||||
0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x03, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE0, 0x81, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x1C, 0x00,
|
||||
0xFC, 0x81, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x10, 0x70, 0x00, 0xFF, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0x60, 0x1C, 0xFF, 0x0F, 0x0E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x06, 0x90, 0xFF,
|
||||
0xFE, 0x1F, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1C, 0x03, 0xE8, 0xFF, 0xFE, 0x1F, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1C, 0x01, 0xE8, 0xFF, 0xFD, 0x3F, 0x1C, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x00, 0xF4, 0xFF,
|
||||
0xFD, 0x7F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x8E, 0x00, 0xF4, 0xFF, 0xFD, 0x7F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0xFA, 0xFF, 0xFF, 0x7F, 0x30, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x01, 0xFA, 0xFF,
|
||||
0xFF, 0x3F, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x01, 0xFA, 0xCF, 0xFF, 0x3F, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0xEA, 0xEF, 0xFF, 0x3F, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0xF2, 0xFF,
|
||||
0xFF, 0x9F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0xF4, 0xFF, 0xFF, 0xC7, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0xF4, 0xFF, 0xFF, 0xF1, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, 0xFA, 0xFF,
|
||||
0xFF, 0xFC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x20, 0xFA, 0xFF, 0x7F, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x40, 0xFA, 0xFF, 0xFF, 0xFF, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0xFA, 0xFF,
|
||||
0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0xFB, 0xC7, 0xFF, 0xFF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFA, 0xE3, 0xFF, 0x7F, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x10, 0xFA, 0xE3,
|
||||
0xFF, 0x7F, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0xC0, 0xFF, 0xF0, 0xFF, 0x7F, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x7F, 0xF8, 0xFF, 0x3F, 0x70, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xFC,
|
||||
0xFF, 0x3F, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0E, 0x00, 0xFF, 0xFD, 0xFF, 0x1F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0xFD, 0xFF, 0x0F, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x08, 0xFD,
|
||||
0xFF, 0x07, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1C, 0x00, 0x08, 0xFA, 0x7F, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x10, 0xFA, 0x3F, 0x82, 0x4E, 0x00,
|
||||
0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x10, 0xF6,
|
||||
0x9F, 0xEF, 0xCC, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x00, 0x20, 0xE4, 0xDF, 0xC8, 0xE5, 0x00, 0x0C, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x40, 0xC8, 0xC3, 0xC1, 0x71, 0x00,
|
||||
0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x80, 0x30,
|
||||
0x80, 0xC1, 0x73, 0xE4, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x03, 0x00, 0x21, 0x80, 0xC7, 0x7F, 0xEC, 0x7E, 0x3F, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x26, 0x00, 0xCF, 0x7E, 0xC6,
|
||||
0x7E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x38,
|
||||
0x00, 0xCE, 0x6C, 0xC6, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1E, 0x00, 0x20, 0x00, 0xDC, 0x64, 0xC6, 0x0C, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xDC, 0x60, 0xC6,
|
||||
0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00,
|
||||
0xC0, 0xCE, 0x60, 0xEE, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xE0, 0x07, 0x00, 0xC0, 0xC7, 0x61, 0xFC, 0x0E, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x9F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF,
|
||||
0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, };
|
||||
|
||||
#endif
|
||||
730
src/SMuFFtools.cpp
Normal file
730
src/SMuFFtools.cpp
Normal file
@@ -0,0 +1,730 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module containing helper functions
|
||||
*/
|
||||
|
||||
#include "SMuFF.h"
|
||||
#include "SMuFFBitmaps.h"
|
||||
#include "Config.h"
|
||||
#include "ZTimerLib.h"
|
||||
#include "ZStepperLib.h"
|
||||
#include "ZServo.h"
|
||||
|
||||
extern ZStepper steppers[];
|
||||
extern ZServo servo;
|
||||
extern char tmp[128];
|
||||
|
||||
SMuFFConfig smuffConfig;
|
||||
int lastEncoderTurn = 0;
|
||||
byte toolSelected = -1;
|
||||
bool feederJamed = false;
|
||||
PositionMode positionMode = RELATIVE;
|
||||
bool displayingUserMessage = false;
|
||||
unsigned int userMessageTime = 0;
|
||||
char _sel[128];
|
||||
char _wait[128];
|
||||
char _title[128];
|
||||
char _msg1[256];
|
||||
char _msg2[128];
|
||||
char _btn[128];
|
||||
int swapTools[MAX_TOOLS];
|
||||
|
||||
|
||||
const char brand[] = VERSION_STRING;
|
||||
|
||||
void setupDisplay() {
|
||||
display.begin(/*Select=*/ ENCODER_BUTTON_PIN, /* menu_next_pin= */ U8X8_PIN_NONE, /* menu_prev_pin= */ U8X8_PIN_NONE, /* menu_home_pin= */ U8X8_PIN_NONE);
|
||||
display.enableUTF8Print();
|
||||
resetDisplay();
|
||||
if (smuffConfig.lcdContrast < MIN_CONTRAST || smuffConfig.lcdContrast > MAX_CONTRAST) {
|
||||
smuffConfig.lcdContrast = DSP_CONTRAST;
|
||||
EEPROM.put(EEPROM_CONTRAST, smuffConfig.lcdContrast);
|
||||
}
|
||||
display.setContrast(smuffConfig.lcdContrast);
|
||||
}
|
||||
|
||||
void drawLogo() {
|
||||
display.setBitmapMode(1);
|
||||
display.drawXBMP(0, 0, logo_width, logo_height, logo_bits);
|
||||
display.setFont(LOGO_FONT);
|
||||
display.setFontMode(0);
|
||||
display.setFontDirection(0);
|
||||
display.setDrawColor(1);
|
||||
display.setCursor(display.getDisplayWidth() - display.getStrWidth(brand) - 1, display.getDisplayHeight() - display.getMaxCharHeight());
|
||||
display.print(brand);
|
||||
}
|
||||
|
||||
void drawStatus() {
|
||||
display.setFont(STATUS_FONT);
|
||||
display.setFontMode(0);
|
||||
display.setDrawColor(1);
|
||||
sprintf_P(tmp, P_CurrentTool);
|
||||
display.drawStr(display.getDisplayWidth() - display.getStrWidth(tmp) - 5, 14, tmp);
|
||||
display.drawStr(display.getDisplayWidth() - display.getStrWidth("X") - 5, 14, (toolSelected >= 0 && toolSelected < smuffConfig.toolCount) ? String(toolSelected).c_str() : "-");
|
||||
sprintf_P(tmp, P_Feed);
|
||||
display.drawStr(display.getDisplayWidth() - display.getStrWidth(tmp) - 5, 34, tmp);
|
||||
display.setFontMode(1);
|
||||
display.setFont(SMALL_FONT);
|
||||
display.setDrawColor(2);
|
||||
display.drawBox(0, display.getDisplayHeight()-display.getMaxCharHeight()+2, display.getDisplayWidth(), display.getMaxCharHeight());
|
||||
sprintf_P(_wait, parserBusy ? P_Busy : P_Ready);
|
||||
sprintf(tmp, "M:%d | %-4s | %-5s ", freeMemory(), traceSerial2.c_str(), _wait);
|
||||
display.drawStr(1, display.getDisplayHeight(), tmp);
|
||||
display.setFontMode(0);
|
||||
display.setDrawColor(1);
|
||||
display.setFont(ICONIC_FONT);
|
||||
display.drawGlyph(110, 38, feederEndstop() ? 0x41 : 0x42);
|
||||
display.setFont(BASE_FONT);
|
||||
}
|
||||
|
||||
void resetDisplay() {
|
||||
display.clearDisplay();
|
||||
display.setFont(BASE_FONT);
|
||||
display.setFontMode(0);
|
||||
display.setDrawColor(1);
|
||||
}
|
||||
|
||||
void drawSelectingMessage(int tool) {
|
||||
display.firstPage();
|
||||
do {
|
||||
resetDisplay();
|
||||
sprintf_P(_sel, P_Selecting);
|
||||
sprintf_P(_wait, P_Wait);
|
||||
if(*smuffConfig.materials[tool] != 0) {
|
||||
sprintf(tmp,"%s", smuffConfig.materials[tool]);
|
||||
}
|
||||
else {
|
||||
sprintf_P(tmp, "%s%d", P_Tool, tool);
|
||||
}
|
||||
display.drawStr((display.getDisplayWidth() - display.getStrWidth(_sel))/2, (display.getDisplayHeight() - display.getMaxCharHeight())/2-10, _sel);
|
||||
display.setFont(BASE_FONT_BIG);
|
||||
display.drawStr((display.getDisplayWidth() - display.getStrWidth(tmp))/2, (display.getDisplayHeight() - display.getMaxCharHeight())/2+9, tmp);
|
||||
display.setFont(BASE_FONT);
|
||||
display.drawStr((display.getDisplayWidth() - display.getStrWidth(_wait))/2, (display.getDisplayHeight() - display.getMaxCharHeight())/2 + display.getMaxCharHeight()+10, _wait);
|
||||
} while(display.nextPage());
|
||||
}
|
||||
|
||||
int splitStringLines(char lines[][MAX_LINE_LENGTH], String message) {
|
||||
|
||||
for(int i=0; i < MAX_LINES; i++) {
|
||||
memset(&lines[i], 0, MAX_LINE_LENGTH);
|
||||
}
|
||||
|
||||
int pos2 = (message.indexOf('\n') == -1) ? message.length() : message.indexOf('\n');
|
||||
int ln = 0;
|
||||
|
||||
do {
|
||||
int len = (pos2 > MAX_LINE_LENGTH-1) ? MAX_LINE_LENGTH-1 : pos2+1;
|
||||
message.substring(0, pos2).toCharArray(lines[ln], len);
|
||||
if(ln >= MAX_LINES)
|
||||
break;
|
||||
ln++;
|
||||
message = message.substring(len);
|
||||
pos2 = message.indexOf('\n');
|
||||
if(pos2 == -1)
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
if(message.length()>0 && ln < MAX_LINES) {
|
||||
int len = message.length()+1;
|
||||
message.substring(0).toCharArray(lines[ln++], len);
|
||||
}
|
||||
return ln;
|
||||
}
|
||||
|
||||
void drawUserMessage(String message) {
|
||||
|
||||
char lines[MAX_LINES][MAX_LINE_LENGTH];
|
||||
int lineCnt = splitStringLines(lines, message);
|
||||
if(isPwrSave) {
|
||||
setPwrSave(0);
|
||||
}
|
||||
display.firstPage();
|
||||
do {
|
||||
resetDisplay();
|
||||
display.setFont(BASE_FONT_BIG);
|
||||
int y = (display.getDisplayHeight()-(lineCnt-1)*display.getMaxCharHeight())/2;
|
||||
display.firstPage();
|
||||
display.drawFrame(0, 0, display.getDisplayWidth(), display.getDisplayHeight());
|
||||
do {
|
||||
for(int i=0; i< lineCnt; i++) {
|
||||
display.drawStr((display.getDisplayWidth() - display.getStrWidth(lines[i]))/2, y, lines[i]);
|
||||
y += display.getMaxCharHeight();
|
||||
}
|
||||
} while(display.nextPage());
|
||||
display.setFont(BASE_FONT);
|
||||
} while(display.nextPage());
|
||||
displayingUserMessage = true;
|
||||
userMessageTime = millis();
|
||||
}
|
||||
|
||||
|
||||
void drawSDStatus(int stat) {
|
||||
resetDisplay();
|
||||
switch(stat) {
|
||||
case SD_ERR_INIT:
|
||||
sprintf_P(tmp, P_SD_InitError);
|
||||
longBeep(2);
|
||||
break;
|
||||
case SD_ERR_NOCONFIG:
|
||||
sprintf_P(tmp, P_SD_NoConfig);
|
||||
longBeep(1);
|
||||
break;
|
||||
case SD_READING_CONFIG:
|
||||
sprintf_P(tmp, P_SD_ReadingConfig);
|
||||
break;
|
||||
}
|
||||
display.firstPage();
|
||||
do {
|
||||
drawLogo();
|
||||
display.setCursor((display.getDisplayWidth() - display.getStrWidth(tmp))/2, display.getDisplayHeight());
|
||||
display.print(tmp);
|
||||
} while(display.nextPage());
|
||||
}
|
||||
|
||||
bool selectorEndstop() {
|
||||
return steppers[SELECTOR].getEndstopHit();
|
||||
}
|
||||
|
||||
bool revolverEndstop() {
|
||||
return steppers[REVOLVER].getEndstopHit();
|
||||
}
|
||||
|
||||
bool feederEndstop() {
|
||||
/*
|
||||
if(smuffConfig.externalControl_Z) {
|
||||
return steppers[FEEDER].getEndstopHitAlt();
|
||||
}
|
||||
*/
|
||||
return steppers[FEEDER].getEndstopHit();
|
||||
}
|
||||
|
||||
uint8_t u8x8_GetMenuEvent(u8x8_t *u8x8)
|
||||
{
|
||||
int stat = 0;
|
||||
int button = digitalRead(ENCODER_BUTTON_PIN);
|
||||
int turn = encoder.read();
|
||||
|
||||
if (button == LOW) {
|
||||
delay(20);
|
||||
button = digitalRead(ENCODER_BUTTON_PIN);
|
||||
if (button == LOW && u8x8->debounce_state == HIGH) {
|
||||
stat = U8X8_MSG_GPIO_MENU_SELECT;
|
||||
resetAutoClose();
|
||||
turn = encoder.read();
|
||||
lastEncoderTurn = turn;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (turn != lastEncoderTurn) {
|
||||
if (turn % ENCODER_DELAY == 0) {
|
||||
int delta = turn < lastEncoderTurn ? -1 : 1;
|
||||
lastEncoderTurn = turn;
|
||||
resetAutoClose();
|
||||
|
||||
switch (delta)
|
||||
{
|
||||
case 1:
|
||||
stat = U8X8_MSG_GPIO_MENU_NEXT;
|
||||
break;
|
||||
case -1:
|
||||
stat = U8X8_MSG_GPIO_MENU_PREV;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
u8x8->debounce_state = button;
|
||||
serialEvent();
|
||||
serialEvent2();
|
||||
//wireReceiveEvent(0);
|
||||
if(checkAutoClose()) {
|
||||
stat = U8X8_MSG_GPIO_MENU_HOME;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool moveHome(int index, bool showMessage, bool checkFeeder) {
|
||||
if(!steppers[index].getEnabled())
|
||||
steppers[index].setEnabled(true);
|
||||
|
||||
if(feederJamed) {
|
||||
beep(4);
|
||||
return false;
|
||||
}
|
||||
parserBusy = true;
|
||||
if (checkFeeder && feederEndstop()) {
|
||||
if (showMessage) {
|
||||
if (!showFeederLoadedMessage()) {
|
||||
parserBusy = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (feederEndstop()) {
|
||||
unloadFilament();
|
||||
}
|
||||
}
|
||||
}
|
||||
//__debug("Stepper home");
|
||||
steppers[index].home();
|
||||
//__debug("DONE Stepper home");
|
||||
if (index == SELECTOR) {
|
||||
toolSelected = -1;
|
||||
}
|
||||
long pos = steppers[index].getStepPosition();
|
||||
if (index == SELECTOR || index == REVOLVER) {
|
||||
EEPROM.update(EEPROM_TOOL, toolSelected);
|
||||
}
|
||||
EEPROM.put(index * sizeof(long), pos);
|
||||
parserBusy = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool showFeederLoadedMessage() {
|
||||
bool state = false;
|
||||
lastEncoderButtonTime = millis();
|
||||
beep(1);
|
||||
int button = showDialog(P_TitleWarning, P_FeederLoaded, P_AskUnload, P_YesNoButtons);
|
||||
if (button == 1) {
|
||||
drawStatus();
|
||||
unloadFilament();
|
||||
state = true;
|
||||
}
|
||||
display.clearDisplay();
|
||||
return state;
|
||||
}
|
||||
|
||||
bool showFeederLoadMessage() {
|
||||
bool state = false;
|
||||
lastEncoderButtonTime = millis();
|
||||
beep(1);
|
||||
int button = showDialog(P_TitleSelected, P_SelectedTool, P_AskLoad, P_YesNoButtons);
|
||||
if (button == 1) {
|
||||
drawStatus();
|
||||
loadFilament();
|
||||
state = true;
|
||||
}
|
||||
display.clearDisplay();
|
||||
return state;
|
||||
}
|
||||
|
||||
bool showFeederFailedMessage(int state) {
|
||||
lastEncoderButtonTime = millis();
|
||||
beep(3);
|
||||
showDialog(P_TitleWarning, state == 1 ? P_CantLoad : P_CantUnload, P_CheckUnit, P_OkButtonOnly);
|
||||
display.clearDisplay();
|
||||
return false;
|
||||
}
|
||||
|
||||
int showDialog(PGM_P title, PGM_P message, PGM_P addMessage, PGM_P buttons) {
|
||||
if(isPwrSave) {
|
||||
setPwrSave(0);
|
||||
}
|
||||
sprintf_P(_title, title);
|
||||
sprintf_P(_msg1, message);
|
||||
sprintf_P(_msg2, addMessage);
|
||||
sprintf_P(_btn, buttons);
|
||||
return display.userInterfaceMessage(_title, _msg1, _msg2, _btn);
|
||||
}
|
||||
|
||||
void signalNoTool() {
|
||||
userBeep();
|
||||
sprintf_P(_msg1, P_NoTool);
|
||||
strcat_P(_msg1, P_Aborting);
|
||||
drawUserMessage(_msg1);
|
||||
}
|
||||
|
||||
bool loadFilament(bool showMessage) {
|
||||
if (toolSelected == 255) {
|
||||
signalNoTool();
|
||||
return false;
|
||||
}
|
||||
if(smuffConfig.externalControl_Z) {
|
||||
resetRevolver();
|
||||
signalLoadFilament();
|
||||
return true;
|
||||
}
|
||||
parserBusy = true;
|
||||
if(!steppers[FEEDER].getEnabled())
|
||||
steppers[FEEDER].setEnabled(true);
|
||||
if(smuffConfig.resetBeforeFeed_Y)
|
||||
resetRevolver();
|
||||
int n = 100;
|
||||
unsigned int curSpeed = steppers[FEEDER].getMaxSpeed();
|
||||
steppers[FEEDER].setMaxSpeed(smuffConfig.insertSpeed_Z);
|
||||
while (!feederEndstop()) {
|
||||
prepSteppingRelMillimeter(FEEDER, 2.5, true);
|
||||
runAndWait(FEEDER);
|
||||
if (n == 50) {
|
||||
resetRevolver();
|
||||
prepSteppingRelMillimeter(FEEDER, -15.0, true);
|
||||
runAndWait(FEEDER);
|
||||
}
|
||||
if (n <= 0) {
|
||||
if (showMessage)
|
||||
showFeederFailedMessage(1);
|
||||
steppers[FEEDER].setMaxSpeed(curSpeed);
|
||||
feederJamed = true;
|
||||
parserBusy = false;
|
||||
return false;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
feederJamed = false;
|
||||
steppers[FEEDER].setMaxSpeed(curSpeed);
|
||||
prepSteppingRelMillimeter(FEEDER, smuffConfig.bowdenLength*.95, true);
|
||||
runAndWait(FEEDER);
|
||||
steppers[FEEDER].setMaxSpeed(smuffConfig.insertSpeed_Z);
|
||||
prepSteppingRelMillimeter(FEEDER, smuffConfig.bowdenLength*.05, true);
|
||||
runAndWait(FEEDER);
|
||||
|
||||
if(smuffConfig.reinforceLength > 0) {
|
||||
resetRevolver();
|
||||
prepSteppingRelMillimeter(FEEDER, smuffConfig.reinforceLength, true);
|
||||
runAndWait(FEEDER);
|
||||
}
|
||||
|
||||
steppers[FEEDER].setMaxSpeed(curSpeed);
|
||||
EEPROM.put(EEPROM_FEEDER_POS, steppers[FEEDER].getStepPosition());
|
||||
if(smuffConfig.homeAfterFeed)
|
||||
steppers[REVOLVER].home();
|
||||
parserBusy = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unloadFilament() {
|
||||
if (toolSelected == 255) {
|
||||
signalNoTool();
|
||||
return false;
|
||||
}
|
||||
if(smuffConfig.externalControl_Z) {
|
||||
signalUnloadFilament();
|
||||
return true;
|
||||
}
|
||||
parserBusy = true;
|
||||
if(!steppers[FEEDER].getEnabled())
|
||||
steppers[FEEDER].setEnabled(true);
|
||||
if(smuffConfig.resetBeforeFeed_Y)
|
||||
resetRevolver();
|
||||
unsigned int curSpeed = steppers[FEEDER].getMaxSpeed();
|
||||
steppers[FEEDER].setEndstopState(!steppers[FEEDER].getEndstopState());
|
||||
if(smuffConfig.unloadRetract != 0) {
|
||||
prepSteppingRelMillimeter(FEEDER, smuffConfig.unloadRetract);
|
||||
runAndWait(FEEDER);
|
||||
if(smuffConfig.unloadPushback != 0) {
|
||||
steppers[FEEDER].setMaxSpeed(smuffConfig.insertSpeed_Z);
|
||||
prepSteppingRelMillimeter(FEEDER, smuffConfig.unloadPushback);
|
||||
runAndWait(FEEDER);
|
||||
delay(smuffConfig.pushbackDelay*1000);
|
||||
steppers[FEEDER].setMaxSpeed(curSpeed);
|
||||
}
|
||||
}
|
||||
prepSteppingRelMillimeter(FEEDER, -(smuffConfig.bowdenLength*3));
|
||||
runAndWait(FEEDER);
|
||||
steppers[FEEDER].setMaxSpeed(smuffConfig.insertSpeed_Z);
|
||||
int n = 200;
|
||||
do {
|
||||
prepSteppingRelMillimeter(FEEDER, -20.0, true);
|
||||
runAndWait(FEEDER);
|
||||
if(!feederEndstop()) {
|
||||
if((n > 0 && n < 200) && n % 50 == 0) {
|
||||
resetRevolver();
|
||||
prepSteppingRelMillimeter(FEEDER, 15.0, true);
|
||||
runAndWait(FEEDER);
|
||||
}
|
||||
if (n <= 0) {
|
||||
showFeederFailedMessage(0);
|
||||
steppers[FEEDER].setMaxSpeed(curSpeed);
|
||||
feederJamed = true;
|
||||
parserBusy = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
n--;
|
||||
} while (!feederEndstop());
|
||||
feederJamed = false;
|
||||
steppers[FEEDER].setMaxSpeed(curSpeed);
|
||||
steppers[FEEDER].setEndstopState(!steppers[FEEDER].getEndstopState());
|
||||
steppers[FEEDER].setStepPosition(0);
|
||||
EEPROM.put(EEPROM_FEEDER_POS, steppers[FEEDER].getStepPosition());
|
||||
parserBusy = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool selectTool(int ndx, bool showMessage) {
|
||||
|
||||
ndx = swapTools[ndx];
|
||||
if(feederJamed) {
|
||||
beep(4);
|
||||
sprintf_P(_msg1, P_FeederJamed);
|
||||
strcat_P(_msg1, P_Aborting);
|
||||
drawUserMessage(_msg1);
|
||||
return false;
|
||||
}
|
||||
signalSelectorBusy();
|
||||
if(toolSelected == ndx) {
|
||||
if(!smuffConfig.externalControl_Z) {
|
||||
userBeep();
|
||||
sprintf_P(_msg1, P_ToolAlreadySet);
|
||||
drawUserMessage(_msg1);
|
||||
}
|
||||
if(smuffConfig.externalControl_Z) {
|
||||
//resetRevolver();
|
||||
signalSelectorReady();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!steppers[SELECTOR].getEnabled())
|
||||
steppers[SELECTOR].setEnabled(true);
|
||||
|
||||
if (showMessage) {
|
||||
while(feederEndstop()) {
|
||||
if (!showFeederLoadedMessage())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!smuffConfig.externalControl_Z && feederEndstop()) {
|
||||
unloadFilament();
|
||||
}
|
||||
else if (smuffConfig.externalControl_Z && feederEndstop()) {
|
||||
// TODO: Signal Duet3D to retract 2mm
|
||||
beep(4);
|
||||
char buf[] = {'Y'};
|
||||
while(feederEndstop()) {
|
||||
M18("M18", buf, 0);
|
||||
showFeederFailedMessage(0);
|
||||
if(smuffConfig.unloadCommand != NULL && strlen(smuffConfig.unloadCommand) > 0) {
|
||||
Serial2.print(smuffConfig.unloadCommand);
|
||||
Serial2.print("\n");
|
||||
__debug("Feeder jamed, sent unload command '%s'\n", smuffConfig.unloadCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//__debug("Selecting tool: %d", ndx);
|
||||
parserBusy = true;
|
||||
drawSelectingMessage(ndx);
|
||||
prepSteppingAbsMillimeter(SELECTOR, smuffConfig.firstToolOffset + (ndx * smuffConfig.toolSpacing));
|
||||
remainingSteppersFlag |= _BV(SELECTOR);
|
||||
if(!smuffConfig.resetBeforeFeed_Y) {
|
||||
prepSteppingAbs(REVOLVER, smuffConfig.firstRevolverOffset + (ndx *smuffConfig.revolverSpacing), true);
|
||||
remainingSteppersFlag |= _BV(REVOLVER);
|
||||
}
|
||||
runAndWait(-1);
|
||||
toolSelected = ndx;
|
||||
EEPROM.put(EEPROM_TOOL, toolSelected);
|
||||
for (int i = 0; i < NUM_STEPPERS; i++) {
|
||||
EEPROM.put(i * sizeof(long), steppers[i].getStepPosition());
|
||||
}
|
||||
if (!smuffConfig.externalControl_Z && showMessage) {
|
||||
showFeederLoadMessage();
|
||||
}
|
||||
if(smuffConfig.externalControl_Z) {
|
||||
resetRevolver();
|
||||
signalSelectorReady();
|
||||
}
|
||||
if(testMode)
|
||||
Serial2.print("T"); Serial2.println(ndx);
|
||||
parserBusy = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void resetRevolver() {
|
||||
//__debug("resetting revolver");
|
||||
moveHome(REVOLVER, false, false);
|
||||
//__debug("DONE resetting revolver");
|
||||
if (toolSelected > -1) {
|
||||
prepSteppingAbs(REVOLVER, smuffConfig.firstRevolverOffset + (toolSelected*smuffConfig.revolverSpacing), true);
|
||||
runAndWait(REVOLVER);
|
||||
}
|
||||
}
|
||||
|
||||
void setStepperSteps(int index, long steps, bool ignoreEndstop) {
|
||||
if (steps != 0)
|
||||
steppers[index].prepareMovement(steps, ignoreEndstop);
|
||||
}
|
||||
|
||||
void prepSteppingAbs(int index, long steps, bool ignoreEndstop) {
|
||||
long pos = steppers[index].getStepPosition();
|
||||
long _steps = steps - pos;
|
||||
setStepperSteps(index, _steps, ignoreEndstop);
|
||||
}
|
||||
|
||||
void prepSteppingAbsMillimeter(int index, float millimeter, bool ignoreEndstop) {
|
||||
unsigned int stepsPerMM = steppers[index].getStepsPerMM();
|
||||
long steps = (long)((float)millimeter * stepsPerMM);
|
||||
long pos = steppers[index].getStepPosition();
|
||||
setStepperSteps(index, steps - pos, ignoreEndstop);
|
||||
}
|
||||
|
||||
void prepSteppingRel(int index, long steps, bool ignoreEndstop) {
|
||||
setStepperSteps(index, steps, ignoreEndstop);
|
||||
}
|
||||
|
||||
void prepSteppingRelMillimeter(int index, float millimeter, bool ignoreEndstop) {
|
||||
unsigned int stepsPerMM = steppers[index].getStepsPerMM();
|
||||
long steps = (long)((float)millimeter * stepsPerMM);
|
||||
setStepperSteps(index, steps, ignoreEndstop);
|
||||
}
|
||||
|
||||
void printEndstopState(int serial) {
|
||||
sprintf(tmp, "Selector: %s\tRevolver: %s\tFeeder: %s\n",
|
||||
selectorEndstop() ? "triggered" : "open",
|
||||
revolverEndstop() ? "triggered" : "open",
|
||||
feederEndstop() ? "triggered" : "open");
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
|
||||
void printSpeeds(int serial) {
|
||||
sprintf_P(tmp, P_AccelSpeed,
|
||||
String(steppers[SELECTOR].getMaxSpeed()).c_str(),
|
||||
String(steppers[REVOLVER].getMaxSpeed()).c_str(),
|
||||
smuffConfig.externalControl_Z ? "external" : String(steppers[FEEDER].getMaxSpeed()).c_str());
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
|
||||
void printAcceleration(int serial) {
|
||||
sprintf_P(tmp, P_AccelSpeed,
|
||||
String(steppers[SELECTOR].getAcceleration()).c_str(),
|
||||
String(steppers[REVOLVER].getAcceleration()).c_str(),
|
||||
smuffConfig.externalControl_Z ? "external" : String(steppers[FEEDER].getAcceleration()).c_str());
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
|
||||
void printOffsets(int serial) {
|
||||
sprintf_P(tmp, P_AccelSpeed,
|
||||
String((int)(smuffConfig.firstToolOffset*10)).c_str(),
|
||||
String(smuffConfig.firstRevolverOffset).c_str(),
|
||||
"--");
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
|
||||
void printPos(int index, int serial) {
|
||||
sprintf(buf, "Pos. '%s': %ld\n", steppers[index].getDescriptor(), steppers[index].getStepPosition());
|
||||
printResponse(buf, serial);
|
||||
}
|
||||
|
||||
void beep(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
tone(BEEPER_PIN, BEEPER_FREQUENCY, BEEPER_DURATION);
|
||||
delay(BEEPER_DURATION*2);
|
||||
}
|
||||
}
|
||||
|
||||
void longBeep(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
tone(BEEPER_PIN, BEEPER_FREQUENCY, BEEPER_DURATION*5);
|
||||
delay(BEEPER_DURATION*5+50);
|
||||
}
|
||||
}
|
||||
|
||||
void userBeep() {
|
||||
tone(BEEPER_PIN, BEEPER_FREQUENCY, BEEPER_DURATION);
|
||||
delay(BEEPER_DURATION*2);
|
||||
tone(BEEPER_PIN, BEEPER_UFREQUENCY, BEEPER_UDURATION);
|
||||
delay(BEEPER_UDURATION*2);
|
||||
tone(BEEPER_PIN, BEEPER_UFREQUENCY, BEEPER_UDURATION);
|
||||
}
|
||||
|
||||
bool setServoPos(int degree) {
|
||||
return servo.setServoPos(degree);
|
||||
}
|
||||
|
||||
void getEepromData() {
|
||||
long pos;
|
||||
|
||||
EEPROM.get(EEPROM_SELECTOR_POS, pos);
|
||||
steppers[SELECTOR].setStepPosition(pos);
|
||||
EEPROM.get(EEPROM_REVOLVER_POS, pos);
|
||||
steppers[REVOLVER].setStepPosition(pos);
|
||||
EEPROM.get(EEPROM_FEEDER_POS, pos);
|
||||
steppers[FEEDER].setStepPosition(pos);
|
||||
|
||||
EEPROM.get(EEPROM_TOOL, toolSelected);
|
||||
EEPROM.get(EEPROM_CONTRAST, smuffConfig.lcdContrast);
|
||||
|
||||
EEPROM.get(EEPROM_TOOL_COUNT, smuffConfig.toolCount);
|
||||
if (smuffConfig.toolCount < MIN_TOOLS || smuffConfig.toolCount > MAX_TOOLS) {
|
||||
smuffConfig.toolCount = 5;
|
||||
EEPROM.put(EEPROM_TOOL_COUNT, smuffConfig.toolCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setSignalPort(int port, bool state) {
|
||||
sprintf(tmp,"%c%c%s", 0x1b, port, state ? "1" : "0");
|
||||
Serial2.write(tmp);
|
||||
}
|
||||
|
||||
void signalSelectorReady() {
|
||||
setSignalPort(SELECTOR_SIGNAL, false);
|
||||
//__debug("Signalling Selector ready");
|
||||
}
|
||||
|
||||
void signalSelectorBusy() {
|
||||
setSignalPort(SELECTOR_SIGNAL, true);
|
||||
//__debug("Signalling Selector busy");
|
||||
}
|
||||
|
||||
void signalLoadFilament() {
|
||||
setSignalPort(FEEDER_SIGNAL, true);
|
||||
//__debug("Signalling load filament");
|
||||
}
|
||||
|
||||
void signalUnloadFilament() {
|
||||
setSignalPort(FEEDER_SIGNAL, false);
|
||||
//__debug("Signalling unload filament");
|
||||
}
|
||||
|
||||
void listDir(File root, int numTabs, int serial) {
|
||||
while (true) {
|
||||
File entry = root.openNextFile();
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
for (int i = 1; i < numTabs; i++) {
|
||||
printResponse("\t", serial);
|
||||
}
|
||||
printResponse(entry.name(), serial);
|
||||
if (entry.isDirectory()) {
|
||||
printResponse("/\r\n", serial);
|
||||
//listDir(entry, numTabs + 1, serial);
|
||||
}
|
||||
else {
|
||||
sprintf(tmp, "\t\t%ld\r\n", entry.size());
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
}
|
||||
|
||||
void __debug(const char* fmt, ...) {
|
||||
#ifdef DEBUG
|
||||
char _tmp[1024];
|
||||
va_list arguments;
|
||||
va_start(arguments, fmt);
|
||||
vsnprintf(_tmp, 1024, fmt, arguments);
|
||||
va_end (arguments);
|
||||
Serial.println(_tmp);
|
||||
#endif
|
||||
}
|
||||
309
src/SimpleGCodeParser.cpp
Normal file
309
src/SimpleGCodeParser.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module implementing a simple G-Code parser
|
||||
*/
|
||||
|
||||
#include "SMuFF.h"
|
||||
#include "Config.h"
|
||||
#include "ZTimerLib.h"
|
||||
#include "ZStepperLib.h"
|
||||
|
||||
extern ZStepper steppers[NUM_STEPPERS];
|
||||
char ptmp[80];
|
||||
bool parserBusy = false;
|
||||
unsigned int currentLine = 0;
|
||||
|
||||
void parseGcode(String serialBuffer, int serial) {
|
||||
|
||||
if(parserBusy) {
|
||||
sendErrorResponseP(serial, P_Busy);
|
||||
return;
|
||||
}
|
||||
serialBuffer.replace(" ","");
|
||||
serialBuffer.replace("\r","");
|
||||
serialBuffer.replace("\n","");
|
||||
|
||||
if(serialBuffer.length()==0)
|
||||
return;
|
||||
|
||||
String line = String(serialBuffer);
|
||||
parserBusy = true;
|
||||
int pos;
|
||||
if((pos = line.lastIndexOf("*")) > -1) {
|
||||
line = line.substring(0, pos);
|
||||
}
|
||||
if((pos = line.lastIndexOf(";")) > -1) {
|
||||
if(pos==0) {
|
||||
parserBusy = false;
|
||||
return;
|
||||
}
|
||||
line = line.substring(0, pos);
|
||||
}
|
||||
if(line.startsWith("N")) {
|
||||
char ln[15];
|
||||
if((int)(currentLine = getParam(line, (char*)"N")) != -1) {
|
||||
sprintf(ln, "%d", currentLine);
|
||||
line = line.substring(strlen(ln)+1);
|
||||
}
|
||||
}
|
||||
//__debug("Line: %s %d", line.c_str(), line.length());
|
||||
if(line.startsWith("G")) {
|
||||
if(parse_G(line.substring(1), serial))
|
||||
sendOkResponse(serial);
|
||||
else
|
||||
sendErrorResponseP(serial);
|
||||
parserBusy = false;
|
||||
return;
|
||||
}
|
||||
else if(line.startsWith("M")) {
|
||||
if(parse_M(line.substring(1), serial))
|
||||
sendOkResponse(serial);
|
||||
else
|
||||
sendErrorResponseP(serial);
|
||||
parserBusy = false;
|
||||
return;
|
||||
}
|
||||
else if(line.startsWith("T")) {
|
||||
if(parse_T(line.substring(1), serial))
|
||||
sendOkResponse(serial);
|
||||
else
|
||||
sendErrorResponseP(serial);
|
||||
parserBusy = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
char tmp[256];
|
||||
sprintf(tmp, "%s '%s'\n", P_UnknownCmd, line.c_str());
|
||||
//__debug("Err: %s", tmp);
|
||||
sendErrorResponse(serial, tmp);
|
||||
}
|
||||
parserBusy = false;
|
||||
}
|
||||
|
||||
bool parse_T(String buf, int serial) {
|
||||
bool stat = true;
|
||||
|
||||
if(buf.length()==0) {
|
||||
sendToolResponse(serial);
|
||||
return stat;
|
||||
}
|
||||
int tool = buf.toInt();
|
||||
int param;
|
||||
|
||||
char msg[10];
|
||||
sprintf_P(msg, P_TResponse, tool);
|
||||
int ofs = String(msg).length()-2;
|
||||
|
||||
if(tool == -1 || tool == 255) {
|
||||
parse_G(String("28"), serial);
|
||||
}
|
||||
else if(tool >= 0 && tool <= smuffConfig.toolCount-1) {
|
||||
stat = selectTool(tool, false);
|
||||
if(stat) {
|
||||
if((param = getParam(buf.substring(ofs), (char*)"S")) != -1) {
|
||||
if(param == 1)
|
||||
loadFilament(false);
|
||||
else if(param == 0)
|
||||
unloadFilament();
|
||||
}
|
||||
}
|
||||
printResponse(msg, serial);
|
||||
}
|
||||
else {
|
||||
sendErrorResponse(serial, "Wrong tool selected.");
|
||||
stat = false;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool parse_G(String buf, int serial) {
|
||||
bool stat = true;
|
||||
|
||||
if(buf.length()==0) {
|
||||
sendGList(serial);
|
||||
return stat;
|
||||
}
|
||||
int code = buf.toInt();
|
||||
//__debug("G[%s]: >%d< %d", buf.c_str(), code, buf.length());
|
||||
|
||||
char msg[10];
|
||||
sprintf_P(msg, P_GResponse, code);
|
||||
int ofs = String(msg).length()-2;
|
||||
|
||||
for(int i=0; i< 999; i++) {
|
||||
if(gCodeFuncsG[i].code == -1)
|
||||
break;
|
||||
if(gCodeFuncsG[i].code == code) {
|
||||
return gCodeFuncsG[i].func(msg, buf.substring(ofs), serial);
|
||||
}
|
||||
}
|
||||
char tmp[256];
|
||||
sprintf_P(tmp, P_UnknownCmd, buf.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_M(String buf, int serial) {
|
||||
bool stat = true;
|
||||
|
||||
if(buf.length()==0) {
|
||||
sendMList(serial);
|
||||
return stat;
|
||||
}
|
||||
int code = buf.toInt();
|
||||
|
||||
char msg[10];
|
||||
sprintf_P(msg, P_MResponse, code);
|
||||
int ofs = String(msg).length()-2;
|
||||
|
||||
for(int i=0; i< 999; i++) {
|
||||
if(gCodeFuncsM[i].code == -1)
|
||||
break;
|
||||
if(gCodeFuncsM[i].code == code) {
|
||||
//__debug("Calling: M", gCodeFuncsM[i].code);
|
||||
return gCodeFuncsM[i].func(msg, buf.substring(ofs), serial);
|
||||
}
|
||||
}
|
||||
char tmp[256];
|
||||
sprintf_P(tmp, P_UnknownCmd, buf.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int getParam(String buf, char* token) {
|
||||
int pos = buf.indexOf(token);
|
||||
//__debug("getParam: %s\n",buf.c_str());
|
||||
if(pos != -1) {
|
||||
//__debug("getParam:pos: %d",pos);
|
||||
if(buf.charAt(pos+1)=='-') {
|
||||
int val = buf.substring(pos+2).toInt();
|
||||
//__debug("Negative: %d", 0-val);
|
||||
return 0-val;
|
||||
}
|
||||
return buf.substring(pos+1).toInt();
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool getParamString(String buf, char* token, char* dest, int bufLen) {
|
||||
int pos = buf.indexOf(token);
|
||||
//__debug("getParamString: %s\n",buf.c_str());
|
||||
if(pos != -1) {
|
||||
if(buf.substring(pos+1).startsWith("\"")) {
|
||||
int endPos = buf.substring(pos+2).indexOf("\"");
|
||||
//__debug("End of string: %d\n", endPos);
|
||||
if(endPos != -1) {
|
||||
memset(dest, 0, bufLen);
|
||||
if(endPos+1 < bufLen) {
|
||||
if(dest != NULL) {
|
||||
buf.substring(pos+2, endPos+3).toCharArray(dest, endPos+1);
|
||||
//__debug("ptmp: >%s< (%d)\n", dest, strlen(dest));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void prepStepping(int index, long param, bool Millimeter /* = true */, bool ignoreEndstop /* = false */) {
|
||||
if(param != 0) {
|
||||
if(positionMode == RELATIVE) {
|
||||
if(Millimeter) prepSteppingRelMillimeter(index, param);
|
||||
else prepSteppingRel(index, param);
|
||||
}
|
||||
else {
|
||||
if(Millimeter) prepSteppingAbsMillimeter(index, param);
|
||||
else prepSteppingAbs(index, param);
|
||||
}
|
||||
remainingSteppersFlag |= _BV(index);
|
||||
}
|
||||
}
|
||||
|
||||
void sendGList(int serial) {
|
||||
printResponseP(P_GCmds, serial);
|
||||
}
|
||||
|
||||
void sendMList(int serial) {
|
||||
printResponseP(P_MCmds, serial);
|
||||
}
|
||||
|
||||
void sendToolResponse(int serial) {
|
||||
char tmp[80];
|
||||
sprintf_P(tmp, P_TResponse, toolSelected);
|
||||
printResponse(tmp, serial);
|
||||
}
|
||||
|
||||
void sendErrorResponse(int serial, const char* msg /* = NULL */) {
|
||||
printResponse(msg, serial);
|
||||
sendOkResponse(serial);
|
||||
}
|
||||
|
||||
void sendErrorResponseP(int serial, const char* msg /* = NULL */) {
|
||||
char tmp[128];
|
||||
sprintf_P(tmp, P_Error, msg == NULL ? "" : msg);
|
||||
printResponse(tmp, serial);
|
||||
sendOkResponse(serial);
|
||||
}
|
||||
|
||||
void sendOkResponse(int serial) {
|
||||
printResponseP(P_Ok, serial);
|
||||
}
|
||||
|
||||
void sendStartResponse(int serial){
|
||||
printResponseP(P_Start, serial);
|
||||
}
|
||||
|
||||
void saveSettings(int serial) {
|
||||
printResponseP(P_AlreadySaved, serial);
|
||||
}
|
||||
|
||||
void reportSettings(int serial) {
|
||||
char tmp[128];
|
||||
long ldummy;
|
||||
byte bdummy;
|
||||
|
||||
EEPROM.get(EEPROM_SELECTOR_POS, ldummy); sprintf_P(tmp, P_SelectorPos, EEPROM_SELECTOR_POS, ldummy); printResponse(tmp, serial);
|
||||
EEPROM.get(EEPROM_REVOLVER_POS, ldummy); sprintf_P(tmp, P_RevolverPos, EEPROM_REVOLVER_POS, ldummy); printResponse(tmp, serial);
|
||||
EEPROM.get(EEPROM_FEEDER_POS, ldummy); sprintf_P(tmp, P_FeederPos, EEPROM_FEEDER_POS, ldummy); printResponse(tmp, serial);
|
||||
EEPROM.get(EEPROM_TOOL, bdummy); sprintf_P(tmp, P_ToolSelected, EEPROM_TOOL, bdummy); printResponse(tmp, serial);
|
||||
EEPROM.get(EEPROM_CONTRAST, bdummy); sprintf_P(tmp, P_Contrast, EEPROM_CONTRAST, bdummy); printResponse(tmp, serial);
|
||||
EEPROM.get(EEPROM_TOOL_COUNT, bdummy); sprintf_P(tmp, P_ToolsConfig, EEPROM_TOOL_COUNT, bdummy); printResponse(tmp, serial);
|
||||
}
|
||||
|
||||
void printResponse(const char* response, int serial) {
|
||||
switch(serial) {
|
||||
case 0: Serial.print(response); break;
|
||||
case 1: Serial1.print(response); break;
|
||||
case 2: Serial2.print(response); break;
|
||||
case 3: Serial3.print(response); break;
|
||||
}
|
||||
}
|
||||
|
||||
void printResponseP(const char* response, int serial) {
|
||||
switch(serial) {
|
||||
case 0: Serial.print((__FlashStringHelper*)response); break;
|
||||
case 1: Serial1.print((__FlashStringHelper*)response); break;
|
||||
case 2: Serial2.print((__FlashStringHelper*)response); break;
|
||||
case 3: Serial3.print((__FlashStringHelper*)response); break;
|
||||
}
|
||||
}
|
||||
133
src/Strings.h
Normal file
133
src/Strings.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SMUFF_STRINGS_H
|
||||
#define _SMUFF_STRINGS_H
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define SD_ERR_INIT 1
|
||||
#define SD_ERR_NOCONFIG 2
|
||||
#define SD_READING_CONFIG 0
|
||||
|
||||
const char P_MenuItemBack [] PROGMEM = { "\u25c0 BACK\n" };
|
||||
const char P_MenuItems [] PROGMEM = { "Home\nMotors off\nOffsets\nLoad feeder\nUnload feeder\nSwap tools" };
|
||||
const char P_OfsMenuItems [] PROGMEM = { "Selector\nRevolver" };
|
||||
const char P_OkButtonOnly [] PROGMEM = { " Ok " };
|
||||
const char P_CancelButtonOnly [] PROGMEM = { " Cancel " };
|
||||
const char P_OkCancelButtons [] PROGMEM = { " Ok \n Cancel " };
|
||||
const char P_YesNoButtons [] PROGMEM = { " Yes \n No " };
|
||||
const char P_TitleWarning [] PROGMEM = { "WARNING" };
|
||||
const char P_TitleSelected [] PROGMEM = { "TOOL SELECTED" };
|
||||
const char P_FeederLoaded [] PROGMEM = { "Feeder is loaded!\n" };
|
||||
const char P_AskUnload [] PROGMEM = { "Want me to unload\nit now?" };
|
||||
const char P_AskLoad [] PROGMEM = { "Want me to load\nit now?" };
|
||||
const char P_SelectedTool [] PROGMEM = { "\n" };
|
||||
const char P_CantLoad [] PROGMEM = { "Can't load feeder." };
|
||||
const char P_CantUnload [] PROGMEM = { "Can't unload feeder." };
|
||||
const char P_CheckUnit [] PROGMEM = { "Please check unit!" };
|
||||
const char P_TitleConfigError [] PROGMEM = { "CONFIG FAILURE" };
|
||||
const char P_ConfigFail1 [] PROGMEM = { "Your config file is" };
|
||||
const char P_ConfigFail2 [] PROGMEM = { "possibly corrupted,\nplease check!" };
|
||||
const char P_ConfigFail3 [] PROGMEM = { "too big,\nplease reduce content!" };
|
||||
const char P_Tool [] PROGMEM = { "Tool " };
|
||||
const char P_ToolMenu [] PROGMEM = { "Tool %d" };
|
||||
const char P_SwapMenu [] PROGMEM = { "Slot %d: T%d" };
|
||||
const char P_SwapReset [] PROGMEM = { "Reset swaps\n" };
|
||||
const char P_SwapToolDialog [] PROGMEM = { "Swap Tool %d\nwith Tool %d" };
|
||||
const char P_Selecting [] PROGMEM = { "Selecting" };
|
||||
const char P_Wait [] PROGMEM = { "please wait..." };
|
||||
const char P_TitleMainMenu [] PROGMEM = { "Main menu" };
|
||||
const char P_TitleToolsMenu [] PROGMEM = { "Tool Selection" };
|
||||
const char P_TitleOffsetsMenu [] PROGMEM = { "Offsets calibration" };
|
||||
const char P_TitleSwapMenu [] PROGMEM = { "Swap tools" };
|
||||
const char P_Busy[] PROGMEM = { "busy..." };
|
||||
const char P_Ready[] PROGMEM = { "ready." };
|
||||
|
||||
const char P_SD_ReadingConfig[] PROGMEM = { "Reading config..." };
|
||||
const char P_SD_InitError[] PROGMEM = { "SD-Card not ready!" };
|
||||
const char P_SD_NoConfig[] PROGMEM = { "No config file found!" };
|
||||
|
||||
const char P_Ok[] PROGMEM = { "ok\n" };
|
||||
const char P_Start[] PROGMEM = { "start\n" };
|
||||
const char P_Error[] PROGMEM = { "Error: %s\n" };
|
||||
const char P_UnknownCmd[] PROGMEM = { "Unknown command:" };
|
||||
const char P_AlreadySaved[] PROGMEM = { "Already saved.\n" };
|
||||
const char P_GVersion[] PROGMEM = { "FIRMWARE_NAME: Smart.Multi.Filament.Feeder (SMuFF) FIRMWARE_VERSION: %s ELECTRONICS: Wanhao i3-Mini DATE: %s\n" };
|
||||
const char P_TResponse[] PROGMEM = { "T%d\n" };
|
||||
const char P_GResponse[] PROGMEM = { "G%d\n" };
|
||||
const char P_MResponse[] PROGMEM = { "M%d\n" };
|
||||
const char P_M250Response[] PROGMEM = { "M250 C%d\n" };
|
||||
|
||||
const char P_SelectorPos[] PROGMEM = { "%3d: Selector position = %ld\n" };
|
||||
const char P_RevolverPos[] PROGMEM = { "%3d: Revolver position = %ld\n" };
|
||||
const char P_FeederPos[] PROGMEM = { "%3d: Feeder position = %ld\n" };
|
||||
const char P_ToolSelected[] PROGMEM = { "%3d: Tool selected = %d\n" };
|
||||
const char P_Contrast[] PROGMEM = { "%3d: Display contrast = %d\n" };
|
||||
const char P_ToolsConfig[] PROGMEM = { "%3d: Tools configured = %d\n" };
|
||||
const char P_AccelSpeed[] PROGMEM = { "X (Selector):\t%s\nY (Revolver):\t%s\nZ (Feeder):\t%s\n" };
|
||||
|
||||
const char P_CurrentTool[] PROGMEM = {"Tool " };
|
||||
const char P_Feed[] PROGMEM = {"Feed " };
|
||||
|
||||
const char P_NoTool [] PROGMEM = { "No tool set.\n" };
|
||||
const char P_Aborting [] PROGMEM = { "Aborting..."};
|
||||
const char P_FeederJamed [] PROGMEM = { "Feeder is jamed.\n" };
|
||||
const char P_ToolAlreadySet [] PROGMEM = { "Tool already set." };
|
||||
|
||||
const char P_WrongFormat [] PROGMEM = { "Wrong format. Use Bdd:dd:dd...\n" };
|
||||
|
||||
const char P_GCmds[] PROGMEM = {
|
||||
"G0\t-\tMove\n" \
|
||||
"G1\t-\tMove\n" \
|
||||
"G4\t-\tDwell\n" \
|
||||
"G12\t-\tWipe filament\n" \
|
||||
"G28\t-\tHome\n" \
|
||||
"G90\t-\tAbsolute positioning\n" \
|
||||
"G91\t-\tRelative positioning\n" };
|
||||
|
||||
const char P_MCmds[] PROGMEM = {
|
||||
"M18\t-\tMotors off\n" \
|
||||
"M84\t-\tMotors off\n" \
|
||||
"M20\t-\tList SD-Card\n" \
|
||||
"M42\t-\tSet pin state\n" \
|
||||
"M106\t-\tFan on\n" \
|
||||
"M107\t-\tFan off\n" \
|
||||
"M114\t-\tReport current positions\n" \
|
||||
"M115\t-\tReport version\n" \
|
||||
"M117\t-\tDisplay message\n" \
|
||||
"M119\t-\tReport endstop status\n" \
|
||||
"M120\t-\tEnable endstops\n" \
|
||||
"M121\t-\tDisable endstops\n" \
|
||||
"M122\t-\tReport Diagnostics\n" \
|
||||
"M201\t-\tSet max acceleration\n" \
|
||||
"M203\t-\tSet max feedrate\n" \
|
||||
"M206\t-\tSet offsets\n" \
|
||||
"M250\t-\tLCD contrast\n" \
|
||||
"M300\t-\tBeep\n" \
|
||||
"M500\t-\tSave settings\n" \
|
||||
"M503\t-\tReport settings\n" \
|
||||
"M700\t-\tLoad filament\n" \
|
||||
"M701\t-\tUnload filament\n" \
|
||||
"M999\t-\tReset\n" \
|
||||
"M2000\t-\tText to decimal\n" \
|
||||
"M2001\t-\tDecimal to text\n"};
|
||||
|
||||
|
||||
#endif
|
||||
55
src/ZServo.cpp
Normal file
55
src/ZServo.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ZServo.h"
|
||||
|
||||
ZServo* instance;
|
||||
|
||||
void ZServo::write(int degree) {
|
||||
setServoPos(degree);
|
||||
}
|
||||
|
||||
bool ZServo::setServoPos(int degree) {
|
||||
bool stat = false;
|
||||
if(_pin > 0) {
|
||||
_pulseLen = map(degree, 0, 180, US_PER_PULSE_0DEG, US_PER_PULSE_180DEG);
|
||||
instance = this;
|
||||
//__debug("Pulse length set to: %dms", _pulseLen);
|
||||
servoTimer.setNextInterruptInterval(TIMER_INTERVAL);
|
||||
stat = true;
|
||||
_degree = degree;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
void ZServo::setServoMS(int microseconds) {
|
||||
_pulseLen = microseconds;
|
||||
servoTimer.setNextInterruptInterval(TIMER_INTERVAL);
|
||||
}
|
||||
|
||||
void ZServo::setServo() {
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_pulseLen);
|
||||
digitalWrite(_pin, LOW);
|
||||
}
|
||||
|
||||
void isrServoTimerHandler() {
|
||||
if(instance != NULL)
|
||||
instance->setServo();
|
||||
}
|
||||
61
src/ZServo.h
Normal file
61
src/ZServo.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <Arduino.h>
|
||||
#include "Config.h"
|
||||
#include "ZTimerLib.h"
|
||||
|
||||
#ifndef _ZSERVO_H
|
||||
#define _ZSERVO_H
|
||||
|
||||
#define US_PER_PULSE_0DEG 500 // 0 degrees
|
||||
#define US_PER_PULSE_180DEG 2400 // 180 degrees
|
||||
#define TIMER_INTERVAL 312 // CPU-Clock / (Prescaler * 50)-1 = 16000000 / (1024 * 50) - 1 = 311,5
|
||||
|
||||
|
||||
void isrServoTimerHandler();
|
||||
|
||||
class ZServo {
|
||||
public:
|
||||
ZServo() { _pin = 0; };
|
||||
ZServo(int pin) { attach(pin); }
|
||||
|
||||
void attach(int pin) {
|
||||
_pin = pin;
|
||||
pinMode(_pin, OUTPUT);
|
||||
digitalWrite(_pin, 0);
|
||||
servoTimer.setupTimer(ZTimer::TIMER5, ZTimer::PRESCALER1024);
|
||||
servoTimer.setupTimerHook(isrServoTimerHandler);
|
||||
}
|
||||
void write(int degree);
|
||||
bool setServoPos(int degree);
|
||||
void setServoMS(int microseconds);
|
||||
void setServo();
|
||||
void stop() { servoTimer.stopTimer(); }
|
||||
|
||||
int getDegree() { return _degree; }
|
||||
|
||||
private:
|
||||
ZTimer servoTimer;
|
||||
int _pin;
|
||||
int _degree;
|
||||
int _pulseLen;
|
||||
};
|
||||
#endif
|
||||
183
src/ZStepperLib.cpp
Normal file
183
src/ZStepperLib.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module implementing a stepper driver library
|
||||
*/
|
||||
|
||||
#include "ZStepperLib.h"
|
||||
|
||||
extern void __debug(const char* fmt, ...);
|
||||
|
||||
ZStepper::ZStepper() {
|
||||
|
||||
}
|
||||
|
||||
ZStepper::ZStepper(int number, char* descriptor, int stepPin, int dirPin, int enablePin, float acceleration, unsigned int minStepInterval) {
|
||||
_number = number;
|
||||
_descriptor = descriptor;
|
||||
_stepPin = stepPin;
|
||||
_dirPin = dirPin;
|
||||
_enablePin = enablePin;
|
||||
_acceleration = acceleration;
|
||||
_minStepInterval = minStepInterval;
|
||||
pinMode(_stepPin, OUTPUT);
|
||||
pinMode(_dirPin, OUTPUT);
|
||||
pinMode(_enablePin, OUTPUT);
|
||||
}
|
||||
|
||||
void ZStepper::defaultStepFunc(void) {
|
||||
if(_stepPin != -1) {
|
||||
digitalWrite(_stepPin, HIGH);
|
||||
digitalWrite(_stepPin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void ZStepper::resetStepper() {
|
||||
_duration = _acceleration;
|
||||
_durationInt = _duration;
|
||||
_stepCount = 0;
|
||||
_movementDone = false;
|
||||
_endstopHit = false;
|
||||
}
|
||||
|
||||
void ZStepper::prepareMovement(long steps, boolean ignoreEndstop = false) {
|
||||
setDirection(steps < 0 ? CCW : CW);
|
||||
_totalSteps = abs(steps);
|
||||
_accelDistance = _totalSteps >> 5;
|
||||
_stepsAcceleration = (float)((_acceleration - _minStepInterval)+.1) / _accelDistance;
|
||||
_ignoreEndstop = ignoreEndstop;
|
||||
resetStepper();
|
||||
}
|
||||
|
||||
void ZStepper::setEndstop(int pin, int triggerState, EndstopType type) {
|
||||
_endstopPin = pin;
|
||||
_endstopState = triggerState;
|
||||
_endstopType = type;
|
||||
pinMode(_endstopPin, _endstopType == LOW ? INPUT_PULLUP : INPUT);
|
||||
_endstopHit = digitalRead(_endstopPin) == _endstopState;
|
||||
}
|
||||
|
||||
void ZStepper::setDirection(ZStepper::MoveDirection direction) {
|
||||
if(_dirPin != -1) {
|
||||
_dir = direction;
|
||||
digitalWrite(_dirPin, !_invertDir ? (_dir == CCW ? HIGH : LOW) : (_dir == CCW ? LOW : HIGH));
|
||||
}
|
||||
}
|
||||
|
||||
void ZStepper::setEnabled(boolean state) {
|
||||
if(_enablePin != -1) {
|
||||
digitalWrite(_enablePin, state ? LOW : HIGH);
|
||||
_enabled = state;
|
||||
}
|
||||
}
|
||||
|
||||
void ZStepper::updateAcceleration() {
|
||||
if(_stepCount <= _accelDistance) {
|
||||
_duration -= _stepsAcceleration; // accelerate
|
||||
if(_duration <= _minStepInterval)
|
||||
_duration = _minStepInterval;
|
||||
//__debug("durInt: %d, %s", _durationInt, String(_duration).c_str());
|
||||
}
|
||||
else if (_stepCount >= _totalSteps - _accelDistance ) {
|
||||
_duration += _stepsAcceleration; // decelerate
|
||||
if(_duration >= _acceleration)
|
||||
_duration = _acceleration;
|
||||
}
|
||||
_durationInt = _duration;
|
||||
}
|
||||
|
||||
void ZStepper::handleISR() {
|
||||
|
||||
//if(_endstopType == ORBITAL)
|
||||
// __debug("O: %d %d ", _stepCount, _dir);
|
||||
|
||||
if((_endstopType == MIN && _dir == CCW) ||
|
||||
(_endstopType == MAX && _dir == CW) ||
|
||||
(_endstopType == ORBITAL && _dir == CCW)) {
|
||||
bool hit = digitalRead(_endstopPin)==_endstopState;
|
||||
setEndstopHit(hit);
|
||||
}
|
||||
if(!_ignoreEndstop && _endstopHit && !_movementDone){
|
||||
setMovementDone(true);
|
||||
if(_endstopType == MIN || _endstopType == ORBITAL) {
|
||||
setStepPosition(0);
|
||||
}
|
||||
else if(_endstopType == MAX)
|
||||
setStepPosition(_maxStepCount);
|
||||
|
||||
if(endstopFunc != NULL)
|
||||
endstopFunc();
|
||||
return;
|
||||
}
|
||||
|
||||
if(_ignoreEndstop && _endstopHit && _endstopType == ORBITAL){
|
||||
setStepPosition(0);
|
||||
}
|
||||
|
||||
if(_maxStepCount != 0 && _dir == CW && _stepCount >= _maxStepCount) {
|
||||
setMovementDone(true);
|
||||
}
|
||||
else if(_stepCount < _totalSteps) {
|
||||
if(stepFunc != NULL)
|
||||
stepFunc();
|
||||
else
|
||||
defaultStepFunc();
|
||||
_stepCount++;
|
||||
setStepPosition(_stepPosition + _dir);
|
||||
if(_stepCount >= _totalSteps) {
|
||||
setMovementDone(true);
|
||||
//__debug("handleISR(): %ld / %ld", _stepCount, _totalSteps);
|
||||
}
|
||||
}
|
||||
updateAcceleration();
|
||||
}
|
||||
|
||||
bool ZStepper::getEndstopHit() {
|
||||
int stat = 0;
|
||||
for(int i=0; i < 5; i++)
|
||||
stat = digitalRead(_endstopPin);
|
||||
setEndstopHit(stat==_endstopState);
|
||||
return _endstopHit;
|
||||
}
|
||||
|
||||
void ZStepper::home() {
|
||||
|
||||
unsigned int curSpeed = getMaxSpeed();
|
||||
long distance = -_maxStepCount;
|
||||
if(_endstopPin != -1) {
|
||||
distance = -(_maxStepCount*2);
|
||||
}
|
||||
//__debug("[ZStepper::home] Distance: %d - max: %d", distance, _maxStepCount);
|
||||
prepareMovement(distance);
|
||||
//__debug("[ZStepper::home] DONE prepareMovement");
|
||||
if(runAndWaitFunc != NULL)
|
||||
runAndWaitFunc(_number);
|
||||
//__debug("[ZStepper::home] DONE runAndWait");
|
||||
do {
|
||||
prepareMovement(_maxStepCount/30);
|
||||
if(runAndWaitFunc != NULL)
|
||||
runAndWaitFunc(_number);
|
||||
} while(_endstopHit);
|
||||
prepareMovement(-(_maxStepCount));
|
||||
setMaxSpeed(curSpeed*5);
|
||||
if(runAndWaitFunc != NULL)
|
||||
runAndWaitFunc(_number);
|
||||
setMaxSpeed(curSpeed);
|
||||
}
|
||||
135
src/ZStepperLib.h
Normal file
135
src/ZStepperLib.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <Arduino.h>
|
||||
#include "Config.h"
|
||||
|
||||
#ifndef _ZSTEPPER_H
|
||||
#define _ZSTEPPER_H
|
||||
|
||||
extern void __debug(const char* fmt, ...);
|
||||
|
||||
class ZStepper {
|
||||
public:
|
||||
typedef enum {
|
||||
NONE = -1,
|
||||
MIN, // Endstop is at position 0
|
||||
MAX, // Endstop is at position >0
|
||||
ORBITAL // Endstop on rotating axis
|
||||
} EndstopType;
|
||||
|
||||
typedef enum {
|
||||
CW = 1, // Clockwise
|
||||
CCW = -1 // Counter clockwise
|
||||
} MoveDirection;
|
||||
|
||||
ZStepper();
|
||||
ZStepper(int number, char* descriptor, int stepPin, int dirPin, int enablePin, float accelaration, unsigned int minStepInterval);
|
||||
|
||||
void prepareMovement(long steps, boolean ignoreEndstop = false);
|
||||
void handleISR();
|
||||
void home();
|
||||
|
||||
void (*stepFunc)() = NULL;
|
||||
void (*endstopFunc)() = NULL;
|
||||
void (*runAndWaitFunc)(int number) = NULL;
|
||||
void (*runNoWaitFunc)(int number) = NULL;
|
||||
void defaultStepFunc(); // default step method, uses digitalWrite on _stepPin
|
||||
|
||||
char* getDescriptor() { return _descriptor; }
|
||||
void setDescriptor(char* descriptor) { _descriptor = descriptor; }
|
||||
MoveDirection getDirection() { return _dir; }
|
||||
void setDirection(MoveDirection newDir);
|
||||
bool getEnabled() { return _enabled; }
|
||||
void setEnabled(bool state);
|
||||
void setEndstop(int pin, int triggerState, EndstopType type);
|
||||
EndstopType getEndstopType() { return _endstopType; }
|
||||
void setEndstopType(EndstopType type) { _endstopType = type; }
|
||||
int getEndstopState() { return _endstopState; }
|
||||
void setEndstopState(int state) { _endstopState = state; }
|
||||
bool getEndstopHit();
|
||||
bool getEndstopHitAlt() { return _endstopHit; }
|
||||
void setEndstopHit(int state) { _endstopHit = state; }
|
||||
int getEndstopPin() { return _endstopPin; }
|
||||
void setEndstopPin(int pin) { _endstopPin = pin; }
|
||||
bool getIgnoreEndstop() { return _ignoreEndstop; }
|
||||
void setIgnoreEndstop(bool state) { _ignoreEndstop = state; }
|
||||
|
||||
long getStepCount() { return _stepCount; }
|
||||
void setStepCount(long count) { _stepCount = count; }
|
||||
long getMaxStepCount() { return _maxStepCount; }
|
||||
void setMaxStepCount(long count) { _maxStepCount = count; }
|
||||
void incrementStepCount() { _stepCount++; }
|
||||
long getTotalSteps() { return _totalSteps; }
|
||||
void setTotalSteps(long count) { _totalSteps = count; }
|
||||
long getStepPosition() { return _stepPosition; }
|
||||
void setStepPosition(long position) { _stepPosition = position; _stepPositionMM = (float)((float)position / _stepsPerMM); }
|
||||
float getStepPositionMM() { return _stepPositionMM; }
|
||||
void setStepPositionMM(float position) { _stepPositionMM = position; _stepPosition = (long)(position * _stepsPerMM);}
|
||||
void incrementStepPosition() { setStepPosition(getStepPosition() + _dir); }
|
||||
bool getMovementDone() { return _movementDone; }
|
||||
void setMovementDone(bool state) { _movementDone = state; }
|
||||
float getAcceleration() { return _acceleration; }
|
||||
void setAcceleration(float value) { _acceleration = value; }
|
||||
unsigned int getMaxSpeed() { return _minStepInterval; }
|
||||
void setMaxSpeed(unsigned int value) { _minStepInterval = value; }
|
||||
bool getInvertDir() { return _invertDir; }
|
||||
void setInvertDir(bool state) { _invertDir = state; }
|
||||
|
||||
unsigned int getDuration() { return _durationInt; }
|
||||
void setDuration(unsigned int value) { _durationInt = value; }
|
||||
unsigned int getStepsPerMM() { return _stepsPerMM; }
|
||||
void setStepsPerMM(int steps) { _stepsPerMM = steps; }
|
||||
|
||||
private:
|
||||
int _number = 0; // index of this stepper
|
||||
char* _descriptor = (char*)""; // display name for this stepper
|
||||
int _stepPin = -1; // stepping pin
|
||||
int _dirPin = -1; // direction pin
|
||||
int _enablePin = -1; // enable pin
|
||||
bool _enabled = false; // enabled state
|
||||
int _endstopPin = -1; // endstop pin
|
||||
volatile bool _endstopHit = false; // set when endstop is being triggered
|
||||
bool _ignoreEndstop = false; // flag whether or not to ignore endstop trigger
|
||||
int _endstopState = HIGH; // value for endstop triggered
|
||||
EndstopType _endstopType = NONE; // type of endstop (MIN, MAX, ORBITAL etc)
|
||||
volatile long _stepPosition = 0; // current position of stepper (total of all movements taken so far)
|
||||
volatile MoveDirection _dir = CW; // current direction of movement, used to keep track of position
|
||||
volatile long _totalSteps = 0; // number of steps requested for current movement
|
||||
volatile bool _movementDone = false; // true if the current movement has been completed (used by main program to wait for completion)
|
||||
float _acceleration = 1000; // acceleration value
|
||||
unsigned int _minStepInterval = 100; // ie. max speed, smaller is faster
|
||||
long _stepCount = 0; // number of steps completed in current movement
|
||||
long _maxStepCount = 0; // maximum number of steps
|
||||
unsigned int _stepsPerMM = 0; // steps needed for one millimeter
|
||||
float _stepPositionMM = 0; // current position of stepper in millimeter
|
||||
bool _invertDir = false; // stepper direction inversion
|
||||
|
||||
// per iteration variables (potentially changed every interrupt)
|
||||
volatile float _duration; // current interval length
|
||||
volatile unsigned int _durationInt; // above variable truncated
|
||||
volatile long _accelDistance = 0; // amount of steps for acceleration/deceleration
|
||||
volatile float _stepsAcceleration = 0.0;
|
||||
|
||||
void resetStepper(); // method to reset work params
|
||||
void updateAcceleration();
|
||||
};
|
||||
|
||||
#endif
|
||||
148
src/ZTimerLib.cpp
Normal file
148
src/ZTimerLib.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module for timer & ISR routines
|
||||
*/
|
||||
|
||||
#include "ZTimerLib.h"
|
||||
|
||||
static void (*__timer1Hook)(void) = NULL;
|
||||
static void (*__timer3Hook)(void) = NULL;
|
||||
static void (*__timer4Hook)(void) = NULL;
|
||||
static void (*__timer5Hook)(void) = NULL;
|
||||
|
||||
void ZTimer::setupTimer(IsrTimer timer, TimerPrescaler prescaler) {
|
||||
_timer = timer;
|
||||
|
||||
stopTimer();
|
||||
noInterrupts();
|
||||
switch(_timer) {
|
||||
case TIMER1:
|
||||
TCCR1A = 0;
|
||||
TCCR1B = prescaler;
|
||||
TCCR1B |= _BV(WGM12); // CTC mode
|
||||
break;
|
||||
case TIMER3:
|
||||
TCCR3A = 0;
|
||||
TCCR3B = prescaler;
|
||||
TCCR3B |= _BV(WGM32); // CTC mode
|
||||
break;
|
||||
case TIMER4:
|
||||
TCCR4A = 0;
|
||||
TCCR4B = prescaler;
|
||||
TCCR4B |= _BV(WGM42); // CTC mode
|
||||
break;
|
||||
case TIMER5:
|
||||
TCCR5A = 0;
|
||||
TCCR5B = prescaler;
|
||||
TCCR5B |= _BV(WGM52); // CTC mode
|
||||
break;
|
||||
}
|
||||
|
||||
setNextInterruptInterval(1000);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
if(__timer1Hook != NULL)
|
||||
__timer1Hook();
|
||||
}
|
||||
|
||||
ISR(TIMER3_COMPA_vect) {
|
||||
if(__timer3Hook != NULL)
|
||||
__timer3Hook();
|
||||
}
|
||||
|
||||
ISR(TIMER4_COMPA_vect) {
|
||||
if(__timer4Hook != NULL)
|
||||
__timer4Hook();
|
||||
}
|
||||
|
||||
ISR(TIMER5_COMPA_vect) {
|
||||
if(__timer5Hook != NULL)
|
||||
__timer5Hook();
|
||||
}
|
||||
|
||||
void ZTimer::setupTimerHook(void (*function)(void))
|
||||
{
|
||||
switch(_timer) {
|
||||
case TIMER1: __timer1Hook = function; break;
|
||||
case TIMER3: __timer3Hook = function; break;
|
||||
case TIMER4: __timer4Hook = function; break;
|
||||
case TIMER5: __timer5Hook = function; break;
|
||||
}
|
||||
}
|
||||
|
||||
void ZTimer::setNextInterruptInterval(unsigned int interval) {
|
||||
stopTimer();
|
||||
switch(_timer) {
|
||||
case TIMER1: OCR1A = interval; TCNT1 = 0; break;
|
||||
case TIMER3: OCR3A = interval; TCNT3 = 0; break;
|
||||
case TIMER4: OCR4A = interval; TCNT4 = 0; break;
|
||||
case TIMER5: OCR5A = interval; TCNT5 = 0; break;
|
||||
}
|
||||
startTimer();
|
||||
}
|
||||
|
||||
unsigned int ZTimer::getOCRxA() {
|
||||
switch(_timer) {
|
||||
case TIMER1: return OCR1A;
|
||||
case TIMER3: return OCR3A;
|
||||
case TIMER4: return OCR4A;
|
||||
case TIMER5: return OCR5A;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZTimer::setOCRxA(unsigned int value) {
|
||||
switch(_timer) {
|
||||
case TIMER1: OCR1A = value; break;
|
||||
case TIMER3: OCR3A = value; break;
|
||||
case TIMER4: OCR4A = value; break;
|
||||
case TIMER5: OCR5A = value; break;
|
||||
}
|
||||
}
|
||||
|
||||
void ZTimer::setTCNTx(unsigned int value) {
|
||||
switch(_timer) {
|
||||
case TIMER1: TCNT1 = value; break;
|
||||
case TIMER3: TCNT3 = value; break;
|
||||
case TIMER4: TCNT4 = value; break;
|
||||
case TIMER5: TCNT5 = value; break;
|
||||
}
|
||||
}
|
||||
|
||||
void ZTimer::startTimer() {
|
||||
switch(_timer) {
|
||||
case TIMER1: TIMSK1 |= _BV(OCIE1A); break;
|
||||
case TIMER3: TIMSK3 |= _BV(OCIE3A); break;
|
||||
case TIMER4: TIMSK4 |= _BV(OCIE4A); break;
|
||||
case TIMER5: TIMSK5 |= _BV(OCIE5A); break;
|
||||
}
|
||||
}
|
||||
|
||||
void ZTimer::stopTimer() {
|
||||
switch(_timer) {
|
||||
case TIMER1: TIMSK1 &= ~_BV(OCIE1A); break;
|
||||
case TIMER3: TIMSK3 &= ~_BV(OCIE3A); break;
|
||||
case TIMER4: TIMSK4 &= ~_BV(OCIE4A); break;
|
||||
case TIMER5: TIMSK5 &= ~_BV(OCIE5A); break;
|
||||
}
|
||||
}
|
||||
61
src/ZTimerLib.h
Normal file
61
src/ZTimerLib.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* SMuFF Firmware
|
||||
* Copyright (C) 2019 Technik Gegg
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <Arduino.h>
|
||||
#include "Config.h"
|
||||
|
||||
#ifndef _ZTIMER_H
|
||||
#define _ZTIMER_H
|
||||
|
||||
extern void __debug(const char* fmt, ...);
|
||||
|
||||
class ZTimer {
|
||||
public:
|
||||
typedef enum {
|
||||
TIMER1 = 1,
|
||||
TIMER3 = 3,
|
||||
TIMER4 = 4,
|
||||
TIMER5 = 5
|
||||
} IsrTimer;
|
||||
|
||||
typedef enum {
|
||||
PRESCALER1 = 1,
|
||||
PRESCALER8 = 2,
|
||||
PRESCALER64 = 3,
|
||||
PRESCALER256 = 4,
|
||||
PRESCALER1024 = 5
|
||||
} TimerPrescaler;
|
||||
|
||||
ZTimer() { };
|
||||
|
||||
void setupTimer(IsrTimer timer, TimerPrescaler prescaler);
|
||||
void setupTimerHook(void (*function)(void));
|
||||
void setNextInterruptInterval(unsigned int interval);
|
||||
unsigned int getOCRxA();
|
||||
void setOCRxA(unsigned int value);
|
||||
void setTCNTx(unsigned int value);
|
||||
void startTimer();
|
||||
void stopTimer();
|
||||
|
||||
private:
|
||||
IsrTimer _timer;
|
||||
};
|
||||
|
||||
#endif
|
||||
11
test/README
Normal file
11
test/README
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
||||
Reference in New Issue
Block a user