-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconvert.py
More file actions
275 lines (227 loc) · 8.79 KB
/
convert.py
File metadata and controls
275 lines (227 loc) · 8.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#!/usr/bin/env python3
"""
Post-processing script for OrcaSlicer to convert G-code format to match Orca-FlashForge
This ensures proper ETA display on FlashForge printers and API compatibility
Usage: Add this script to OrcaSlicer's post-processing scripts
The script will automatically restructure the G-code file format
Optional: Use --add-md5 flag to add MD5 checksum for forge-x firmware compatibility
"""
import sys
import os
import argparse
import hashlib
from typing import Tuple
def extract_sections(gcode_content: str) -> Tuple[str, str, str, str, str]:
"""
Extract different sections from the G-code file
Returns: (header_block, thumbnail_block, executable_gcode, metadata, config_block)
"""
lines = gcode_content.split('\n')
header_block = []
thumbnail_block = []
config_block = []
metadata = []
executable_gcode = []
# Simple boolean flags for tracking sections
in_header = False
in_config = False
in_thumbnail = False
collecting_metadata = True
# Metadata fields to explicitly look for
metadata_fields = [
"; filament used [mm]", "; filament used [cm3]", "; filament used [g]",
"; filament cost", "; total filament used [g]", "; total filament cost",
"; total layers count", "; estimated printing time (normal mode)"
]
for line in lines:
stripped = line.strip()
# CONFIG block detection
if stripped == "; CONFIG_BLOCK_START":
in_config = True
config_block.append(line)
continue
elif stripped == "; CONFIG_BLOCK_END":
config_block.append(line)
in_config = False
continue
elif in_config:
config_block.append(line)
continue
# HEADER block detection
if stripped == "; HEADER_BLOCK_START":
in_header = True
header_block.append(line)
continue
elif stripped == "; HEADER_BLOCK_END":
header_block.append(line)
in_header = False
continue
elif in_header:
header_block.append(line)
continue
# THUMBNAIL block detection
if stripped == "; THUMBNAIL_BLOCK_START":
in_thumbnail = True
thumbnail_block.append(line)
continue
elif stripped == "; THUMBNAIL_BLOCK_END":
thumbnail_block.append(line)
in_thumbnail = False
continue
elif in_thumbnail:
thumbnail_block.append(line)
continue
# Metadata collection (before CONFIG_BLOCK_START)
if collecting_metadata:
if any(field in stripped for field in metadata_fields):
metadata.append(line)
continue
elif stripped == "; CONFIG_BLOCK_START":
collecting_metadata = False
# Everything else goes to executable gcode
executable_gcode.append(line)
return (
'\n'.join(header_block),
'\n'.join(thumbnail_block),
'\n'.join(executable_gcode),
'\n'.join(metadata),
'\n'.join(config_block)
)
def restructure_gcode(input_file: str) -> str:
"""
Restructure G-code from OrcaSlicer format to Orca-FlashForge format
"""
try:
with open(input_file, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
print(f"Error reading file {input_file}: {e}")
return None
# Extract sections
header_block, thumbnail_block, executable_gcode, metadata, config_block = extract_sections(content)
# Build new structure following Orca-FlashForge format:
# 1. Header block
# 2. Metadata (filament usage, ETA, etc.)
# 3. Config block
# 4. Thumbnail block
# 5. Executable G-code
restructured_parts = []
# 1. Header block
if header_block.strip():
restructured_parts.append(header_block)
restructured_parts.append("") # Empty line for spacing
# 2. Metadata (the crucial part for ETA display)
if metadata.strip():
restructured_parts.append(metadata)
restructured_parts.append("") # Empty line for spacing
# 3. Config block
if config_block.strip():
restructured_parts.append(config_block)
restructured_parts.append("") # Empty line for spacing
# 4. Thumbnail block
if thumbnail_block.strip():
restructured_parts.append(thumbnail_block)
restructured_parts.append("") # Empty line for spacing
# 5. Executable G-code
if executable_gcode.strip():
restructured_parts.append(executable_gcode)
return '\n'.join(restructured_parts)
def add_md5_checksum(gcode_file: str) -> bool:
"""
Add MD5 checksum to the beginning of the G-code file for forge-x firmware compatibility.
This prepends "; MD5:[hash]" to the file, which allows the forge-x firmware to verify
file integrity before printing, preventing issues from corrupted files.
Args:
gcode_file: Path to the G-code file
Returns:
True if successful, False otherwise
"""
try:
# Read the entire file content
with open(gcode_file, 'rb') as f:
file_content = f.read()
# Calculate MD5 hash
md5_hash = hashlib.md5(file_content).hexdigest()
# Create the MD5 comment line
md5_line = f"; MD5:{md5_hash}\n"
# Prepend MD5 to the file content
new_content = md5_line.encode('utf-8') + file_content
# Write back to the file
with open(gcode_file, 'wb') as f:
f.write(new_content)
print(f"MD5 checksum added: {md5_hash}")
return True
except Exception as e:
print(f"Error adding MD5 checksum: {e}")
return False
def main():
"""
Main function for post-processing script
"""
# Set up argument parser
parser = argparse.ArgumentParser(
description='Post-processing script for OrcaSlicer to convert G-code format to Orca-FlashForge',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s file.gcode # Convert format only
%(prog)s file.gcode --add-md5 # Convert format and add MD5 checksum
%(prog)s file.gcode -m # Short form for MD5
"""
)
parser.add_argument('gcode_file', help='Path to the G-code file to process')
parser.add_argument('--add-md5', '-m', action='store_true',
help='Add MD5 checksum for forge-x firmware compatibility')
# Parse arguments (support both argparse and OrcaSlicer's positional args)
if len(sys.argv) == 2 and not sys.argv[1].startswith('-'):
# OrcaSlicer only passes filename, no flags
args = parser.parse_args([sys.argv[1]])
else:
args = parser.parse_args()
gcode_file = args.gcode_file
if not os.path.exists(gcode_file):
print(f"Error: File {gcode_file} does not exist")
sys.exit(1)
print(f"Converting G-code format: {gcode_file}")
if args.add_md5:
print("MD5 checksum generation: ENABLED")
# Create backup
backup_file = gcode_file + ".backup"
try:
with open(gcode_file, 'r', encoding='utf-8') as src:
with open(backup_file, 'w', encoding='utf-8') as dst:
dst.write(src.read())
print(f"Backup created: {backup_file}")
except Exception as e:
print(f"Warning: Could not create backup: {e}")
# Restructure the file
restructured_content = restructure_gcode(gcode_file)
if restructured_content is None:
print("Error: Failed to restructure G-code")
sys.exit(1)
# Write the restructured content back to the original file
try:
with open(gcode_file, 'w', encoding='utf-8') as f:
f.write(restructured_content)
print(f"Successfully converted {gcode_file} to Orca-FlashForge format")
print("ETA and metadata should now be properly displayed on FlashForge printer and API")
except Exception as e:
print(f"Error writing file {gcode_file}: {e}")
# Try to restore backup
if os.path.exists(backup_file):
try:
with open(backup_file, 'r', encoding='utf-8') as src:
with open(gcode_file, 'w', encoding='utf-8') as dst:
dst.write(src.read())
print("Restored original file from backup")
except:
print("Failed to restore backup - manual intervention required")
sys.exit(1)
# Add MD5 checksum if requested
if args.add_md5:
print("\nAdding MD5 checksum for forge-x firmware...")
if not add_md5_checksum(gcode_file):
print("Warning: Failed to add MD5 checksum, but file conversion was successful")
sys.exit(1)
if __name__ == "__main__":
main()