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