Prusa-Firmware/Firmware/main.cpp

613 lines
20 KiB
C++

//! @file
#include "main.h"
#include <Arduino.h>
#include <stdio.h>
#include <string.h>
#include <avr/io.h>
#include "shr16.h"
#include "adc.h"
#include "uart.h"
#include "spi.h"
#include "tmc2130.h"
#include "abtn3.h"
#include "mmctl.h"
#include "motion.h"
#include "Buttons.h"
#include <avr/wdt.h>
#include "permanent_storage.h"
// public variables:
int8_t sys_state = 0;
uint8_t sys_signals = 0;
bool fsensor_triggered = false;
bool unloadatBoot = false;
bool mmuFSensorLoading = false;
bool duplicateTCmd = false;
bool fixedTheProblem = false;
bool fixTheProblems = false;
bool load_filament_at_toolChange = false;
uint8_t tmc2130_mode = NORMAL_MODE; // STEALTH_MODE;
static char echo[32];
#if (UART_COM == 0)
FILE *uart_com = uart0io;
#elif (UART_COM == 1)
FILE *uart_com = uart1io;
#endif //(UART_COM == 0)
extern "C" void process_commands(FILE *inout);
//! @brief Initialization after reset
//!
//! button | action
//! ------ | ------
//! middle | enter setup
//! right | continue after error
//!
//! LED indication of states
//!
//! RG | RG | RG | RG | RG | meaning
//! -- | -- | -- | -- | -- | ------------------------
//! 00 | 00 | 00 | 00 | 0b | Shift register initialized
//! 00 | 00 | 00 | 0b | 00 | uart initialized
//! 00 | 00 | 0b | 00 | 00 | spi initialized
//! 00 | 0b | 00 | 00 | 00 | tmc2130 initialized
//! 0b | 00 | 00 | 00 | 00 | A/D converter initialized
//! b0 | b0 | b0 | b0 | b0 | Error, filament detected, still present
//! 0b | 0b | 0b | 0b | 0b | Error, filament detected, no longer present, continue by right button click
//!
//! @n R - Red LED
//! @n G - Green LED
//! @n 1 - active
//! @n 0 - inactive
//! @n b - blinking
void setup()
{
shr16_init(); // shift register
led_blink(0);
delay(1000); // wait for boot ok printer
uart0_init(); //uart0
uart1_init(); //uart1
led_blink(1);
#if (UART_STD == 0)
stdin = uart0io; // stdin = uart0
stdout = uart0io; // stdout = uart0
#elif(UART_STD == 1)
stdin = uart1io; // stdin = uart1
stdout = uart1io; // stdout = uart1
#endif //(UART_STD == 1)
bool requestMenu = false;
fprintf_P(uart_com, PSTR("start\n")); //startup message
spi_init();
led_blink(2);
tmc2130_init(HOMING_MODE); // trinamic, homing
led_blink(3);
adc_init(); // ADC
led_blink(4);
init_Pulley();
if (buttonClicked() == Btn::middle) {
requestMenu = true;
}
// if FINDA is sensing filament do not home
while (digitalRead(A1) == 1) {
while (Btn::right != buttonClicked()) {
if (digitalRead(A1) == 1) {
shr16_set_led(0x2aa);
} else {
shr16_set_led(0x155);
}
delay(300);
shr16_set_led(0x000);
delay(300);
}
}
home();
// TODO 2: add reading previously stored mode (stealth/normal) from eeprom
tmc2130_init(tmc2130_mode); // trinamic, initialize all axes
// check if to goto the settings menu
if (requestMenu) {
setupMenu();
}
}
//! @brief Select filament menu
//!
//! Select filament by pushing left and right button, park position can be also selected.
//!
//! button | action
//! ------ | ------
//! left | select previous filament
//! right | select next filament
//!
//! LED indication of states
//!
//! RG | RG | RG | RG | RG | meaning
//! -- | -- | -- | -- | -- | ------------------------
//! 01 | 00 | 00 | 00 | 00 | filament 1
//! 00 | 01 | 00 | 00 | 00 | filament 2
//! 00 | 00 | 01 | 00 | 00 | filament 3
//! 00 | 00 | 00 | 01 | 00 | filament 4
//! 00 | 00 | 00 | 00 | 01 | filament 5
//! 00 | 00 | 00 | 00 | bb | park position
//!
//! @n R - Red LED
//! @n G - Green LED
//! @n 1 - active
//! @n 0 - inactive
//! @n b - blinking
void manual_extruder_selector()
{
shr16_set_led(1 << 2 * (4 - active_extruder));
#ifdef TESTING_STEALTH
if (buttonClicked() != Btn::none) {
switch (buttonClicked()) {
case Btn::right:
if (active_extruder < EXTRUDERS) {
select_extruder(active_extruder + 1);
}
break;
case Btn::left:
if (active_extruder > 0) {
select_extruder(active_extruder - 1);
}
break;
default:
break;
}
}
#else
if ((Btn::left | Btn::right) & buttonClicked()) {
switch (buttonClicked()) {
case Btn::right:
if (active_extruder < EXTRUDERS) {
select_extruder(active_extruder + 1);
}
break;
case Btn::left:
if (active_extruder > 0) {
select_extruder(active_extruder - 1);
}
break;
default:
break;
}
}
#endif
if (active_extruder == 5) {
shr16_set_led(2 << 2 * 0);
delay(50);
shr16_set_led(1 << 2 * 0);
delay(50);
}
}
//! @brief main loop
//!
//! It is possible to manually select filament and feed it when not printing.
//!
//! button | action
//! ------ | ------
//! middle | feed filament
//!
//! @copydoc manual_extruder_selector()
void loop()
{
process_commands(uart_com);
if (!isPrinting) {
manual_extruder_selector();
#ifndef TESTING_STEALTH
if (Btn::middle == buttonClicked() && active_extruder < 5) {
shr16_set_led(2 << 2 * (4 - active_extruder));
if (Btn::middle == buttonClicked()) {
feed_filament();
}
}
}
#endif
}
extern "C" {
void process_commands(FILE *inout)
{
static char line[32];
static int count = 0;
int c = -1;
if (count < 32) {
if ((c = getc(inout)) >= 0) {
if (c == '\r') {
c = 0;
}
if (c == '\n') {
c = 0;
}
line[count++] = c;
}
} else {
count = 0;
//overflow
}
int value = 0;
int value0 = 0;
if (fixTheProblems == true) {
fprintf_P(inout, PSTR("not_ok\n"));
count = 0;
} else if (fixedTheProblem == true) {
fixTheProblems = false;
fixedTheProblem = false;
fprintf_P(inout, PSTR("ok\n"));
count = 0;
}
if ((count > 0) && (c == 0)) {
//line received
//printf_P(PSTR("line received: '%s' %d\n"), line, count);
if (strstr(line, "EE") != NULL) {
for (int i = 0; i < 32; i++) {
line[i] = echo[i];
}
count = 0;
} else if (strstr(line, "P0") == NULL) {
for (int i = 0; i < 32; i++) {
echo[i] = line[i];
}
count = 0;
//delay(10); // delay so MK3 comms is not floaded
if (strstr(line, "T0") != NULL) {
fprintf_P(inout, PSTR("T0\n"));
return;
}
if (strstr(line, "T1") != NULL) {
fprintf_P(inout, PSTR("T1\n"));
return;
}
if (strstr(line, "T2") != NULL) {
fprintf_P(inout, PSTR("T2\n"));
return;
}
if (strstr(line, "T3") != NULL) {
fprintf_P(inout, PSTR("T3\n"));
return;
}
if (strstr(line, "T4") != NULL) {
fprintf_P(inout, PSTR("T4\n"));
return;
}
if (strstr(line, "L0") != NULL) {
fprintf_P(inout, PSTR("L0\n"));
return;
}
if (strstr(line, "L1") != NULL) {
fprintf_P(inout, PSTR("L1\n"));
return;
}
if (strstr(line, "L2") != NULL) {
fprintf_P(inout, PSTR("L2\n"));
return;
}
if (strstr(line, "L3") != NULL) {
fprintf_P(inout, PSTR("L3\n"));
return;
}
if (strstr(line, "L4") != NULL) {
fprintf_P(inout, PSTR("L4\n"));
return;
}
if (strstr(line, "C0") != NULL) {
fprintf_P(inout, PSTR("C0\n"));
return;
}
if (strstr(line, "U0") != NULL) {
fprintf_P(inout, PSTR("U0\n"));
return;
}
if (strstr(line, "E0") != NULL) {
fprintf_P(inout, PSTR("E0\n"));
return;
}
if (strstr(line, "E1") != NULL) {
fprintf_P(inout, PSTR("E1\n"));
return;
}
if (strstr(line, "E2") != NULL) {
fprintf_P(inout, PSTR("E2\n"));
return;
}
if (strstr(line, "E3") != NULL) {
fprintf_P(inout, PSTR("E3\n"));
return;
}
if (strstr(line, "E4") != NULL) {
fprintf_P(inout, PSTR("E4\n"));
return;
}
if (strstr(line, "R0") != NULL) {
fprintf_P(inout, PSTR("R0\n"));
return;
}
if (strstr(line, "FS") != NULL) {
fprintf_P(inout, PSTR("FS\n"));
return;
}
if (strstr(line, "FL") != NULL) {
fprintf_P(inout, PSTR("FS\n"));
return;
}
}
count = 0;
if (sscanf_P(line, PSTR("T%d"), &value) > 0) {
//T-code scanned
if ((value >= 0) && (value < EXTRUDERS)) {
if ((active_extruder == value) & (isFilamentLoaded)) {
duplicateTCmd = true;
fprintf_P(inout, PSTR("ok\n"));
} else {
mmuFSensorLoading = true;
duplicateTCmd = false;
toolChange(value);
fprintf_P(inout, PSTR("FL\n"));
if (load_filament_at_toolChange){
load_filament_withSensor();
load_filament_at_toolChange = false;
}
}
}
} else if (sscanf_P(line, PSTR("L%d"), &value) > 0) {
// Load filament
if ((value >= 0) && (value < EXTRUDERS) && !isFilamentLoaded) {
select_extruder(value);
delay(10);
feed_filament();
delay(100);
fprintf_P(inout, PSTR("ok\n"));
}
} else if (sscanf_P(line, PSTR("M%d"), &value) > 0) {
// M0: set to normal mode; M1: set to stealth mode
switch (value) {
case 0:
tmc2130_mode = NORMAL_MODE;
break;
case 1:
tmc2130_mode = STEALTH_MODE;
break;
default:
return;
}
//init all axes
tmc2130_init(tmc2130_mode);
fprintf_P(inout, PSTR("ok\n"));
} else if (sscanf_P(line, PSTR("U%d"), &value) > 0) { // Unload filament
unload_filament_withSensor();
delay(200);
fprintf_P(inout, PSTR("ok\n"));
isPrinting = false;
trackToolChanges = 0;
} else if (sscanf_P(line, PSTR("X%d"), &value) > 0) {
if (value == 0) { // MMU reset
wdt_enable(WDTO_15MS);
}
} else if (sscanf_P(line, PSTR("P%d"), &value) > 0) {
if (value == 0) { // Read finda
fprintf_P(inout, PSTR("%dok\n"), digitalRead(A1));
}
} else if (sscanf_P(line, PSTR("S%d"), &value) > 0) {
if (value == 0) { // return ok
fprintf_P(inout, PSTR("ok\n"));
} else if (value == 1) { // Read version
fprintf_P(inout, PSTR("%dok\n"), FW_VERSION);
} else if (value == 2) { // Read build nr
fprintf_P(inout, PSTR("%dok\n"), FW_BUILDNR);
}
} else if (strstr(line, "FS") > 0) {
fsensor_triggered = true;
fprintf_P(inout, PSTR("ok\n"));
} else if (sscanf_P(line, PSTR("F%d %d"), &value, &value0) > 0) {
if (((value >= 0) && (value < EXTRUDERS)) && ((value0 >= 0) && (value0 <= 2))) {
filament_type[value] = value0;
fprintf_P(inout, PSTR("ok\n"));
}
} else if (sscanf_P(line, PSTR("C%d"), &value) > 0) {
if (value == 0) // C0 continue loading current filament (used after T-code), maybe add different code for
// each extruder (the same way as T-codes) in the future?
{
if (!duplicateTCmd) {
load_filament_into_extruder();
fprintf_P(inout, PSTR("ok\n"));
} else fprintf_P(inout, PSTR("ok\n"));
}
} else if (sscanf_P(line, PSTR("E%d"), &value) > 0) {
if ((value >= 0) && (value < EXTRUDERS)) { // Ex: eject filament
eject_filament(value);
fprintf_P(inout, PSTR("ok\n"));
}
} else if (sscanf_P(line, PSTR("R%d"), &value) > 0) {
if (value == 0) { // R0: recover after eject filament
recover_after_eject();
fprintf_P(inout, PSTR("ok\n"));
}
}
}
}
} // extern C
void process_signals()
{
// what to do here?
}
void fault_handler(Fault id)
{
while (1) {
shr16_set_led(id + 1);
delay(1000);
shr16_set_led(0);
delay(2000);
}
}
//****************************************************************************************************
//* this routine is the common routine called for fixing the filament issues (loading or unloading)
//****************************************************************************************************
void fixTheProblem(void) {
fixedTheProblem = false;
fixTheProblems = true;
engage_filament_pulley(false); // park the idler stepper motor
delay(50);
tmc2130_disable_axis(AX_SEL, tmc2130_mode);
while (!(Btn::middle == buttonClicked() && digitalRead(A1) == 1)) {
// wait until key is entered to proceed (this is to allow for operator intervention)
/*if (Btn::middle == buttonClicked() && digitalRead(A1) == 0) {
break;
}*/
delay(100);
shr16_set_led(0x000);
delay(100);
if (digitalRead(A1) == 1) {
shr16_set_led(2 << 2 * (4 - active_extruder));
} else {
shr16_set_led(1 << 2 * (4 - active_extruder));
}
process_commands(uart_com);
}
tmc2130_init_axis(AX_SEL, tmc2130_mode); // turn ON the selector stepper motor
homeSelectorSmooth();
reset_positions(AX_SEL, 0, active_extruder, ACC_NORMAL);
isFilamentLoaded = false;
delay(10); // wait for 10 millisecond
fixedTheProblem = true;
}
bool load_filament_withSensor()
{
loop:
{
engage_filament_pulley(true); // if idler is in parked position un-park him get in contact with filament
tmc2130_init_axis(AX_PUL, tmc2130_mode);
uint8_t current_loading_normal[3] = CURRENT_LOADING_NORMAL;
uint8_t current_loading_stealth[3] = CURRENT_LOADING_STEALTH;
uint8_t current_running_normal[3] = CURRENT_RUNNING_NORMAL;
uint8_t current_running_stealth[3] = CURRENT_RUNNING_STEALTH;
uint8_t current_holding_normal[3] = CURRENT_HOLDING_NORMAL;
uint8_t current_holding_stealth[3] = CURRENT_HOLDING_STEALTH;
unsigned long startTime, currentTime;
bool tag = false;
// load filament until FINDA senses end of the filament, means correctly loaded into the selector
// we can expect something like 570 steps to get in sensor
if (tmc2130_mode == NORMAL_MODE) {
tmc2130_init_axis_current_normal(AX_PUL, current_holding_normal[AX_PUL],
current_loading_normal[AX_PUL]);
} else {
tmc2130_init_axis_current_normal(AX_PUL, current_holding_stealth[AX_PUL],
current_loading_stealth[AX_PUL]);
}
if (moveSmooth(AX_PUL, 2500, 650, false, false, ACC_NORMAL, true) == MR_Success) {
if (tmc2130_mode == NORMAL_MODE) {
tmc2130_init_axis_current_normal(AX_PUL, current_holding_normal[AX_PUL],
current_running_normal[AX_PUL]);
} else {
tmc2130_init_axis_current_normal(AX_PUL, current_holding_stealth[AX_PUL],
current_running_stealth[AX_PUL]);
}
moveSmooth(AX_PUL, 8500, MAX_SPEED_PUL, false, false, ACC_FEED_NORMAL);
startTime = millis();
fsensor_triggered = false;
process_commands(uart_com);
while (tag == false) {
currentTime = millis();
if ((currentTime - startTime) > 12000) {
fixTheProblem();
goto loop;
}
move_pulley(2,MAX_SPEED_PUL);
process_commands(uart_com);
if (fsensor_triggered == true) tag = true;
delayMicroseconds(500); ///RMM:TODO changed to 300 from 600us on 3 Nov 18
}
mmuFSensorLoading = false;
fsensor_triggered = false;
//delayMicroseconds(600);
moveSmooth(AX_PUL, STEPS_MK3FSensor_To_Bondtech, 350,false, false);
isFilamentLoaded = true; // filament loaded
shr16_set_led(0x000);
shr16_set_led(2 << 2 * (4 - active_extruder));
return true;
}
fixTheProblem();
goto loop;
shr16_set_led(0x000);
shr16_set_led(2 << 2 * (4 - active_extruder));
return false;
}
}
/**
* @brief unload_filament_withSensor
* unloads filament from extruder - filament is above Bondtech gears
*/
bool unload_filament_withSensor()
{
bool _return = false;
tmc2130_init_axis(AX_PUL, tmc2130_mode);
tmc2130_init_axis(AX_IDL, tmc2130_mode);
engage_filament_pulley(true); // if idler is in parked position un-park him get in contact with filament
moveSmooth(AX_PUL, -400, 350, false, false);
switch (moveSmooth(AX_PUL, -12000, MAX_SPEED_PUL - (MAX_SPEED_PUL/5), false, false, ACC_FEED_NORMAL, true)) {
case MR_Success:
moveSmooth(AX_PUL, -50, 650, false, false, ACC_NORMAL);
moveSmooth(AX_PUL, 600, 650, false, false, ACC_NORMAL, true);
moveSmooth(AX_PUL, -600, 650, false, false, ACC_NORMAL);
if (digitalRead(A1) == 1) {
fixTheProblem();
return;
}
isFilamentLoaded = false; // filament unloaded
_return = true;
break;
default:
fixTheProblem();
}
tmc2130_disable_axis(AX_PUL, tmc2130_mode);
engage_filament_pulley(false);
return _return;
}