Browse Source

Flags for MarlinSerial instance features (#21318)

X-Ryl669 4 years ago
parent
commit
139c149486
No account linked to committer's email address

+ 4
- 3
Marlin/src/core/bug_on.h View File

27
   // Useful macro for stopping the CPU on an unexpected condition
27
   // Useful macro for stopping the CPU on an unexpected condition
28
   // This is used like SERIAL_ECHOPAIR, that is: a key-value call of the local variables you want
28
   // This is used like SERIAL_ECHOPAIR, that is: a key-value call of the local variables you want
29
   // to dump to the serial port before stopping the CPU.
29
   // to dump to the serial port before stopping the CPU.
30
-  #define BUG_ON(V...) do { SERIAL_ECHOPAIR(ONLY_FILENAME, __LINE__, ": "); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0)
30
+                          // \/ Don't replace by SERIAL_ECHOPAIR since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building
31
+  #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLN(": "); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0)
31
 #elif ENABLED(MARLIN_DEV_MODE)
32
 #elif ENABLED(MARLIN_DEV_MODE)
32
   // Don't stop the CPU here, but at least dump the bug on the serial port
33
   // Don't stop the CPU here, but at least dump the bug on the serial port
33
-  //#define BUG_ON(V...) do { SERIAL_ECHOPAIR(ONLY_FILENAME, __LINE__, ": BUG!\n"); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); } while(0)
34
-  #define BUG_ON(V...) NOOP
34
+                          // \/ Don't replace by SERIAL_ECHOPAIR since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building
35
+  #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLN(": BUG!"); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); } while(0)
35
 #else
36
 #else
36
   // Release mode, let's ignore the bug
37
   // Release mode, let's ignore the bug
37
   #define BUG_ON(V...) NOOP
38
   #define BUG_ON(V...) NOOP

+ 37
- 7
Marlin/src/core/macros.h View File

318
 
318
 
319
   #endif
319
   #endif
320
 
320
 
321
+  // Allow manipulating enumeration value like flags without ugly cast everywhere
322
+  #define ENUM_FLAGS(T) \
323
+    FORCE_INLINE constexpr T operator&(T x, T y) { return static_cast<T>(static_cast<int>(x) & static_cast<int>(y)); } \
324
+    FORCE_INLINE constexpr T operator|(T x, T y) { return static_cast<T>(static_cast<int>(x) | static_cast<int>(y)); } \
325
+    FORCE_INLINE constexpr T operator^(T x, T y) { return static_cast<T>(static_cast<int>(x) ^ static_cast<int>(y)); } \
326
+    FORCE_INLINE constexpr T operator~(T x)      { return static_cast<T>(~static_cast<int>(x)); } \
327
+    FORCE_INLINE T & operator&=(T &x, T y) { return x &= y; } \
328
+    FORCE_INLINE T & operator|=(T &x, T y) { return x |= y; } \
329
+    FORCE_INLINE T & operator^=(T &x, T y) { return x ^= y; }
330
+
321
   // C++11 solution that is standard compliant. <type_traits> is not available on all platform
331
   // C++11 solution that is standard compliant. <type_traits> is not available on all platform
322
   namespace Private {
332
   namespace Private {
323
     template<bool, typename _Tp = void> struct enable_if { };
333
     template<bool, typename _Tp = void> struct enable_if { };
357
       return *str ? findStringEnd(str + 1) : str;
367
       return *str ? findStringEnd(str + 1) : str;
358
     }
368
     }
359
 
369
 
360
-    // Check whether a string contains a slash
361
-    constexpr bool containsSlash(const char *str) {
362
-      return *str == '/' ? true : (*str ? containsSlash(str + 1) : false);
370
+    // Check whether a string contains a specific character
371
+    constexpr bool contains(const char *str, const char ch) {
372
+      return *str == ch ? true : (*str ? contains(str + 1, ch) : false);
363
     }
373
     }
364
-    // Find the last position of the slash
365
-    constexpr const char* findLastSlashPos(const char *str) {
366
-      return *str == '/' ? (str + 1) : findLastSlashPos(str - 1);
374
+    // Find the last position of the specific character (should be called with findStringEnd)
375
+    constexpr const char* findLastPos(const char *str, const char ch) {
376
+      return *str == ch ? (str + 1) : findLastPos(str - 1, ch);
367
     }
377
     }
368
     // Compile-time evaluation of the last part of a file path
378
     // Compile-time evaluation of the last part of a file path
369
     // Typically used to shorten the path to file in compiled strings
379
     // Typically used to shorten the path to file in compiled strings
370
     // CompileTimeString::baseName(__FILE__) returns "macros.h" and not /path/to/Marlin/src/core/macros.h
380
     // CompileTimeString::baseName(__FILE__) returns "macros.h" and not /path/to/Marlin/src/core/macros.h
371
     constexpr const char* baseName(const char *str) {
381
     constexpr const char* baseName(const char *str) {
372
-      return containsSlash(str) ? findLastSlashPos(findStringEnd(str)) : str;
382
+      return contains(str, '/') ? findLastPos(findStringEnd(str), '/') : str;
383
+    }
384
+
385
+    // Find the first occurence of a character in a string (or return the last position in the string)
386
+    constexpr const char* findFirst(const char *str, const char ch) {
387
+      return *str == ch || *str == 0 ? (str + 1) : findFirst(str + 1, ch);
388
+    }
389
+    // Compute the string length at compile time
390
+    constexpr unsigned stringLen(const char *str) {
391
+      return *str == 0 ? 0 : 1 + stringLen(str + 1);
373
     }
392
     }
374
   }
