71 lines
3.1 KiB
C
71 lines
3.1 KiB
C
/*
|
|
* 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.
|
|
*
|
|
*/
|
|
#include <stdint.h>
|
|
#include "Configuration.h"
|
|
|
|
#ifndef MEATPACK_H_
|
|
#define MEATPACK_H_
|
|
|
|
#ifdef ENABLE_MEATPACK
|
|
|
|
#define MeatPack_SecondNotPacked 0b11110000
|
|
#define MeatPack_FirstNotPacked 0b00001111
|
|
|
|
// These are 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 {
|
|
MPCommand_None = 0U,
|
|
// MPCommand_TogglePacking = 253U, -- Unused, byte 253 can be re-used later.
|
|
MPCommand_EnablePacking = 251U,
|
|
MPCommand_DisablePacking = 250U,
|
|
MPCommand_ResetAll = 249U,
|
|
MPCommand_QueryConfig = 248U,
|
|
MPCommand_EnableNoSpaces = 247U,
|
|
MPCommand_DisableNoSpaces = 246U
|
|
};
|
|
|
|
// Pass in a character rx'd by SD card or serial. Automatically parses command/ctrl sequences,
|
|
// and will control state internally.
|
|
extern void mp_handle_rx_char(const uint8_t c);
|
|
|
|
// 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.
|
|
extern uint8_t mp_get_result_char(char* const __restrict out);
|
|
#endif
|
|
|
|
#endif // MEATPACK_H_
|