Filament_sensor.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #pragma once
  2. #include <inttypes.h>
  3. #include <stdio.h>
  4. #include <avr/pgmspace.h>
  5. #include <util/atomic.h>
  6. #include "Marlin.h"
  7. #include "ultralcd.h"
  8. #include "menu.h"
  9. #include "cardreader.h"
  10. #include "temperature.h"
  11. #include "cmdqueue.h"
  12. #include "eeprom.h"
  13. #include "pins.h"
  14. #include "fastio.h"
  15. class Filament_sensor {
  16. public:
  17. virtual void init() = 0;
  18. virtual bool update() = 0;
  19. virtual bool getFilamentPresent() = 0;
  20. enum class SensorActionOnError : uint8_t {
  21. _Continue = 0,
  22. _Pause = 1,
  23. _Undef = EEPROM_EMPTY_VALUE
  24. };
  25. void setAutoLoadEnabled(bool state, bool updateEEPROM = false) {
  26. autoLoadEnabled = state;
  27. if (updateEEPROM) {
  28. eeprom_update_byte((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED, state);
  29. }
  30. }
  31. void setRunoutEnabled(bool state, bool updateEEPROM = false) {
  32. runoutEnabled = state;
  33. if (updateEEPROM) {
  34. eeprom_update_byte((uint8_t *)EEPROM_FSENSOR, state);
  35. }
  36. }
  37. bool getFilamentLoadEvent() {
  38. return postponedLoadEvent;
  39. }
  40. protected:
  41. void settings_init() {
  42. autoLoadEnabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_AUTOLOAD_ENABLED);
  43. runoutEnabled = eeprom_read_byte((uint8_t*)EEPROM_FSENSOR);
  44. sensorActionOnError = (SensorActionOnError)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA);
  45. if (sensorActionOnError == SensorActionOnError::_Undef) {
  46. sensorActionOnError = SensorActionOnError::_Pause;
  47. }
  48. }
  49. bool checkFilamentEvents() {
  50. if (!ready)
  51. return false;
  52. bool newFilamentPresent = getFilamentPresent();
  53. if (oldFilamentPresent != newFilamentPresent) {
  54. oldFilamentPresent = newFilamentPresent;
  55. if (newFilamentPresent) { //filament insertion
  56. puts_P(PSTR("filament inserted"));
  57. triggerFilamentInserted();
  58. postponedLoadEvent = true;
  59. }
  60. else { //filament removal
  61. puts_P(PSTR("filament removed"));
  62. triggerFilamentRemoved();
  63. }
  64. return true;
  65. }
  66. return false;
  67. };
  68. void triggerFilamentInserted() {
  69. if (autoLoadEnabled && (eFilamentAction == FilamentAction::None) && !(moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))) {
  70. eFilamentAction = FilamentAction::AutoLoad;
  71. if(target_temperature[0] >= EXTRUDE_MINTEMP){
  72. bFilamentPreheatState = true;
  73. menu_submenu(mFilamentItemForce);
  74. } else {
  75. menu_submenu(lcd_generic_preheat_menu);
  76. lcd_timeoutToStatus.start();
  77. }
  78. }
  79. }
  80. void triggerFilamentRemoved() {
  81. if (runoutEnabled && (eFilamentAction == FilamentAction::None) && !saved_printing && (moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))) {
  82. runoutEnabled = false;
  83. autoLoadEnabled = false;
  84. stop_and_save_print_to_ram(0, 0);
  85. restore_print_from_ram_and_continue(0);
  86. eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
  87. eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
  88. enquecommand_front_P((PSTR("M600")));
  89. }
  90. }
  91. bool autoLoadEnabled;
  92. bool runoutEnabled;
  93. bool oldFilamentPresent; //for creating filament presence switching events.
  94. bool ready;
  95. bool postponedLoadEvent; //this event lasts exactly one update cycle. It is long enough to be able to do polling for load event.
  96. SensorActionOnError sensorActionOnError;
  97. };
  98. class IR_sensor: public Filament_sensor {
  99. public:
  100. void init() {
  101. SET_INPUT(IR_SENSOR_PIN); //input mode
  102. WRITE(IR_SENSOR_PIN, 1); //pullup
  103. settings_init();
  104. }
  105. bool update() {
  106. if (!ready) {
  107. ready = true; //the IR sensor gets ready instantly as it's just a gpio read operation.
  108. oldFilamentPresent = getFilamentPresent(); //initialize the current filament state so that we don't create a switching event right after the sensor is ready.
  109. }
  110. postponedLoadEvent = false;
  111. bool event = checkFilamentEvents();
  112. ;//
  113. return event;
  114. }
  115. bool getFilamentPresent() {
  116. return !READ(IR_SENSOR_PIN);
  117. }
  118. void settings_init() {
  119. Filament_sensor::settings_init();
  120. }
  121. protected:
  122. };
  123. class IR_sensor_analog: public IR_sensor {
  124. public:
  125. void init() {
  126. IR_sensor::init();
  127. ;//
  128. }
  129. bool update() {
  130. bool event = IR_sensor::update();
  131. if (voltReady) {
  132. voltReady = false;
  133. printf_P(PSTR("newVoltRaw:%u\n"), getVoltRaw() / OVERSAMPLENR);
  134. ;//
  135. }
  136. ;//
  137. return event;
  138. }
  139. void voltUpdate(uint16_t raw) { //to be called from the ADC ISR when a cycle is finished
  140. voltRaw = raw;
  141. voltReady = true;
  142. }
  143. uint16_t getVoltRaw() {
  144. uint16_t newVoltRaw;
  145. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  146. newVoltRaw = voltRaw;
  147. }
  148. return newVoltRaw;
  149. }
  150. void settings_init() {
  151. IR_sensor::settings_init();
  152. sensorRevision = (SensorRevision)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_PCB);
  153. }
  154. enum class SensorRevision : uint8_t {
  155. _Old = 0,
  156. _Rev04 = 1,
  157. _Undef = EEPROM_EMPTY_VALUE
  158. };
  159. private:
  160. SensorRevision sensorRevision;
  161. volatile bool voltReady; //this gets set by the adc ISR
  162. volatile uint16_t voltRaw;
  163. };
  164. extern IR_sensor_analog fsensor;