393
   }
375
 
394
 
376
   #define ONLY_FILENAME CompileTimeString::baseName(__FILE__)
395
   #define ONLY_FILENAME CompileTimeString::baseName(__FILE__)
396
+  /** Get the templated type name. This does not depends on RTTI, but on the preprocessor, so it should be quite safe to use even on old compilers.
397
+      WARNING: DO NOT RENAME THIS FUNCTION (or change the text inside the function to match what the preprocessor will generate)
398
+      The name is chosen very short since the binary will store "const char* gtn(T*) [with T = YourTypeHere]" so avoid long function name here */
399
+  template <typename T>
400
+  inline const char* gtn(T*) {
401
+    // It works on GCC by instantiating __PRETTY_FUNCTION__ and parsing the result. So the syntax here is very limited to GCC output
402
+    constexpr unsigned verboseChatLen = sizeof("const char* gtn(T*) [with T = ") - 1;
403
+    static char templateType[sizeof(__PRETTY_FUNCTION__) - verboseChatLen] = {};
404
+    __builtin_memcpy(templateType, __PRETTY_FUNCTION__ + verboseChatLen, sizeof(__PRETTY_FUNCTION__) - verboseChatLen - 2);
405
+    return templateType;
406
+  }
377
 
407
 
378
 #else
408
 #else
379
 
409
 

+ 1
- 1
Marlin/src/core/serial.h View File

146
 #define AS_CHAR(C) serial_char_t(C)
146
 #define AS_CHAR(C) serial_char_t(C)
147
 
147
 
148
 // SERIAL_ECHO_F prints a floating point value with optional precision
148
 // SERIAL_ECHO_F prints a floating point value with optional precision
149
-inline void SERIAL_ECHO_F(EnsureDouble x, int digit = 2) { SERIAL_IMPL.print(x, digit); }
149
+inline void SERIAL_ECHO_F(EnsureDouble x, int digit=2) { SERIAL_IMPL.print(x, digit); }
150
 
150
 
151
 template <typename T>
151
 template <typename T>
152
 void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }
152
 void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }

+ 48
- 20
Marlin/src/core/serial_base.h View File

45
   constexpr serial_index_t() : index(-1) {}
45
   constexpr serial_index_t() : index(-1) {}
46
 };
46
 };
47
 
47
 
48
-// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
49
-CALL_IF_EXISTS_IMPL(void, flushTX);
50
-CALL_IF_EXISTS_IMPL(bool, connected, true);
51
-
52
 // In order to catch usage errors in code, we make the base to encode number explicit
48
 // In order to catch usage errors in code, we make the base to encode number explicit
53
 // If given a number (and not this enum), the compiler will reject the overload, falling back to the (double, digit) version
49
 // If given a number (and not this enum), the compiler will reject the overload, falling back to the (double, digit) version
