Prusa-Firmware/Firmware/Prusa_farm.cpp
Alex Voinea 39eb728d54 More farm optimizations
Kudos @gudnimg
2022-08-30 13:57:43 +02:00

505 lines
13 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
#define NC_TIME 10 //time in s for periodic important status messages sending which needs reponse from monitoring
#define NC_BUTTON_LONG_PRESS 15 //time in s
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