SPE-1784: New compressed (binary) gcode format integration

Added GCode Block save/load with no encoding

Changed blocks order to: File metadata|Printer metadata|Thumbnails[]|Print metadata|Slicer metadata|GCode[]
This commit is contained in:
enricoturri1966 2023-07-20 14:20:00 +02:00
parent 989cf7a27d
commit 3f5de75bae
6 changed files with 533 additions and 169 deletions

View File

@ -1002,10 +1002,17 @@ namespace DoExport {
print_statistics.initial_extruder_id = initial_extruder_id;
std::vector<std::string> filament_types;
if (! extruders.empty()) {
#if ENABLE_BINARIZED_GCODE
std::pair<std::string, unsigned int> out_filament_used_mm(PrintStatistics::FilamentUsedMmMask + " ", 0);
std::pair<std::string, unsigned int> out_filament_used_cm3(PrintStatistics::FilamentUsedCm3Mask + " ", 0);
std::pair<std::string, unsigned int> out_filament_used_g(PrintStatistics::FilamentUsedGMask + " ", 0);
std::pair<std::string, unsigned int> out_filament_cost(PrintStatistics::FilamentCostMask + " ", 0);
#else
std::pair<std::string, unsigned int> out_filament_used_mm("; filament used [mm] = ", 0);
std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
std::pair<std::string, unsigned int> out_filament_cost("; filament cost = ", 0);
#endif // ENABLE_BINARIZED_GCODE
for (const Extruder &extruder : extruders) {
print_statistics.printing_extruders.emplace_back(extruder.id());
filament_types.emplace_back(config.filament_type.get_at(extruder.id()));
@ -1032,9 +1039,9 @@ namespace DoExport {
if (export_binary_data) {
char buf[128];
sprintf(buf, "%.2lf", used_filament);
binary_data.print_metadata.raw_data.push_back({ "filament used [mm]", std::string(buf) });
binary_data.print_metadata.raw_data.push_back({ PrintStatistics::FilamentUsedMm, std::string(buf) });
sprintf(buf, "%.2lf", extruded_volume * 0.001);
binary_data.print_metadata.raw_data.push_back({ "filament used [cm3]", std::string(buf) });
binary_data.print_metadata.raw_data.push_back({ PrintStatistics::FilamentUsedCm3, std::string(buf) });
}
else {
#endif // ENABLE_BINARIZED_GCODE
@ -1049,7 +1056,7 @@ namespace DoExport {
if (export_binary_data) {
char buf[128];
sprintf(buf, "%.2lf", filament_weight);
binary_data.print_metadata.raw_data.push_back({ "filament used [g]", std::string(buf) });
binary_data.print_metadata.raw_data.push_back({ PrintStatistics::FilamentUsedG, std::string(buf) });
}
else
#endif // ENABLE_BINARIZED_GCODE
@ -1060,7 +1067,7 @@ namespace DoExport {
if (export_binary_data) {
char buf[128];
sprintf(buf, "%.2lf", filament_cost);
binary_data.print_metadata.raw_data.push_back({ "filament cost", std::string(buf) });
binary_data.print_metadata.raw_data.push_back({ PrintStatistics::FilamentCost, std::string(buf) });
}
else
#endif // ENABLE_BINARIZED_GCODE
@ -1072,12 +1079,18 @@ namespace DoExport {
print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
}
#if ENABLE_BINARIZED_GCODE
if (!export_binary_data) {
#endif // ENABLE_BINARIZED_GCODE
filament_stats_string_out += out_filament_used_mm.first;
filament_stats_string_out += "\n" + out_filament_used_cm3.first;
if (out_filament_used_g.second)
filament_stats_string_out += "\n" + out_filament_used_g.first;
if (out_filament_cost.second)
filament_stats_string_out += "\n" + out_filament_cost.first;
#if ENABLE_BINARIZED_GCODE
}
#endif // ENABLE_BINARIZED_GCODE
print_statistics.initial_filament_type = config.filament_type.get_at(initial_extruder_id);
std::sort(filament_types.begin(), filament_types.end());
print_statistics.printing_filament_types = filament_types.front();
@ -1216,6 +1229,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
this->m_avoid_crossing_curled_overhangs.init_bed_shape(get_bed_shape(print.config()));
}
#if ENABLE_BINARIZED_GCODE
if (!export_to_binary_gcode)
#endif // ENABLE_BINARIZED_GCODE
// Write information on the generator.
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
@ -1582,7 +1598,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// Get filament stats.
#if ENABLE_BINARIZED_GCODE
file.write(DoExport::update_print_stats_and_format_filament_stats(
const std::string filament_stats_string_out = DoExport::update_print_stats_and_format_filament_stats(
// Const inputs
has_wipe_tower, print.wipe_tower_data(),
this->config(),
@ -1592,15 +1608,18 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
print.m_print_statistics,
export_to_binary_gcode,
m_processor.get_binary_data()
));
);
if (!export_to_binary_gcode)
file.write(filament_stats_string_out);
if (export_to_binary_gcode) {
BinaryGCode::BinaryData& binary_data = m_processor.get_binary_data();
char buf[128];
sprintf(buf, "%.2lf", print.m_print_statistics.total_weight);
binary_data.print_metadata.raw_data.push_back({ "total filament used [g]", std::string(buf) });
binary_data.print_metadata.raw_data.push_back({ PrintStatistics::TotalFilamentUsedG, std::string(buf) });
sprintf(buf, "%.2lf", print.m_print_statistics.total_cost);
binary_data.print_metadata.raw_data.push_back({ "total filament cost", std::string(buf) });
binary_data.print_metadata.raw_data.push_back({ PrintStatistics::TotalFilamentCost, std::string(buf) });
if (print.m_print_statistics.total_toolchanges > 0)
binary_data.print_metadata.raw_data.push_back({ "total toolchanges", std::to_string(print.m_print_statistics.total_toolchanges) });
}
@ -1619,8 +1638,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// if exporting gcode in ascii format, statistics export is done here
#endif // ENABLE_BINARIZED_GCODE
file.write("\n");
#if ENABLE_BINARIZED_GCODE
file.write_format(PrintStatistics::TotalFilamentUsedGValueMask.c_str(), print.m_print_statistics.total_weight);
file.write_format(PrintStatistics::TotalFilamentCostValueMask.c_str(), print.m_print_statistics.total_cost);
#else
file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
#endif // ENABLE_BINARIZED_GCODE
if (print.m_print_statistics.total_toolchanges > 0)
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());

View File

@ -12,6 +12,7 @@
namespace BinaryGCode {
static size_t g_checksum_max_cache_size = 65536;
static const size_t MAX_GCODE_CACHE_SIZE = 65536;
std::string translate_result(BinaryGCode::EResult result)
{
@ -26,10 +27,13 @@ std::string translate_result(BinaryGCode::EResult result)
case BinaryGCode::EResult::InvalidBlockType: { return "Invalid block type"; }
case BinaryGCode::EResult::InvalidCompressionType: { return "Invalid compression type"; }
case BinaryGCode::EResult::InvalidMetadataEncodingType: { return "Invalid metadata encoding type"; }
case BinaryGCode::EResult::InvalidGCodeEncodingType: { return "Invalid gcode encoding type"; }
case BinaryGCode::EResult::DataCompressionError: { return "Data compression error"; }
case BinaryGCode::EResult::DataUncompressionError: { return "Data uncompression error"; }
case BinaryGCode::EResult::MetadataEncodingError: { return "Data encoding error"; }
case BinaryGCode::EResult::MetadataDecodingError: { return "Data decoding error"; }
case BinaryGCode::EResult::GCodeEncodingError: { return "GCode encoding error"; }
case BinaryGCode::EResult::GCodeDecodingError: { return "GCode decoding error"; }
case BinaryGCode::EResult::BlockNotFound: { return "Block not found"; }
case BinaryGCode::EResult::InvalidChecksum: { return "Invalid checksum"; }
case BinaryGCode::EResult::InvalidThumbnailFormat: { return "Invalid thumbnail format"; }
@ -48,6 +52,7 @@ static uint16_t block_types_count() { return 1 + (uint16_t)EBlockTyp
static uint16_t compression_types_count() { return 1 + (uint16_t)ECompressionType::None; }
static uint16_t thumbnail_formats_count() { return 1 + (uint16_t)EThumbnailFormat::QOI; }
static uint16_t metadata_encoding_types_count() { return 1 + (uint16_t)EMetadataEncodingType::INI; }
static uint16_t gcode_encoding_types_count() { return 1 + (uint16_t)EGCodeEncodingType::MeatPack; }
static bool write_to_file(FILE& file, const void* data, size_t data_size)
{
@ -61,43 +66,60 @@ static bool read_from_file(FILE& file, void* data, size_t data_size)
return !ferror(&file);
}
static bool encode_metadata(const std::vector<std::pair<std::string, std::string>>& data_in, std::vector<uint8_t>& data_out,
static bool encode_metadata(const std::vector<std::pair<std::string, std::string>>& src, std::vector<uint8_t>& dst,
EMetadataEncodingType encoding_type)
{
for (const auto& [key, value] : data_in) {
for (const auto& [key, value] : src) {
switch (encoding_type)
{
case EMetadataEncodingType::INI:
{
data_out.insert(data_out.end(), key.begin(), key.end());
data_out.emplace_back('=');
data_out.insert(data_out.end(), value.begin(), value.end());
data_out.emplace_back('\n');
dst.insert(dst.end(), key.begin(), key.end());
dst.emplace_back('=');
dst.insert(dst.end(), value.begin(), value.end());
dst.emplace_back('\n');
break;
}
}
}
return true;
}
static bool decode_metadata(const std::vector<uint8_t>& data_in, std::vector<std::pair<std::string, std::string>>& data_out,
static bool encode_gcode(const std::string& src, std::vector<uint8_t>& dst, EGCodeEncodingType encoding_type)
{
switch (encoding_type)
{
case EGCodeEncodingType::None:
{
dst.insert(dst.end(), src.begin(), src.end());
break;
}
case EGCodeEncodingType::MeatPack:
{
// TODO
break;
}
}
return true;
}
static bool decode_metadata(const std::vector<uint8_t>& src, std::vector<std::pair<std::string, std::string>>& dst,
EMetadataEncodingType encoding_type)
{
switch (encoding_type)
{
case EMetadataEncodingType::INI:
{
auto start_it = data_in.begin();
auto end_it = data_in.begin();
while (end_it != data_in.end()) {
while (end_it != data_in.end() && *end_it != '\n') {
auto start_it = src.begin();
auto end_it = src.begin();
while (end_it != src.end()) {
while (end_it != src.end() && *end_it != '\n') {
++end_it;
}
const std::string item(start_it, end_it);
const size_t pos = item.find_first_of('=');
if (pos != std::string::npos) {
data_out.emplace_back(std::make_pair(item.substr(0, pos), item.substr(pos + 1)));
dst.emplace_back(std::make_pair(item.substr(0, pos), item.substr(pos + 1)));
start_it = ++end_it;
}
}
@ -108,12 +130,30 @@ static bool decode_metadata(const std::vector<uint8_t>& data_in, std::vector<std
return true;
}
static bool compress(const std::vector<uint8_t>& data_in, std::vector<uint8_t>& data_out, ECompressionType compression_type)
static bool decode_gcode(const std::vector<uint8_t>& src, std::string& dst, EGCodeEncodingType encoding_type)
{
switch (encoding_type)
{
case EGCodeEncodingType::None:
{
dst.insert(dst.end(), src.begin(), src.end());
break;
}
case EGCodeEncodingType::MeatPack:
{
// TODO
break;
}
}
return true;
}
static bool compress(const std::vector<uint8_t>& src, std::vector<uint8_t>& data_out, ECompressionType compression_type)
{
return true;
}
static bool uncompress(const std::vector<uint8_t>& data_in, std::vector<uint8_t>& data_out, ECompressionType compression_type)
static bool uncompress(const std::vector<uint8_t>& src, std::vector<uint8_t>& data_out, ECompressionType compression_type)
{
return true;
}
@ -357,7 +397,6 @@ EResult BaseMetadataBlock::read_data(FILE& file, const BlockHeader& block_header
if (!read_from_file(file, (void*)&encoding_type, sizeof(encoding_type)))
return EResult::ReadError;
if (encoding_type > metadata_encoding_types_count())
// Found invalid metadata encoding type
return EResult::InvalidMetadataEncodingType;
std::vector<uint8_t> data;
@ -620,11 +659,99 @@ EResult SlicerMetadataBlock::read_data(FILE& file, const FileHeader& file_header
EResult GCodeBlock::write(FILE& file, ECompressionType compression_type, EChecksumType checksum_type) const
{
if (encoding_type > gcode_encoding_types_count())
return EResult::InvalidGCodeEncodingType;
BlockHeader block_header = { (uint16_t)EBlockType::GCode, (uint16_t)compression_type, (uint32_t)0 };
std::vector<uint8_t> out_data;
if (!raw_data.empty()) {
// process payload encoding
std::vector<uint8_t> uncompressed_data;
if (!encode_gcode(raw_data, uncompressed_data, (EGCodeEncodingType)encoding_type))
return EResult::GCodeEncodingError;
// process payload compression
block_header.uncompressed_size = (uint32_t)uncompressed_data.size();
std::vector<uint8_t> compressed_data;
if (compression_type != ECompressionType::None) {
if (!compress(uncompressed_data, compressed_data, compression_type))
return EResult::DataCompressionError;
block_header.compressed_size = (uint32_t)compressed_data.size();
}
out_data.swap((compression_type == ECompressionType::None) ? uncompressed_data : compressed_data);
}
// write block header
EResult res = block_header.write(file);
if (res != EResult::Success)
// propagate error
return res;
// write block payload
if (!write_to_file(file, (const void*)&encoding_type, sizeof(encoding_type)))
return EResult::WriteError;
if (!out_data.empty()) {
#if ENABLE_BINARIZED_GCODE_DEBUG
const std::string out = "GCodeBlock data size:" + std::to_string(out_data.size()) + "\n";
OutputDebugStringA(out.c_str());
#endif // ENABLE_BINARIZED_GCODE_DEBUG
if (!write_to_file(file, (const void*)out_data.data(), out_data.size()))
return EResult::WriteError;
}
// write checksum
if (checksum_type != EChecksumType::None) {
Checksum cs(checksum_type);
// update checksum with block header
block_header.update_checksum(cs);
// update checksum with block payload
cs.append(encode((const void*)&encoding_type, sizeof(encoding_type)));
if (!out_data.empty())
cs.append(out_data);
res = cs.write(file);
if (res != EResult::Success)
// propagate error
return res;
}
return EResult::Success;
}
EResult GCodeBlock::read_data(FILE& file, const FileHeader& file_header, const BlockHeader& block_header)
{
const ECompressionType compression_type = (ECompressionType)block_header.compression;
if (!read_from_file(file, (void*)&encoding_type, sizeof(encoding_type)))
return EResult::ReadError;
if (encoding_type > gcode_encoding_types_count())
return EResult::InvalidGCodeEncodingType;
std::vector<uint8_t> data;
const size_t data_size = (compression_type == ECompressionType::None) ? block_header.uncompressed_size : block_header.compressed_size;
if (data_size > 0) {
data.resize(data_size);
if (!read_from_file(file, (void*)data.data(), data_size))
return EResult::ReadError;
}
std::vector<uint8_t> uncompressed_data;
if (compression_type != ECompressionType::None) {
if (!uncompress(data, uncompressed_data, compression_type))
return EResult::DataUncompressionError;
}
if (!decode_gcode((compression_type == ECompressionType::None) ? data : uncompressed_data, raw_data, (EGCodeEncodingType)encoding_type))
return EResult::GCodeDecodingError;
const EChecksumType checksum_type = (EChecksumType)file_header.checksum_type;
if (checksum_type != EChecksumType::None) {
// read block checksum
Checksum cs(checksum_type);
const EResult res = cs.read(file);
if (res != EResult::Success)
// propagate error
return res;
}
return EResult::Success;
}
@ -660,60 +787,116 @@ EResult ChecksumBlock::read_data(FILE& file, const BlockHeader& block_header)
}
#endif // ENABLE_CHECKSUM_BLOCK
EResult Binarizer::initialize(FILE& file, EChecksumType checksum_type)
EResult Binarizer::initialize(FILE& file, EGCodeEncodingType gcode_encoding_type, EChecksumType checksum_type)
{
if (!m_enabled)
return EResult::Success;
// initialize checksum
m_file = &file;
m_gcode_encoding_type = gcode_encoding_type;
m_checksum_type = checksum_type;
#if ENABLE_CHECKSUM_BLOCK
// initialize checksum
m_checksum = ChecksumBlock();
#endif // ENABLE_CHECKSUM_BLOCK
// save header
FileHeader file_header;
file_header.checksum_type = (uint16_t)m_checksum_type;
EResult res = file_header.write(file);
EResult res = file_header.write(*m_file);
if (res != EResult::Success)
return res;
// save file metadata block
res = m_binary_data.file_metadata.write(file, ECompressionType::None, m_checksum_type);
res = m_binary_data.file_metadata.write(*m_file, m_compression_type, m_checksum_type);
if (res != EResult::Success)
return res;
// save printer metadata block
res = m_binary_data.printer_metadata.write(file, ECompressionType::None, m_checksum_type);
res = m_binary_data.printer_metadata.write(*m_file, m_compression_type, m_checksum_type);
if (res != EResult::Success)
return res;
// save thumbnail blocks
for (const ThumbnailBlock& block : m_binary_data.thumbnails) {
res = block.write(file, m_checksum_type);
res = block.write(*m_file, m_checksum_type);
if (res != EResult::Success)
return res;
}
// save slicer metadata block
res = m_binary_data.slicer_metadata.write(file, ECompressionType::None, m_checksum_type);
// save print metadata block
res = m_binary_data.print_metadata.write(*m_file, m_compression_type, m_checksum_type);
if (res != EResult::Success)
return res;
// save gcode block
// save slicer metadata block
res = m_binary_data.slicer_metadata.write(*m_file, m_compression_type, m_checksum_type);
if (res != EResult::Success)
return res;
return EResult::Success;
}
EResult Binarizer::finalize(FILE& file)
static EResult write_gcode_block(FILE& file, const std::string& raw_data, EGCodeEncodingType encoding_type, ECompressionType compression_type,
EChecksumType checksum_type)
{
GCodeBlock block;
block.encoding_type = (uint16_t)encoding_type;
block.raw_data = raw_data;
return block.write(file, compression_type, checksum_type);
}
EResult Binarizer::append_gcode(const std::string& gcode)
{
if (gcode.empty())
return EResult::Success;
assert(m_file != nullptr);
if (m_file == nullptr)
return EResult::WriteError;
auto it_begin = gcode.begin();
do {
const size_t begin_pos = std::distance(gcode.begin(), it_begin);
const size_t end_line_pos = gcode.find_first_of('\n', begin_pos);
if (end_line_pos == std::string::npos)
return EResult::WriteError;
const size_t line_size = 1 + end_line_pos - begin_pos;
if (line_size + m_gcode_cache.length() > MAX_GCODE_CACHE_SIZE) {
if (!m_gcode_cache.empty()) {
const EResult res = write_gcode_block(*m_file, m_gcode_cache, m_gcode_encoding_type, m_compression_type, m_checksum_type);
if (res != EResult::Success)
// propagate error
return res;
m_gcode_cache.clear();
}
}
if (line_size > MAX_GCODE_CACHE_SIZE)
return EResult::WriteError;
m_gcode_cache.insert(m_gcode_cache.end(), it_begin, it_begin + line_size);
it_begin += line_size;
}
while (it_begin != gcode.end());
return EResult::Success;
}
EResult Binarizer::finalize()
{
if (!m_enabled)
return EResult::Success;
// save print metadata block
EResult res = m_binary_data.print_metadata.write(file, ECompressionType::None, m_checksum_type);
// save gcode cache, if not empty
if (!m_gcode_cache.empty()) {
const EResult res = write_gcode_block(*m_file, m_gcode_cache, m_gcode_encoding_type, m_compression_type, m_checksum_type);
if (res != EResult::Success)
// propagate error
return res;
}
#if ENABLE_CHECKSUM_BLOCK
if (m_checksum_type != EChecksumType::None) {

View File

@ -29,10 +29,13 @@ enum class EResult : uint16_t
InvalidBlockType,
InvalidCompressionType,
InvalidMetadataEncodingType,
InvalidGCodeEncodingType,
DataCompressionError,
DataUncompressionError,
MetadataEncodingError,
MetadataDecodingError,
GCodeEncodingError,
GCodeDecodingError,
BlockNotFound,
InvalidChecksum,
InvalidThumbnailFormat,
@ -195,12 +198,23 @@ struct SlicerMetadataBlock : public BaseMetadataBlock
EResult read_data(FILE& file, const FileHeader& file_header, const BlockHeader& block_header);
};
struct GCodeBlock : public BaseMetadataBlock
enum class EGCodeEncodingType : uint16_t
{
None,
MeatPack,
};
struct GCodeBlock
{
uint16_t encoding_type{ 0 };
std::string raw_data;
// write block header and data
EResult write(FILE& file, ECompressionType compression_type, EChecksumType checksum_type) const;
// read block data
EResult read_data(FILE& file, const FileHeader& file_header, const BlockHeader& block_header);
static size_t get_parameters_size() { return sizeof(encoding_type); }
};
#if ENABLE_CHECKSUM_BLOCK
@ -248,16 +262,20 @@ public:
BinaryData& get_binary_data() { return m_binary_data; }
const BinaryData& get_binary_data() const { return m_binary_data; }
EResult initialize(FILE& file, EChecksumType checksum_type);
EResult finalize(FILE& file);
EResult initialize(FILE& file, EGCodeEncodingType gcode_encoding_type, EChecksumType checksum_type);
EResult append_gcode(const std::string& gcode);
EResult finalize();
private:
bool m_enabled{ false };
EChecksumType m_checksum_type{ EChecksumType::None };
ECompressionType m_compression_type{ ECompressionType::None };
EGCodeEncodingType m_gcode_encoding_type{ EGCodeEncodingType::None };
FILE* m_file{ nullptr };
BinaryData m_binary_data;
std::string m_gcode_cache;
#if ENABLE_CHECKSUM_BLOCK
ChecksumBlock m_checksum;
#endif // ENABLE_CHECKSUM_BLOCK

View File

@ -1127,10 +1127,18 @@ void GCodeProcessor::process_binary_file(const std::string& filename, std::funct
FILE* m_file{ nullptr };
};
#if ENABLE_GCODE_VIEWER_STATISTICS
m_start_time = std::chrono::high_resolution_clock::now();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
FILE* file = boost::nowide::fopen(filename.c_str(), "rb");
if (file == nullptr)
throw Slic3r::RuntimeError("Unable to open file: " + filename + "\n");
fseek(file, 0, SEEK_END);
const long file_size = ftell(file);
rewind(file);
ScopedFile scoped_file(file);
BinaryGCode::set_checksum_max_cache_size(1024);
@ -1141,7 +1149,6 @@ void GCodeProcessor::process_binary_file(const std::string& filename, std::funct
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError("File: " + filename + "does not contain a valid binary gcode\n Error: " + BinaryGCode::translate_result(res) + "\n");
const long first_block_header_position = ftell(file);
const bool verify_checksum = true;
// read file metadata block
@ -1222,7 +1229,27 @@ void GCodeProcessor::process_binary_file(const std::string& filename, std::funct
throw Slic3r::RuntimeError("Error while reading file: " + filename + ": " + BinaryGCode::translate_result(res) + "\n");
}
// read print metadata block
if ((BinaryGCode::EBlockType)block_header.type != BinaryGCode::EBlockType::PrintMetadata)
throw Slic3r::RuntimeError("Unable to find print metadata block in file: " + filename + "\n");
BinaryGCode::PrintMetadataBlock print_metadata_block;
res = print_metadata_block.read_data(*file, file_header, block_header);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError("Error while reading file: " + filename + ": " + BinaryGCode::translate_result(res) + "\n");
#if ENABLE_BINARIZED_GCODE_DEBUG
OutputDebugStringA("Print metadata:\n");
for (const auto& [key, value] : print_metadata_block.raw_data) {
OutputDebugStringA(key.c_str());
OutputDebugStringA("->");
OutputDebugStringA(value.c_str());
OutputDebugStringA("\n");
}
#endif // ENABLE_BINARIZED_GCODE_DEBUG
// read slicer metadata block
res = BinaryGCode::read_next_block_header(*file, file_header, block_header, verify_checksum);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError("Error while reading file: " + filename + ": " + BinaryGCode::translate_result(res) + "\n");
if ((BinaryGCode::EBlockType)block_header.type != BinaryGCode::EBlockType::SlicerMetadata)
throw Slic3r::RuntimeError("Unable to find slicer metadata block in file: " + filename + "\n");
BinaryGCode::SlicerMetadataBlock slicer_metadata_block;
@ -1250,25 +1277,38 @@ void GCodeProcessor::process_binary_file(const std::string& filename, std::funct
config.load_from_ini_string(str, ForwardCompatibilitySubstitutionRule::EnableSilent);
apply_config(config);
// read print metadata block
m_result.filename = filename;
m_result.id = ++s_result_id;
initialize_result_moves();
// read gcodes block
res = BinaryGCode::read_next_block_header(*file, file_header, block_header, verify_checksum);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError("Error while reading file: " + filename + ": " + BinaryGCode::translate_result(res) + "\n");
if ((BinaryGCode::EBlockType)block_header.type != BinaryGCode::EBlockType::PrintMetadata)
throw Slic3r::RuntimeError("Unable to find print metadata block in file: " + filename + "\n");
BinaryGCode::PrintMetadataBlock print_metadata_block;
res = print_metadata_block.read_data(*file, file_header, block_header);
if ((BinaryGCode::EBlockType)block_header.type != BinaryGCode::EBlockType::GCode)
throw Slic3r::RuntimeError("Unable to find gcode block in file: " + filename + "\n");
while ((BinaryGCode::EBlockType)block_header.type == BinaryGCode::EBlockType::GCode) {
BinaryGCode::GCodeBlock block;
res = block.read_data(*file, file_header, block_header);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError("Error while reading file: " + filename + ": " + BinaryGCode::translate_result(res) + "\n");
// TODO: Update m_result.lines_ends
m_parser.parse_buffer(block.raw_data, [this](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
this->process_gcode_line(line, true);
});
if (ftell(file) == file_size)
break;
res = BinaryGCode::read_next_block_header(*file, file_header, block_header, verify_checksum);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError("Error while reading file: " + filename + ": " + BinaryGCode::translate_result(res) + "\n");
#if ENABLE_BINARIZED_GCODE_DEBUG
OutputDebugStringA("Print metadata:\n");
for (const auto& [key, value] : print_metadata_block.raw_data) {
OutputDebugStringA(key.c_str());
OutputDebugStringA("->");
OutputDebugStringA(value.c_str());
OutputDebugStringA("\n");
}
#endif // ENABLE_BINARIZED_GCODE_DEBUG
// Don't post-process the G-code to update time stamps.
this->finalize(false);
}
#endif // ENABLE_BINARIZED_GCODE
@ -3622,9 +3662,57 @@ void GCodeProcessor::post_process()
}
#if ENABLE_BINARIZED_GCODE
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
std::vector<double> filament_cm3(m_result.extruders_count, 0.0);
std::vector<double> filament_g(m_result.extruders_count, 0.0);
std::vector<double> filament_cost(m_result.extruders_count, 0.0);
double filament_total_g = 0.0;
double filament_total_cost = 0.0;
for (const auto& [id, volume] : m_result.print_statistics.volumes_per_extruder) {
filament_mm[id] = volume / (static_cast<double>(M_PI) * sqr(0.5 * m_result.filament_diameters[id]));
filament_cm3[id] = volume * 0.001;
filament_g[id] = filament_cm3[id] * double(m_result.filament_densities[id]);
filament_cost[id] = filament_g[id] * double(m_result.filament_cost[id]) * 0.001;
filament_total_g += filament_g[id];
filament_total_cost += filament_cost[id];
}
if (m_binarizer.is_enabled()) {
BinaryGCode::set_checksum_max_cache_size(4096);
const BinaryGCode::EResult res = m_binarizer.initialize(*out.f, BinaryGCode::EChecksumType::CRC32);
// update print metadata
auto update_value = [](std::string& value, const std::vector<double>& values) {
char buf[1024];
value.clear();
for (size_t i = 0; i < values.size(); ++i) {
sprintf(buf, i == values.size() - 1 ? " %.2lf" : " %.2lf,", values[i]);
value += buf;
}
};
// update binary data
BinaryGCode::BinaryData& binary_data = m_binarizer.get_binary_data();
for (auto& [key, value] : binary_data.print_metadata.raw_data) {
if (key == PrintStatistics::FilamentUsedMm) update_value(value, filament_mm);
else if (key == PrintStatistics::FilamentUsedG) update_value(value, filament_g);
else if (key == PrintStatistics::TotalFilamentUsedG) update_value(value, { filament_total_g });
else if (key == PrintStatistics::FilamentUsedCm3) update_value(value, filament_cm3);
else if (key == PrintStatistics::FilamentCost) update_value(value, filament_cost);
else if (key == PrintStatistics::TotalFilamentCost) update_value(value, { filament_total_cost });
}
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = m_time_processor.machines[i];
PrintEstimatedStatistics::ETimeMode mode = static_cast<PrintEstimatedStatistics::ETimeMode>(i);
if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) {
char buf[128];
sprintf(buf, "(%s mode)", (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent");
binary_data.print_metadata.raw_data.push_back({ "estimated printing time " + std::string(buf), get_time_dhms(machine.time) });
binary_data.print_metadata.raw_data.push_back({ "estimated first layer printing time " + std::string(buf), get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()) });
}
}
const BinaryGCode::EResult res = m_binarizer.initialize(*out.f, BinaryGCode::EGCodeEncodingType::None, BinaryGCode::EChecksumType::CRC32);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError(std::string("Unable to initialize the gcode binarizer.\n"));
}
@ -3876,8 +3964,29 @@ void GCodeProcessor::post_process()
}
}
write_to_file(out, out_string, result, out_path);
#if ENABLE_BINARIZED_GCODE
if (m_binarizer.is_enabled()) {
BinaryGCode::EResult res = m_binarizer.append_gcode(out_string);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError(std::string("Error while sending gcode to the binarizer.\n"));
}
else
#endif // ENABLE_BINARIZED_GCODE
write_to_file(out, out_string, result, out_path);
#if ENABLE_BINARIZED_GCODE
update_out_file_pos(out, out_string, result);
#endif // ENABLE_BINARIZED_GCODE
}
#if ENABLE_BINARIZED_GCODE
void update_out_file_pos(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result) {
for (size_t i = 0; i < out_string.size(); ++i) {
if (out_string[i] == '\n')
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
}
m_out_file_pos += out_string.size();
}
#endif // ENABLE_BINARIZED_GCODE
// flush the current content of the cache to file
void flush(FilePtr& out, GCodeProcessorResult& result, const std::string& out_path) {
@ -3892,7 +4001,18 @@ void GCodeProcessor::post_process()
m_statistics.remove_all_lines();
#endif // NDEBUG
#if ENABLE_BINARIZED_GCODE
if (m_binarizer.is_enabled()) {
BinaryGCode::EResult res = m_binarizer.append_gcode(out_string);
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError(std::string("Error while sending gcode to the binarizer.\n"));
}
else
#endif // ENABLE_BINARIZED_GCODE
write_to_file(out, out_string, result, out_path);
#if ENABLE_BINARIZED_GCODE
update_out_file_pos(out, out_string, result);
#endif // ENABLE_BINARIZED_GCODE
}
void synchronize_moves(GCodeProcessorResult& result) const {
@ -3922,12 +4042,13 @@ void GCodeProcessor::post_process()
}
#if ENABLE_BINARIZED_GCODE
}
#endif // ENABLE_BINARIZED_GCODE
#else
for (size_t i = 0; i < out_string.size(); ++i) {
if (out_string[i] == '\n')
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
}
m_out_file_pos += out_string.size();
#endif // ENABLE_BINARIZED_GCODE
}
}
};
@ -3999,6 +4120,7 @@ void GCodeProcessor::post_process()
return processed;
};
#if !ENABLE_BINARIZED_GCODE
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
std::vector<double> filament_cm3(m_result.extruders_count, 0.0);
std::vector<double> filament_g(m_result.extruders_count, 0.0);
@ -4015,6 +4137,7 @@ void GCodeProcessor::post_process()
filament_total_g += filament_g[id];
filament_total_cost += filament_cost[id];
}
#endif // !ENABLE_BINARIZED_GCODE
auto process_used_filament = [&](std::string& gcode_line) {
// Prefilter for parsing speed.
@ -4036,12 +4159,21 @@ void GCodeProcessor::post_process()
};
bool ret = false;
#if ENABLE_BINARIZED_GCODE
ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedMmMask, filament_mm);
ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedGMask, filament_g);
ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentUsedGMask, { filament_total_g });
ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedCm3Mask, filament_cm3);
ret |= process_tag(gcode_line, PrintStatistics::FilamentCostMask, filament_cost);
ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentCostMask, { filament_total_cost });
#else
ret |= process_tag(gcode_line, "; filament used [mm] =", filament_mm);
ret |= process_tag(gcode_line, "; filament used [g] =", filament_g);
ret |= process_tag(gcode_line, "; total filament used [g] =", { filament_total_g });
ret |= process_tag(gcode_line, "; filament used [cm3] =", filament_cm3);
ret |= process_tag(gcode_line, "; filament cost =", filament_cost);
ret |= process_tag(gcode_line, "; total filament cost =", { filament_total_cost });
#endif // ENABLE_BINARIZED_GCODE
return ret;
};
@ -4251,39 +4383,7 @@ void GCodeProcessor::post_process()
#if ENABLE_BINARIZED_GCODE
if (m_binarizer.is_enabled()) {
// update print metadata
auto update_value = [](std::string& value, const std::vector<double>& values) {
char buf[1024];
value.clear();
for (size_t i = 0; i < values.size(); ++i) {
sprintf(buf, i == values.size() - 1 ? " %.2lf" : " %.2lf,", values[i]);
value += buf;
}
};
// update binary data
BinaryGCode::BinaryData& binary_data = m_binarizer.get_binary_data();
for (auto& [key, value] : binary_data.print_metadata.raw_data) {
if (key == "filament used [mm]") update_value(value, filament_mm);
else if (key == "filament used [g]") update_value(value, filament_g);
else if (key == "total filament used [g]") update_value(value, { filament_total_g });
else if (key == "filament used [cm3]") update_value(value, filament_cm3);
else if (key == "filament cost") update_value(value, filament_cost);
else if (key == "total filament cost") update_value(value, { filament_total_cost });
}
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = m_time_processor.machines[i];
PrintEstimatedStatistics::ETimeMode mode = static_cast<PrintEstimatedStatistics::ETimeMode>(i);
if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) {
char buf[128];
sprintf(buf, "(%s mode)", (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent");
binary_data.print_metadata.raw_data.push_back({ "estimated printing time " + std::string(buf), get_time_dhms(machine.time) });
binary_data.print_metadata.raw_data.push_back({ "estimated first layer printing time " + std::string(buf), get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()) });
}
}
const BinaryGCode::EResult res = m_binarizer.finalize(*out.f);
const BinaryGCode::EResult res = m_binarizer.finalize();
if (res != BinaryGCode::EResult::Success)
throw Slic3r::RuntimeError(std::string("Error while finalizing the gcode binarizer.\n"));
}

View File

@ -1548,6 +1548,28 @@ std::string Print::output_filename(const std::string &filename_base) const
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
}
#if ENABLE_BINARIZED_GCODE
const std::string PrintStatistics::FilamentUsedG = "filament used [g]";
const std::string PrintStatistics::FilamentUsedGMask = "; " + PrintStatistics::FilamentUsedG + " =";
const std::string PrintStatistics::TotalFilamentUsedG = "total " + PrintStatistics::FilamentUsedG;
const std::string PrintStatistics::TotalFilamentUsedGMask = "; " + PrintStatistics::TotalFilamentUsedG + " =";
const std::string PrintStatistics::TotalFilamentUsedGValueMask = TotalFilamentUsedGMask + " %.2lf\n";
const std::string PrintStatistics::FilamentUsedCm3 = "filament used [cm3]";
const std::string PrintStatistics::FilamentUsedCm3Mask = "; " + PrintStatistics::FilamentUsedCm3 + " =";
const std::string PrintStatistics::FilamentUsedMm = "filament used [mm]";
const std::string PrintStatistics::FilamentUsedMmMask = "; " + PrintStatistics::FilamentUsedMm + " =";
const std::string PrintStatistics::FilamentCost = "filament cost";
const std::string PrintStatistics::FilamentCostMask = "; " + PrintStatistics::FilamentCost + " =";
const std::string PrintStatistics::TotalFilamentCost = "total " + PrintStatistics::FilamentCost;
const std::string PrintStatistics::TotalFilamentCostMask = "; " + PrintStatistics::TotalFilamentCost + " =";
const std::string PrintStatistics::TotalFilamentCostValueMask = PrintStatistics::TotalFilamentCostMask + " %.2lf\n";
#endif // ENABLE_BINARIZED_GCODE
DynamicConfig PrintStatistics::config() const
{
DynamicConfig config;

View File

@ -528,6 +528,23 @@ struct PrintStatistics
filament_stats.clear();
printing_extruders.clear();
}
#if ENABLE_BINARIZED_GCODE
static const std::string FilamentUsedG;
static const std::string FilamentUsedGMask;
static const std::string TotalFilamentUsedG;
static const std::string TotalFilamentUsedGMask;
static const std::string TotalFilamentUsedGValueMask;
static const std::string FilamentUsedCm3;
static const std::string FilamentUsedCm3Mask;
static const std::string FilamentUsedMm;
static const std::string FilamentUsedMmMask;
static const std::string FilamentCost;
static const std::string FilamentCostMask;
static const std::string TotalFilamentCost;
static const std::string TotalFilamentCostMask;
static const std::string TotalFilamentCostValueMask;
#endif // ENABLE_BINARIZED_GCODE
};
using PrintObjectPtrs = std::vector<PrintObject*>;