54
 // We don't want hidden conversion of the first parameter to double, so it has to be as hard to do for the compiler as creating this enum
50
 // We don't want hidden conversion of the first parameter to double, so it has to be as hard to do for the compiler as creating this enum
59
   Bin = 2
55
   Bin = 2
60
 };
56
 };
61
 
57
 
62
-// A simple forward struct that prevent the compiler to select print(double, int) as a default overload for any type different than
63
-// double or float. For double or float, a conversion exists so the call will be transparent
58
+// A simple feature list enumeration
59
+enum class SerialFeature {
60
+  None                = 0x00,
61
+  MeatPack            = 0x01,   //!< Enabled when Meatpack is present
62
+  BinaryFileTransfer  = 0x02,   //!< Enabled for BinaryFile transfer support (in the future)
63
+  Virtual             = 0x04,   //!< Enabled for virtual serial port (like Telnet / Websocket / ...)
64
+  Hookable            = 0x08,   //!< Enabled if the serial class supports a setHook method
65
+};
66
+ENUM_FLAGS(SerialFeature);
67
+
68
+// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
69
+CALL_IF_EXISTS_IMPL(void, flushTX);
70
+CALL_IF_EXISTS_IMPL(bool, connected, true);
71
+CALL_IF_EXISTS_IMPL(SerialFeature, features, SerialFeature::None);
72
+
73
+// A simple forward struct to prevent the compiler from selecting print(double, int) as a default overload
74
+// for any type other than double/float. For double/float, a conversion exists so the call will be invisible.
64
 struct EnsureDouble {
75
 struct EnsureDouble {
65
   double a;
76
   double a;
66
   FORCE_INLINE operator double() { return a; }
77
   FORCE_INLINE operator double() { return a; }
67
-  // If the compiler breaks on ambiguity here, it's likely because you're calling print(X, base) with X not a double or a float, and a
68
-  // base that's not one of PrintBase's value. This exact code is made to detect such error, you NEED to set a base explicitely like this:
78
+  // If the compiler breaks on ambiguity here, it's likely because print(X, base) is called with X not a double/float, and
79
+  // a base that's not a PrintBase value. This code is made to detect the error. You MUST set a base explicitly like this:
69
   // SERIAL_PRINT(v, PrintBase::Hex)
80
   // SERIAL_PRINT(v, PrintBase::Hex)
70
   FORCE_INLINE EnsureDouble(double a) : a(a) {}
81
   FORCE_INLINE EnsureDouble(double a) : a(a) {}
71
   FORCE_INLINE EnsureDouble(float a) : a(a) {}
82
   FORCE_INLINE EnsureDouble(float a) : a(a) {}
72
 };
83
 };
73
 
84
 
74
-// Using Curiously Recurring Template Pattern here to avoid virtual table cost when compiling.
85
+// Using Curiously-Recurring Template Pattern here to avoid virtual table cost when compiling.
75
 // Since the real serial class is known at compile time, this results in the compiler writing
86
 // Since the real serial class is known at compile time, this results in the compiler writing
76
 // a completely efficient code.
87
 // a completely efficient code.
77
 template <class Child>
88
 template <class Child>
85
     SerialBase(const bool) {}
96
     SerialBase(const bool) {}
86
   #endif
97
   #endif
87
 
98
 
99
+  #define SerialChild static_cast<Child*>(this)
100
+
88
   // Static dispatch methods below:
101
   // Static dispatch methods below:
89
   // The most important method here is where it all ends to:
102
   // The most important method here is where it all ends to:
90
-  size_t write(uint8_t c)           { return static_cast<Child*>(this)->write(c); }
103
+  size_t write(uint8_t c)           { return SerialChild->write(c); }
104
+
91
   // Called when the parser finished processing an instruction, usually build to nothing
105
   // Called when the parser finished processing an instruction, usually build to nothing
