GCodeWriter.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. # Copyright (c) 2015 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from UM.Mesh.MeshWriter import MeshWriter
  4. from UM.Logger import Logger
  5. from UM.Application import Application
  6. import re #For escaping characters in the settings.
  7. import copy
  8. class GCodeWriter(MeshWriter):
  9. ## The file format version of the serialised g-code.
  10. #
  11. # It can only read settings with the same version as the version it was
  12. # written with. If the file format is changed in a way that breaks reverse
  13. # compatibility, increment this version number!
  14. version = 1
  15. ## Dictionary that defines how characters are escaped when embedded in
  16. # g-code.
  17. #
  18. # Note that the keys of this dictionary are regex strings. The values are
  19. # not.
  20. escape_characters = {
  21. re.escape("\\"): "\\\\", # The escape character.
  22. re.escape("\n"): "\\n", # Newlines. They break off the comment.
  23. re.escape("\r"): "\\r" # Carriage return. Windows users may need this for visualisation in their editors.
  24. }
  25. def __init__(self):
  26. super().__init__()
  27. def write(self, stream, node, mode = MeshWriter.OutputMode.TextMode):
  28. if mode != MeshWriter.OutputMode.TextMode:
  29. Logger.log("e", "GCode Writer does not support non-text mode")
  30. return False
  31. scene = Application.getInstance().getController().getScene()
  32. gcode_list = getattr(scene, "gcode_list")
  33. if gcode_list:
  34. for gcode in gcode_list:
  35. stream.write(gcode)
  36. # Serialise the profile and put them at the end of the file.
  37. profile = self._serialiseProfile(Application.getInstance().getMachineManager().getWorkingProfile())
  38. stream.write(profile)
  39. return True
  40. return False
  41. ## Serialises the profile to prepare it for saving in the g-code.
  42. #
  43. # The profile are serialised, and special characters (including newline)
  44. # are escaped.
  45. #
  46. # \param profile The profile to serialise.
  47. # \return A serialised string of the profile.
  48. def _serialiseProfile(self, profile):
  49. prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
  50. prefix_length = len(prefix)
  51. # Serialise a deepcopy to remove the defaults from the profile
  52. serialised = copy.deepcopy(profile).serialise()
  53. # Escape characters that have a special meaning in g-code comments.
  54. pattern = re.compile("|".join(GCodeWriter.escape_characters.keys()))
  55. # Perform the replacement with a regular expression.
  56. serialised = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], serialised)
  57. # Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix.
  58. result = ""
  59. # Lines have 80 characters, so the payload of each line is 80 - prefix.
  60. for pos in range(0, len(serialised), 80 - prefix_length):
  61. result += prefix + serialised[pos : pos + 80 - prefix_length] + "\n"
  62. serialised = result
  63. return serialised