My Marlin configs for Fabrikator Mini and CTC i3 Pro B
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

meatpack.h 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /*
  23. * MeatPack G-code Compression
  24. *
  25. * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com
  26. * Date: Dec. 2020
  27. *
  28. * Specifically optimized for 3D printing G-Code, this is a zero-cost data compression method
  29. * which packs ~180-190% more data into the same amount of bytes going to the CNC controller.
  30. * As a majority of G-Code can be represented by a restricted alphabet, I performed histogram
  31. * analysis on a wide variety of 3D printing gcode samples, and found ~93% of all gcode could
  32. * be represented by the same 15-character alphabet.
  33. *
  34. * This allowed me to design a system of packing 2 8-bit characters into a single byte, assuming
  35. * they fall within this limited 15-character alphabet. Using a 4-bit lookup table, these 8-bit
  36. * characters can be represented by a 4-bit index.
  37. *
  38. * Combined with some logic to allow commingling of full-width characters outside of this 15-
  39. * character alphabet (at the cost of an extra 8-bits per full-width character), and by stripping
  40. * out unnecessary comments, the end result is gcode which is roughly half the original size.
  41. *
  42. * Why did I do this? I noticed micro-stuttering and other data-bottleneck issues while printing
  43. * objects with high curvature, especially at high speeds. There is also the issue of the limited
  44. * baud rate provided by Prusa's Atmega2560-based boards, over the USB serial connection. So soft-
  45. * ware like OctoPrint would also suffer this same micro-stuttering and poor print quality issue.
  46. *
  47. */
  48. #pragma once
  49. #include <stdint.h>
  50. #include "../core/serial_hook.h"
  51. /**
  52. * Commands sent to MeatPack to control its behavior.
  53. * They are sent by first sending 2x MeatPack_CommandByte (0xFF) in sequence,
  54. * followed by one of the command bytes below.
  55. * Provided that 0xFF is an exceedingly rare character that is virtually never
  56. * present in G-code naturally, it is safe to assume 2 in sequence should never
  57. * happen naturally, and so it is used as a signal here.
  58. *
  59. * 0xFF *IS* used in "packed" G-code (used to denote that the next 2 characters are
  60. * full-width), however 2 in a row will never occur, as the next 2 bytes will always
  61. * some non-0xFF character.
  62. */
  63. enum MeatPack_Command : uint8_t {
  64. MPCommand_None = 0,
  65. MPCommand_EnablePacking = 0xFB,
  66. MPCommand_DisablePacking = 0xFA,
  67. MPCommand_ResetAll = 0xF9,
  68. MPCommand_QueryConfig = 0xF8,
  69. MPCommand_EnableNoSpaces = 0xF7,
  70. MPCommand_DisableNoSpaces = 0xF6
  71. };
  72. enum MeatPack_ConfigStateBits : uint8_t {
  73. MPConfig_Bit_Active = 0,
  74. MPConfig_Bit_NoSpaces = 1
  75. };
  76. class MeatPack {
  77. // Utility definitions
  78. static const uint8_t kCommandByte = 0b11111111,
  79. kFirstNotPacked = 0b00001111,
  80. kSecondNotPacked = 0b11110000,
  81. kFirstCharIsLiteral = 0b00000001,
  82. kSecondCharIsLiteral = 0b00000010;
  83. static const uint8_t kSpaceCharIdx = 11;
  84. static const char kSpaceCharReplace = 'E';
  85. static bool cmd_is_next; // A command is pending
  86. static uint8_t state; // Configuration state
  87. static uint8_t second_char; // Buffers a character if dealing with out-of-sequence pairs
  88. static uint8_t cmd_count, // Counter of command bytes received (need 2)
  89. full_char_count, // Counter for full-width characters to be received
  90. char_out_count; // Stores number of characters to be read out.
  91. static uint8_t char_out_buf[2]; // Output buffer for caching up to 2 characters
  92. public:
  93. // Pass in a character rx'd by SD card or serial. Automatically parses command/ctrl sequences,
  94. // and will control state internally.
  95. static void handle_rx_char(const uint8_t c, const serial_index_t serial_ind);
  96. /**
  97. * After passing in rx'd char using above method, call this to get characters out.
  98. * Can return from 0 to 2 characters at once.
  99. * @param out [in] Output pointer for unpacked/processed data.
  100. * @return Number of characters returned. Range from 0 to 2.
  101. */
  102. static uint8_t get_result_char(char* const __restrict out);
  103. static void reset_state();
  104. static void report_state();
  105. static uint8_t unpack_chars(const uint8_t pk, uint8_t* __restrict const chars_out);
  106. static void handle_command(const MeatPack_Command c);
  107. static void handle_output_char(const uint8_t c);
  108. static void handle_rx_char_inner(const uint8_t c);
  109. };
  110. extern MeatPack meatpack;
  111. // Implement the MeatPack serial class so it's transparent to rest of the code
  112. template <typename SerialT>
  113. struct MeatpackSerial : public SerialBase <MeatpackSerial < SerialT >> {
  114. typedef SerialBase< MeatpackSerial<SerialT> > BaseClassT;
  115. SerialT & out;
  116. char serialBuffer[2];
  117. uint8_t charCount;
  118. uint8_t readIndex;
  119. NO_INLINE size_t write(uint8_t c) { return out.write(c); }
  120. void flush() { out.flush(); }
  121. void begin(long br) { out.begin(br); readIndex = 0; }
  122. void end() { out.end(); }
  123. void msgDone() { out.msgDone(); }
  124. // Existing instances implement Arduino's operator bool, so use that if it's available
  125. bool connected() { return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
  126. void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); }
  127. int available(uint8_t index) {
  128. // There is a potential issue here with multiserial, since it'll return its decoded buffer whatever the serial index here.
  129. // So, instead of doing MeatpackSerial<MultiSerial<...>> we should do MultiSerial<MeatpackSerial<...>, MeatpackSerial<...>>
  130. // TODO, let's fix this later on
  131. if (charCount) return charCount; // The buffer still has data
  132. if (out.available(index) <= 0) return 0; // No data to read
  133. // Don't read in read method, instead do it here, so we can make progress in the read method
  134. const int r = out.read(index);
  135. if (r == -1) return 0; // This is an error from the underlying serial code
  136. meatpack.handle_rx_char((uint8_t)r, index);
  137. charCount = meatpack.get_result_char(serialBuffer);
  138. readIndex = 0;
  139. return charCount;
  140. }
  141. int readImpl(const uint8_t index) {
  142. // Not enough char to make progress?
  143. if (charCount == 0 && available(index) == 0) return -1;
  144. charCount--;
  145. return serialBuffer[readIndex++];
  146. }
  147. int read(uint8_t index) { return readImpl(index); }
  148. int available() { return available(0); }
  149. int read() { return readImpl(0); }
  150. MeatpackSerial(const bool e, SerialT & out) : BaseClassT(e), out(out) {}
  151. };