92
-  void msgDone()                    { static_cast<Child*>(this)->msgDone(); }
93
-  // Called upon initialization
94
-  void begin(const long baudRate)   { static_cast<Child*>(this)->begin(baudRate); }
95
-  // Called upon destruction
96
-  void end()                        { static_cast<Child*>(this)->end(); }
106
+  void msgDone() const              { SerialChild->msgDone(); }
107
+
108
+  // Called on initialization
109
+  void begin(const long baudRate)   { SerialChild->begin(baudRate); }
110
+
111
+  // Called on destruction
112
+  void end()                        { SerialChild->end(); }
113
+
97
   /** Check for available data from the port
114
   /** Check for available data from the port
98
       @param index  The port index, usually 0 */
115
       @param index  The port index, usually 0 */
99
-  int available(serial_index_t index = 0)  { return static_cast<Child*>(this)->available(index); }
116
+  int available(serial_index_t index=0) const { return SerialChild->available(index); }
117
+
100
   /** Read a value from the port
118
   /** Read a value from the port
101
       @param index  The port index, usually 0 */
119
       @param index  The port index, usually 0 */
102
-  int  read(serial_index_t index = 0)      { return static_cast<Child*>(this)->read(index); }
120
+  int read(serial_index_t index=0)        { return SerialChild->read(index); }
121
+
122
+  /** Combine the features of this serial instance and return it
123
+      @param index  The port index, usually 0 */
124
+  SerialFeature features(serial_index_t index=0) const { return static_cast<const Child*>(this)->features(index);  }
125
+
126
+  // Check if the serial port has a feature
127
+  bool has_feature(serial_index_t index, SerialFeature flag) const { (features(index) & flag) != SerialFeature::None; }
128
+
103
   // Check if the serial port is connected (usually bypassed)
129
   // Check if the serial port is connected (usually bypassed)
104
-  bool connected()                  { return static_cast<Child*>(this)->connected(); }
130
+  bool connected() const            { return SerialChild->connected(); }
131
+
105
   // Redirect flush
132
   // Redirect flush
106
-  void flush()                      { static_cast<Child*>(this)->flush(); }
133
+  void flush()                      { SerialChild->flush(); }
134
+
107
   // Not all implementation have a flushTX, so let's call them only if the child has the implementation
135
   // Not all implementation have a flushTX, so let's call them only if the child has the implementation
108
-  void flushTX()                    { CALL_IF_EXISTS(void, static_cast<Child*>(this), flushTX); }
136
+  void flushTX()                    { CALL_IF_EXISTS(void, SerialChild, flushTX); }
109
 
137
 
110
   // Glue code here
138
   // Glue code here
111
   FORCE_INLINE void write(const char *str)                    { while (*str) write(*str++); }
139
   FORCE_INLINE void write(const char *str)                    { while (*str) write(*str++); }

+ 23
- 4
Marlin/src/core/serial_hook.h View File

65
   bool connected()              { return CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected);; }
65
   bool connected()              { return CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected);; }
66
   void flushTX()                { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
66
   void flushTX()                { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
67
 
67
 
68
+  SerialFeature features(serial_index_t index) const { return CALL_IF_EXISTS(SerialFeature, static_cast<const SerialT*>(this), features, index);  }
69
+
68
   // We have 2 implementation of the same method in both base class, let's say which one we want
70
   // We have 2 implementation of the same method in both base class, let's say which one we want
69
   using SerialT::available;
71
   using SerialT::available;
70
   using SerialT::read;
72
   using SerialT::read;
98
   bool connected()          { return CALL_IF_EXISTS(bool, &out, connected); }
100
   bool connected()          { return CALL_IF_EXISTS(bool, &out, connected); }
99
   void flushTX()            { CALL_IF_EXISTS(void, &out, flushTX); }
101
   void flushTX()            { CALL_IF_EXISTS(void, &out, flushTX); }
100
 
102
 
101
-  int available(serial_index_t )  { return (int)out.available(); }
102
-  int read(serial_index_t )       { return (int)out.read(); }
103
+  int available(serial_index_t)   { return (int)out.available(); }
104
+  int read(serial_index_t)        { return (int)out.read(); }
103
   int available()                 { return (int)out.available(); }
105
   int available()                 { return (int)out.available(); }
104
   int read()                      { return (int)out.read(); }
106
   int read()                      { return (int)out.read(); }
107
+  SerialFeature features(serial_index_t index) const  { return CALL_IF_EXISTS(SerialFeature, &out, features, index);  }
105
 
108
 
106
   ConditionalSerial(bool & conditionVariable, SerialT & out, const bool e) : BaseClassT(e), condition(conditionVariable), out(out) {}
109
   ConditionalSerial(bool & conditionVariable, SerialT & out, const bool e) : BaseClassT(e), condition(conditionVariable), out(out) {}
107
 };
110
 };
