Filament_sensor.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #pragma once
  2. #include <inttypes.h>
  3. #include "cmdqueue.h"
  4. #include "pins.h"
  5. #include "fastio.h"
  6. #include "adc.h"
  7. #include "pat9125.h"
  8. #define FSENSOR_IR 1
  9. #define FSENSOR_IR_ANALOG 2
  10. #define FSENSOR_PAT9125 3
  11. /// Can be used to block printer's filament sensor handling - to avoid errorneous injecting of M600
  12. /// while doing a toolchange with the MMU
  13. /// In case of "no filament sensor" these methods default to an empty implementation
  14. class FSensorBlockRunout {
  15. public:
  16. FSensorBlockRunout();
  17. ~FSensorBlockRunout();
  18. };
  19. /// Base class Filament sensor
  20. ///
  21. /// Ideally, there could have been a nice class hierarchy of filament sensor types with common functionality
  22. /// extracted into this base class.
  23. /// But:
  24. /// - virtual methods take more space
  25. /// - we don't need to switch among different filament sensors at runtime
  26. /// Therefore the class hierarchy carefully avoids using virtual methods and doesn't look too fancy.
  27. #ifdef FILAMENT_SENSOR
  28. class Filament_sensor {
  29. public:
  30. enum class State : uint8_t {
  31. disabled = 0,
  32. initializing,
  33. ready,
  34. error,
  35. };
  36. enum class SensorActionOnError : uint8_t {
  37. _Continue = 0,
  38. _Pause = 1,
  39. _Undef = EEPROM_EMPTY_VALUE
  40. };
  41. static void setEnabled(bool enabled);
  42. void setAutoLoadEnabled(bool state, bool updateEEPROM = false);
  43. bool getAutoLoadEnabled() const { return autoLoadEnabled; }
  44. void setRunoutEnabled(bool state, bool updateEEPROM = false);
  45. bool getRunoutEnabled() const { return runoutEnabled; }
  46. void setActionOnError(SensorActionOnError state, bool updateEEPROM = false);
  47. SensorActionOnError getActionOnError() const { return sensorActionOnError; }
  48. bool getFilamentLoadEvent() const { return postponedLoadEvent; }
  49. bool isError() const { return state == State::error; }
  50. bool isReady() const { return state == State::ready; }
  51. bool isEnabled() const { return state != State::disabled; }
  52. protected:
  53. void settings_init_common();
  54. bool checkFilamentEvents();
  55. void triggerFilamentInserted();
  56. void triggerFilamentRemoved();
  57. static void filAutoLoad();
  58. void filRunout();
  59. void triggerError();
  60. State state;
  61. bool autoLoadEnabled;
  62. bool runoutEnabled;
  63. bool oldFilamentPresent; //for creating filament presence switching events.
  64. bool postponedLoadEvent; //this event lasts exactly one update cycle. It is long enough to be able to do polling for load event.
  65. ShortTimer eventBlankingTimer;
  66. SensorActionOnError sensorActionOnError;
  67. };
  68. #if (FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
  69. class IR_sensor: public Filament_sensor {
  70. public:
  71. void init();
  72. void deinit();
  73. bool update();
  74. bool getFilamentPresent() const { return !READ(IR_SENSOR_PIN); }
  75. #ifdef FSENSOR_PROBING
  76. static bool probeOtherType(); //checks if the wrong fsensor type is detected.
  77. #endif
  78. void settings_init();
  79. };
  80. #if (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
  81. constexpr static uint16_t Voltage2Raw(float V) {
  82. return (V * 1023 * OVERSAMPLENR / VOLT_DIV_REF ) + 0.5F;
  83. }
  84. constexpr static float Raw2Voltage(uint16_t raw) {
  85. return VOLT_DIV_REF * (raw / (1023.F * OVERSAMPLENR));
  86. }
  87. class IR_sensor_analog: public IR_sensor {
  88. public:
  89. void init();
  90. bool update();
  91. void voltUpdate(uint16_t raw);
  92. uint16_t __attribute__((noinline)) getVoltRaw();
  93. enum class SensorRevision : uint8_t {
  94. _Old = 0,
  95. _Rev04 = 1,
  96. _Undef = EEPROM_EMPTY_VALUE
  97. };
  98. SensorRevision getSensorRevision() const { return sensorRevision; }
  99. const char* __attribute__((noinline)) getIRVersionText();
  100. void setSensorRevision(SensorRevision rev, bool updateEEPROM = false);
  101. constexpr static uint16_t IRsensor_Ldiode_TRESHOLD = Voltage2Raw(0.3F); // ~0.3V, raw value=982
  102. constexpr static uint16_t IRsensor_Lmax_TRESHOLD = Voltage2Raw(1.5F); // ~1.5V (0.3*Vcc), raw value=4910
  103. constexpr static uint16_t IRsensor_Hmin_TRESHOLD = Voltage2Raw(3.0F); // ~3.0V (0.6*Vcc), raw value=9821
  104. constexpr static uint16_t IRsensor_Hopen_TRESHOLD = Voltage2Raw(4.6F); // ~4.6V (N.C. @ Ru~20-50k, Rd'=56k, Ru'=10k), raw value=15059
  105. constexpr static uint16_t IRsensor_VMax_TRESHOLD = Voltage2Raw(5.F); // ~5V, raw value=16368
  106. private:
  107. SensorRevision sensorRevision;
  108. bool voltReady; // set by the adc ISR, therefore avoid accessing the variable directly but use getVoltReady()
  109. bool getVoltReady()const;
  110. void clearVoltReady();
  111. uint16_t voltRaw; // set by the adc ISR, therefore avoid accessing the variable directly but use getVoltRaw()
  112. bool checkVoltage(uint16_t raw);
  113. uint16_t minVolt = Voltage2Raw(6.F);
  114. uint16_t maxVolt = 0;
  115. uint16_t nFSCheckCount;
  116. uint8_t voltageErrorCnt;
  117. static constexpr uint16_t FS_CHECK_COUNT = 4;
  118. /// Switching mechanism of the fsensor type.
  119. /// Called from 2 spots which have a very similar behavior
  120. /// 1: SensorRevision::_Old -> SensorRevision::_Rev04 and print _i("FS v0.4 or newer")
  121. /// 2: SensorRevision::_Rev04 -> sensorRevision=SensorRevision::_Old and print _i("FS v0.3 or older")
  122. void IR_ANALOG_Check(SensorRevision isVersion, SensorRevision switchTo);
  123. };
  124. #endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
  125. #endif //(FILAMENT_SENSOR_TYPE == FSENSOR_IR) || (FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG)
  126. #if (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
  127. class PAT9125_sensor: public Filament_sensor {
  128. public:
  129. void init();
  130. void deinit();
  131. bool update();
  132. bool getFilamentPresent() const { return filterFilPresent; }
  133. #ifdef FSENSOR_PROBING
  134. bool probeOtherType(); //checks if the wrong fsensor type is detected.
  135. #endif
  136. void setJamDetectionEnabled(bool state, bool updateEEPROM = false);
  137. bool getJamDetectionEnabled() const { return jamDetection; }
  138. void stStep(bool rev) { //from stepper isr
  139. stepCount += rev ? -1 : 1;
  140. }
  141. void settings_init();
  142. private:
  143. static constexpr uint16_t pollingPeriod = 10; //[ms]
  144. static constexpr uint8_t filterCnt = 5; //how many checks need to be done in order to determine the filament presence precisely.
  145. ShortTimer pollingTimer;
  146. uint8_t filter;
  147. uint8_t filterFilPresent;
  148. bool jamDetection;
  149. int16_t oldPos;
  150. int16_t stepCount;
  151. int16_t chunkSteps;
  152. uint8_t jamErrCnt;
  153. constexpr void calcChunkSteps(float u) {
  154. chunkSteps = (int16_t)(1.25 * u); //[mm]
  155. }
  156. int16_t getStepCount();
  157. void resetStepCount();
  158. void filJam();
  159. bool updatePAT9125();
  160. };
  161. #endif //(FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
  162. #if FILAMENT_SENSOR_TYPE == FSENSOR_IR
  163. extern IR_sensor fsensor;
  164. #elif FILAMENT_SENSOR_TYPE == FSENSOR_IR_ANALOG
  165. extern IR_sensor_analog fsensor;
  166. #elif FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125
  167. extern PAT9125_sensor fsensor;
  168. #endif
  169. #endif //FILAMENT_SENSOR