aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/feature/meatpack.h
diff options
context:
space:
mode:
Diffstat (limited to 'Marlin/src/feature/meatpack.h')
-rw-r--r--Marlin/src/feature/meatpack.h123
1 files changed, 123 insertions, 0 deletions
diff --git a/Marlin/src/feature/meatpack.h b/Marlin/src/feature/meatpack.h
new file mode 100644
index 0000000..2641130
--- /dev/null
+++ b/Marlin/src/feature/meatpack.h
@@ -0,0 +1,123 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * MeatPack G-code Compression
+ *
+ * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com
+ * Date: Dec. 2020
+ *
+ * Specifically optimized for 3D printing G-Code, this is a zero-cost data compression method
+ * which packs ~180-190% more data into the same amount of bytes going to the CNC controller.
+ * As a majority of G-Code can be represented by a restricted alphabet, I performed histogram
+ * analysis on a wide variety of 3D printing gcode samples, and found ~93% of all gcode could
+ * be represented by the same 15-character alphabet.
+ *
+ * This allowed me to design a system of packing 2 8-bit characters into a single byte, assuming
+ * they fall within this limited 15-character alphabet. Using a 4-bit lookup table, these 8-bit
+ * characters can be represented by a 4-bit index.
+ *
+ * Combined with some logic to allow commingling of full-width characters outside of this 15-
+ * character alphabet (at the cost of an extra 8-bits per full-width character), and by stripping
+ * out unnecessary comments, the end result is gcode which is roughly half the original size.
+ *
+ * Why did I do this? I noticed micro-stuttering and other data-bottleneck issues while printing
+ * objects with high curvature, especially at high speeds. There is also the issue of the limited
+ * baud rate provided by Prusa's Atmega2560-based boards, over the USB serial connection. So soft-
+ * ware like OctoPrint would also suffer this same micro-stuttering and poor print quality issue.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+
+/**
+ * Commands sent to MeatPack to control its behavior.
+ * They are sent by first sending 2x MeatPack_CommandByte (0xFF) in sequence,
+ * followed by one of the command bytes below.
+ * Provided that 0xFF is an exceedingly rare character that is virtually never
+ * present in G-code naturally, it is safe to assume 2 in sequence should never
+ * happen naturally, and so it is used as a signal here.
+ *
+ * 0xFF *IS* used in "packed" G-code (used to denote that the next 2 characters are
+ * full-width), however 2 in a row will never occur, as the next 2 bytes will always
+ * some non-0xFF character.
+ */
+enum MeatPack_Command : uint8_t {
+ MPCommand_None = 0,
+ MPCommand_EnablePacking = 0xFB,
+ MPCommand_DisablePacking = 0xFA,
+ MPCommand_ResetAll = 0xF9,
+ MPCommand_QueryConfig = 0xF8,
+ MPCommand_EnableNoSpaces = 0xF7,
+ MPCommand_DisableNoSpaces = 0xF6
+};
+
+enum MeatPack_ConfigStateBits : uint8_t {
+ MPConfig_Bit_Active = 0,
+ MPConfig_Bit_NoSpaces = 1
+};
+
+class MeatPack {
+private:
+ friend class GCodeQueue;
+
+ // Utility definitions
+ static const uint8_t kCommandByte = 0b11111111,
+ kFirstNotPacked = 0b00001111,
+ kSecondNotPacked = 0b11110000,
+ kFirstCharIsLiteral = 0b00000001,
+ kSecondCharIsLiteral = 0b00000010;
+
+ static const uint8_t kSpaceCharIdx = 11;
+ static const char kSpaceCharReplace = 'E';
+
+ static bool cmd_is_next; // A command is pending
+ static uint8_t state; // Configuration state
+ static uint8_t second_char; // Buffers a character if dealing with out-of-sequence pairs
+ static uint8_t cmd_count, // Counter of command bytes received (need 2)
+ full_char_count, // Counter for full-width characters to be received
+ char_out_count; // Stores number of characters to be read out.
+ static uint8_t char_out_buf[2]; // Output buffer for caching up to 2 characters
+
+ // Pass in a character rx'd by SD card or serial. Automatically parses command/ctrl sequences,
+ // and will control state internally.
+ static void handle_rx_char(const uint8_t c, const serial_index_t serial_ind);
+
+ /**
+ * After passing in rx'd char using above method, call this to get characters out.
+ * Can return from 0 to 2 characters at once.
+ * @param out [in] Output pointer for unpacked/processed data.
+ * @return Number of characters returned. Range from 0 to 2.
+ */
+ static uint8_t get_result_char(char* const __restrict out);
+
+ static void reset_state();
+ static void report_state();
+ static uint8_t unpacked_char(register const uint8_t in);
+ static uint8_t unpack_chars(const uint8_t pk, uint8_t* __restrict const chars_out);
+ static void handle_command(const MeatPack_Command c);
+ static void handle_output_char(const uint8_t c);
+ static void handle_rx_char_inner(const uint8_t c);
+};
+
+extern MeatPack meatpack;