126
   int read(serial_index_t)      { return (int)out.read(); }
129
   int read(serial_index_t)      { return (int)out.read(); }
127
   int available()               { return (int)out.available(); }
130
   int available()               { return (int)out.available(); }
128
   int read()                    { return (int)out.read(); }
131
   int read()                    { return (int)out.read(); }
132
+  SerialFeature features(serial_index_t index) const  { return CALL_IF_EXISTS(SerialFeature, &out, features, index);  }
129
 
133
 
130
   ForwardSerial(const bool e, SerialT & out) : BaseClassT(e), out(out) {}
134
   ForwardSerial(const bool e, SerialT & out) : BaseClassT(e), out(out) {}
131
 };
135
 };
163
 
167
 
164
   // Underlying implementation might use Arduino's bool operator
168
   // Underlying implementation might use Arduino's bool operator
165
   bool connected() {
169
   bool connected() {
166
-    return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected) : static_cast<SerialT*>(this)->operator bool();
170
+    return Private::HasMember_connected<SerialT>::value
171
+      ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected)
172
+      : static_cast<SerialT*>(this)->operator bool();
167
   }
173
   }
168
-  void flushTX()                { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
174
+
175
+  void flushTX() { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
176
+
177
+  // Append Hookable for this class
178
+  SerialFeature features(serial_index_t index) const  { return SerialFeature::Hookable | CALL_IF_EXISTS(SerialFeature, static_cast<const SerialT*>(this), features, index);  }
169
 
179
 
170
   void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
180
   void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
171
     // Order is important here as serial code can be called inside interrupts
181
     // Order is important here as serial code can be called inside interrupts
251
     if (portMask.enabled(SecondOutput))  CALL_IF_EXISTS(void, &serial1, flushTX);
261
     if (portMask.enabled(SecondOutput))  CALL_IF_EXISTS(void, &serial1, flushTX);
252
   }
262
   }
253
 
263
 
264
+  // Forward feature queries
265
+  SerialFeature features(serial_index_t index) const  {
266
+    if (index.within(0 + offset, step + offset - 1))
267
+      return serial0.features(index);
268
+    else if (index.within(step + offset, 2 * step + offset - 1))
269
+      return serial1.features(index);
270
+    return SerialFeature::None;
271
+  }
272
+
254
   MultiSerial(Serial0T & serial0, Serial1T & serial1, const SerialMask mask = Both, const bool e = false) :
273
   MultiSerial(Serial0T & serial0, Serial1T & serial1, const SerialMask mask = Both, const bool e = false) :
255
     BaseClassT(e),
274
     BaseClassT(e),
256
     portMask(mask), serial0(serial0), serial1(serial1) {}
275
     portMask(mask), serial0(serial0), serial1(serial1) {}

+ 2
- 0
Marlin/src/feature/meatpack.h View File

142
   // Existing instances implement Arduino's operator bool, so use that if it's available
142
   // Existing instances implement Arduino's operator bool, so use that if it's available
