chiark / gitweb /
67604fed63493444d3ee4baa28b16271ee51361c
[cura.git] / Cura / skeinforge_application / skeinforge_plugins / craft_plugins / export_plugins / binary_16_byte.py
1 """
2 This page is in the table of contents.
3 Binary 16 byte is an export plugin to convert gcode into 16 byte binary segments.
4
5 An export plugin is a script in the export_plugins folder which has the getOutput function, the globalIsReplaceable variable and if it's output is not replaceable, the writeOutput function.  It is meant to be run from the export tool.  To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
6
7 The getOutput function of this script takes a gcode text and returns that text converted into 16 byte segments.  The writeOutput function of this script takes a gcode text and writes that in a binary format converted into 16 byte segments.
8
9 This plugin is just a starter to make a real binary converter.
10
11 ==Settings==
12 ===Feed Rate Step Length===
13 Default is 0.1 millimeters/second.
14
15 Defines the feed rate step length.
16
17 ===File Extension===
18 Default is bin.
19
20 Defines the file extension suffix.
21
22 ===Offset===
23 ====X Offset====
24 Default is zero.
25
26 Defines the X Offset.
27
28 ====Y Offset====
29 Default is zero.
30
31 Defines the Y Offset.
32
33 ====Z Offset====
34 Default is zero.
35
36 Defines the Z Offset.
37
38 ===Step Length===
39 ====X Step Length====
40 Default is 0.1 millimeters.
41
42 Defines the X axis step length.
43
44 ====Y Step Length====
45 Default is 0.1 millimeters.
46
47 Defines the Y axis step length.
48
49 ====Z Step Length====
50 Default is 0.01 millimeters.
51
52 Defines the Z axis step length.
53
54 ==Record structure==
55 BinArray(0) = AscW(Inst_Code_Letter)
56 BinArray(1) = cInst_Code
57
58 X Data
59 sInt32_to_Hbytes(iXdim_1)
60 BinArray(2) = lsb 'short lsb
61 BinArray(3) = msb 'short msb
62
63 Y Data
64 sInt32_to_Hbytes(iYdim_2)
65 BinArray(4) = lsb 'short lsb
66 BinArray(5) = msb 'short msb
67
68 Z Data
69 sInt32_to_Hbytes(iZdim_3)
70 BinArray(6) = lsb 'short lsb
71 BinArray(7) = msb 'short msb
72
73 I Data
74 sInt32_to_Hbytes(iIdim_4)
75 BinArray(8) = lsb 'short lsb
76 BinArray(9) = msb 'short msb
77
78 J Data
79 sInt32_to_Hbytes(iJdim_5)
80 BinArray(10) = lsb 'short lsb
81 BinArray(11) = msb 'short msb
82
83 BinArray(12) = FP_Char
84 sInt32_to_Hbytes(iFP_Num)
85 BinArray(13) = lsb 'short lsb
86
87 BinArray(14) = bActiveFlags
88
89 BinArray(15) = AscW("#")End of record filler
90
91 Byte 14 is worth a few extra notes, this byte is used to define which of the axes are active, its used to get round the problem of say a line of code with no mention of z. This would be put into the file as z = 0 as the space for this data is reserved, if we did nothing, this would instruct the machine to go to z = 0. If we use the active flag to define the z axis as inactive the z = 0 is ignored and the value set to the last saved value of z, i.e it does not move.  If the z data is actually set to z = 0 then the axis would be set to active and the move takes place.
92
93 """
94
95 from __future__ import absolute_import
96 import __init__
97 from fabmetheus_utilities import archive
98 from fabmetheus_utilities import gcodec
99 from fabmetheus_utilities import settings
100 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
101 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
102 from skeinforge_application.skeinforge_utilities import skeinforge_profile
103 from struct import Struct
104 import cStringIO
105 import os
106 import sys
107
108
109 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
110 __date__ = '$Date: 2008/21/04 $'
111 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
112
113
114 # This is true if the output is text and false if it is binary."
115 globalIsReplaceable = False
116
117
118 def getIntegerFlagFromCharacterSplitLine(character, splitLine):
119         "Get the integer flag after the first occurence of the character in the split line."
120         lineFromCharacter = gcodec.getStringFromCharacterSplitLine(character, splitLine)
121         if lineFromCharacter == None:
122                 return 0
123         return 1
124
125 def getIntegerFromCharacterLengthLineOffset( character, offset, splitLine, stepLength ):
126         "Get the integer after the first occurence of the character in the split line."
127         lineFromCharacter = gcodec.getStringFromCharacterSplitLine(character, splitLine)
128         if lineFromCharacter == None:
129                 return 0
130         floatValue = ( float( lineFromCharacter ) + offset ) / stepLength
131         return int( round( floatValue ) )
132
133 def getNewRepository():
134         'Get new repository.'
135         return Binary16ByteRepository()
136
137 def getOutput( gcodeText, binary16ByteRepository = None ):
138         'Get the exported version of a gcode file.'
139         if gcodeText == '':
140                 return ''
141         if binary16ByteRepository == None:
142                 binary16ByteRepository = Binary16ByteRepository()
143                 settings.getReadRepository( binary16ByteRepository )
144         return Binary16ByteSkein().getCraftedGcode( gcodeText, binary16ByteRepository )
145
146 def writeOutput( fileName, gcodeText = ''):
147         "Write the exported version of a gcode file."
148         binary16ByteRepository = Binary16ByteRepository()
149         settings.getReadRepository( binary16ByteRepository )
150         gcodeText = gcodec.getGcodeFileText(fileName, gcodeText)
151         skeinOutput = getOutput( gcodeText, binary16ByteRepository )
152         suffixFileName = fileName[ : fileName.rfind('.') ] + '.' + binary16ByteRepository.fileExtension.value
153         archive.writeFileText( suffixFileName, skeinOutput )
154         print('The converted file is saved as ' + archive.getSummarizedFileName(suffixFileName) )
155
156
157 class Binary16ByteRepository:
158         "A class to handle the export settings."
159         def __init__(self):
160                 "Set the default settings, execute title & settings fileName."
161                 #Set the default settings.
162                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.export_plugins.binary_16_byte.html', self)
163                 self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File to be Converted to Binary 16 Byte', self, '')
164                 self.feedRateStepLength = settings.FloatSpin().getFromValue( 0.0, 'Feed Rate Step Length (millimeters/second)', self, 1.0, 0.1 )
165                 self.fileExtension = settings.StringSetting().getFromValue('File Extension:', self, 'bin')
166                 settings.LabelDisplay().getFromName('Offset:', self )
167                 self.xOffset = settings.FloatSpin().getFromValue( - 100.0, 'X Offset (millimeters)', self, 100.0, 0.0 )
168                 self.yOffset = settings.FloatSpin().getFromValue( -100.0, 'Y Offset (millimeters)', self, 100.0, 0.0 )
169                 self.zOffset = settings.FloatSpin().getFromValue( - 10.0, 'Z Offset (millimeters)', self, 10.0, 0.0 )
170                 settings.LabelDisplay().getFromName('Step Length:', self )
171                 self.xStepLength = settings.FloatSpin().getFromValue( 0.0, 'X Step Length (millimeters)', self, 1.0, 0.1 )
172                 self.yStepLength = settings.FloatSpin().getFromValue( 0.0, 'Y Step Length (millimeters)', self, 1.0, 0.1 )
173                 self.zStepLength = settings.FloatSpin().getFromValue( 0.0, 'Z Step Length (millimeters)', self, 0.2, 0.01 )
174                 self.executeTitle = 'Convert to Binary 16 Byte'
175
176         def execute(self):
177                 "Convert to binary 16 byte button has been clicked."
178                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode( self.fileNameInput.value, ['.gcode'], self.fileNameInput.wasCancelled )
179                 for fileName in fileNames:
180                         writeOutput(fileName)
181
182
183 class Binary16ByteSkein:
184         "A class to convert gcode into 16 byte binary segments."
185         def __init__(self):
186                 self.output = cStringIO.StringIO()
187
188         def getCraftedGcode( self, gcodeText, binary16ByteRepository ):
189                 "Parse gcode text and store the gcode."
190                 self.binary16ByteRepository = binary16ByteRepository
191                 lines = archive.getTextLines(gcodeText)
192                 for line in lines:
193                         self.parseLine(line)
194                 return self.output.getvalue()
195
196         def parseLine(self, line):
197                 "Parse a gcode line."
198                 binary16ByteRepository = self.binary16ByteRepository
199                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
200                 firstWord = gcodec.getFirstWord(splitLine)
201                 if len(firstWord) < 1:
202                         return
203                 firstLetter = firstWord[0]
204                 if firstLetter == '(':
205                         return
206                 feedRateInteger = getIntegerFromCharacterLengthLineOffset('F', 0.0, splitLine, binary16ByteRepository.feedRateStepLength.value )
207                 iInteger = getIntegerFromCharacterLengthLineOffset('I', 0.0, splitLine, binary16ByteRepository.xStepLength.value )
208                 jInteger = getIntegerFromCharacterLengthLineOffset('J', 0.0, splitLine, binary16ByteRepository.yStepLength.value )
209                 xInteger = getIntegerFromCharacterLengthLineOffset('X', binary16ByteRepository.xOffset.value, splitLine, binary16ByteRepository.xStepLength.value )
210                 yInteger = getIntegerFromCharacterLengthLineOffset('Y', binary16ByteRepository.yOffset.value, splitLine, binary16ByteRepository.yStepLength.value )
211                 zInteger = getIntegerFromCharacterLengthLineOffset('Z', binary16ByteRepository.zOffset.value, splitLine, binary16ByteRepository.zStepLength.value )
212                 sixteenByteStruct = Struct('cBhhhhhhBc')
213                 flagInteger = getIntegerFlagFromCharacterSplitLine('X', splitLine )
214                 flagInteger += 2 * getIntegerFlagFromCharacterSplitLine('Y', splitLine )
215                 flagInteger += 4 * getIntegerFlagFromCharacterSplitLine('Z', splitLine )
216                 flagInteger += 8 * getIntegerFlagFromCharacterSplitLine('I', splitLine )
217                 flagInteger += 16 * getIntegerFlagFromCharacterSplitLine('J', splitLine )
218                 flagInteger += 32 * getIntegerFlagFromCharacterSplitLine('F', splitLine )
219                 packedString = sixteenByteStruct.pack( firstLetter, int( firstWord[1 :] ), xInteger, yInteger, zInteger, iInteger, jInteger, feedRateInteger, flagInteger, '#')
220                 self.output.write( packedString )
221
222
223 def main():
224         "Display the export dialog."
225         if len(sys.argv) > 1:
226                 writeOutput(' '.join(sys.argv[1 :]))
227         else:
228                 settings.startMainLoopFromConstructor(getNewRepository())
229
230 if __name__ == "__main__":
231         main()