143
   bool connected()                    { return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
143
   bool connected()                    { return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
144
   void flushTX()                      { CALL_IF_EXISTS(void, &out, flushTX); }
144
   void flushTX()                      { CALL_IF_EXISTS(void, &out, flushTX); }
145
+  SerialFeature features(serial_index_t index) const  { return SerialFeature::MeatPack | CALL_IF_EXISTS(SerialFeature, &out, features, index);  }
146
+
145
 
147
 
146
   int available(serial_index_t index) {
148
   int available(serial_index_t index) {
147
     if (charCount) return charCount;          // The buffer still has data
149
     if (charCount) return charCount;          // The buffer still has data

+ 5
- 0
Marlin/src/gcode/gcode_d.cpp View File

167
         dump_delay_accuracy_check();
167
         dump_delay_accuracy_check();
168
         break;
168
         break;
169
 
169
 
170
+      case 7: // D7 dump the current serial port type (hence configuration)
171
+        SERIAL_ECHOLNPAIR("Current serial configuration RX_BS:", RX_BUFFER_SIZE, ", TX_BS:", TX_BUFFER_SIZE);
172
+        SERIAL_ECHOLN(gtn(&SERIAL_IMPL));
173
+        break;
174
+
170
       case 100: { // D100 Disable heaters and attempt a hard hang (Watchdog Test)
175
       case 100: { // D100 Disable heaters and attempt a hard hang (Watchdog Test)
171
         SERIAL_ECHOLNPGM("Disabling heaters and attempting to trigger Watchdog");
176
         SERIAL_ECHOLNPGM("Disabling heaters and attempting to trigger Watchdog");
172
         SERIAL_ECHOLNPGM("(USE_WATCHDOG " TERN(USE_WATCHDOG, "ENABLED", "DISABLED") ")");
177
         SERIAL_ECHOLNPGM("(USE_WATCHDOG " TERN(USE_WATCHDOG, "ENABLED", "DISABLED") ")");

+ 7
- 2
Marlin/src/gcode/host/M115.cpp View File

22
 
22
 
23
 #include "../gcode.h"
23
 #include "../gcode.h"
24
 #include "../../inc/MarlinConfig.h"
24
 #include "../../inc/MarlinConfig.h"
25
+#include "../queue.h"           // for getting the command port
26
+
25
 
27
 
26
 #if ENABLED(M115_GEOMETRY_REPORT)
28
 #if ENABLED(M115_GEOMETRY_REPORT)
27
   #include "../../module/motion.h"
29
   #include "../../module/motion.h"
59
 
61
 
60
   #if ENABLED(EXTENDED_CAPABILITIES_REPORT)
62
   #if ENABLED(EXTENDED_CAPABILITIES_REPORT)
61
 
63
 
64
+    // The port that sent M115
65
+    serial_index_t port = queue.ring_buffer.command_port();
66
+
62
     // PAREN_COMMENTS
67
     // PAREN_COMMENTS
63
     TERN_(PAREN_COMMENTS, cap_line(PSTR("PAREN_COMMENTS"), true));
68
     TERN_(PAREN_COMMENTS, cap_line(PSTR("PAREN_COMMENTS"), true));
64
 
69
 
69
     cap_line(PSTR("SERIAL_XON_XOFF"), ENABLED(SERIAL_XON_XOFF));
74
     cap_line(PSTR("SERIAL_XON_XOFF"), ENABLED(SERIAL_XON_XOFF));
70
 
75
 
71
     // BINARY_FILE_TRANSFER (M28 B1)
76
     // BINARY_FILE_TRANSFER (M28 B1)
72
-    cap_line(PSTR("BINARY_FILE_TRANSFER"), ENABLED(BINARY_FILE_TRANSFER));
77
+    cap_line(PSTR("BINARY_FILE_TRANSFER"), ENABLED(BINARY_FILE_TRANSFER)); // TODO: Use SERIAL_IMPL.has_feature(port, SerialFeature::BinaryFileTransfer) once implemented
73
 
78
 
74
     // EEPROM (M500, M501)
79
     // EEPROM (M500, M501)
75
     cap_line(PSTR("EEPROM"), ENABLED(EEPROM_SETTINGS));
80
     cap_line(PSTR("EEPROM"), ENABLED(EEPROM_SETTINGS));
148
     cap_line(PSTR("COOLER_TEMPERATURE"), ENABLED(HAS_COOLER));
153
     cap_line(PSTR("COOLER_TEMPERATURE"), ENABLED(HAS_COOLER));
149
 
154
 
150
     // MEATPACK Compression
155
     // MEATPACK Compression
151
-    cap_line(PSTR("MEATPACK"), ENABLED(HAS_MEATPACK));
156
+    cap_line(PSTR("MEATPACK"), SERIAL_IMPL.has_feature(port, SerialFeature::MeatPack));
152
 
157
 
153
     // Machine Geometry
158
     // Machine Geometry
154
     #if ENABLED(M115_GEOMETRY_REPORT)
159
     #if ENABLED(M115_GEOMETRY_REPORT)

Loading…
Cancel
Save