chiark / gitweb /
Add temperature control to print window
[cura.git] / Cura / gui / printWindow.py
1 from __future__ import absolute_import\r
2 import __init__\r
3 \r
4 import wx, threading, re\r
5 \r
6 from gui import machineCom\r
7 from gui import icon\r
8 from util import gcodeInterpreter\r
9 \r
10 printWindowHandle = None\r
11 \r
12 def printFile(filename):\r
13         global printWindowHandle\r
14         if printWindowHandle == None:\r
15                 printWindowHandle = printWindow()\r
16                 printWindowHandle.OnConnect(None)\r
17         printWindowHandle.Show(True)\r
18         printWindowHandle.Raise()\r
19         printWindowHandle.LoadGCodeFile(filename)\r
20 \r
21 class printWindow(wx.Frame):\r
22         "Main user interface window"\r
23         def __init__(self):\r
24                 super(printWindow, self).__init__(None, -1, title='Printing')\r
25                 self.machineCom = None\r
26                 self.machineConnected = False\r
27                 self.thread = None\r
28                 self.gcode = None\r
29                 self.gcodeList = None\r
30                 self.sendList = []\r
31                 self.printIdx = None\r
32                 self.temp = None\r
33                 self.bufferLineCount = 4\r
34                 self.sendCnt = 0\r
35 \r
36                 #self.SetIcon(icon.getMainIcon())\r
37                 \r
38                 self.SetSizer(wx.BoxSizer())\r
39                 self.panel = wx.Panel(self)\r
40                 self.GetSizer().Add(self.panel, 1, flag=wx.EXPAND)\r
41                 self.sizer = wx.GridBagSizer(2, 2)\r
42                 self.panel.SetSizer(self.sizer)\r
43                 \r
44                 sb = wx.StaticBox(self.panel, label="Statistics")\r
45                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)\r
46                 self.statsText = wx.StaticText(self.panel, -1, "Filament: ####.##m #.##g\nPrint time: #####:##")\r
47                 boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)\r
48                 \r
49                 self.sizer.Add(boxsizer, pos=(0,0), span=(4,1), flag=wx.EXPAND)\r
50                 \r
51                 self.connectButton = wx.Button(self.panel, -1, 'Connect')\r
52                 #self.loadButton = wx.Button(self.panel, -1, 'Load GCode')\r
53                 self.printButton = wx.Button(self.panel, -1, 'Print GCode')\r
54                 self.cancelButton = wx.Button(self.panel, -1, 'Cancel print')\r
55                 self.progress = wx.Gauge(self.panel, -1)\r
56                 \r
57                 h = self.connectButton.GetSize().GetHeight()\r
58                 self.temperatureSelect = wx.SpinCtrl(self.panel, -1, '0', size=(21*3,21), style=wx.SP_ARROW_KEYS)\r
59                 self.temperatureSelect.SetRange(0, 400)\r
60                 \r
61                 self.sizer.Add(self.connectButton, pos=(0,1))\r
62                 #self.sizer.Add(self.loadButton, pos=(1,1))\r
63                 self.sizer.Add(self.printButton, pos=(2,1))\r
64                 self.sizer.Add(self.cancelButton, pos=(3,1))\r
65                 self.sizer.Add(self.progress, pos=(4,0), span=(1,2), flag=wx.EXPAND)\r
66 \r
67                 self.sizer.Add(wx.StaticText(self.panel, -1, "Temp:"), pos=(0,3))\r
68                 self.sizer.Add(self.temperatureSelect, pos=(0,4))\r
69 \r
70                 self.sizer.AddGrowableRow(3)\r
71                 self.sizer.AddGrowableCol(0)\r
72                 \r
73                 self.Bind(wx.EVT_CLOSE, self.OnClose)\r
74                 self.connectButton.Bind(wx.EVT_BUTTON, self.OnConnect)\r
75                 #self.loadButton.Bind(wx.EVT_BUTTON, self.OnLoad)\r
76                 self.printButton.Bind(wx.EVT_BUTTON, self.OnPrint)\r
77                 self.cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)\r
78                 \r
79                 self.Bind(wx.EVT_SPINCTRL, self.OnTempChange, self.temperatureSelect)\r
80                 \r
81                 self.Layout()\r
82                 self.Fit()\r
83                 self.Centre()\r
84                 \r
85                 self.UpdateButtonStates()\r
86                 self.UpdateProgress()\r
87         \r
88         def UpdateButtonStates(self):\r
89                 self.connectButton.Enable(not self.machineConnected)\r
90                 #self.loadButton.Enable(self.printIdx == None)\r
91                 self.printButton.Enable(self.machineConnected and self.gcodeList != None and self.printIdx == None)\r
92                 self.cancelButton.Enable(self.printIdx != None)\r
93         \r
94         def UpdateProgress(self):\r
95                 status = ""\r
96                 if self.gcode != None:\r
97                         status += "Filament: %.2fm %.2fg\n" % (self.gcode.extrusionAmount / 1000, self.gcode.calculateWeight() * 1000)\r
98                         status += "Print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))\r
99                 if self.printIdx == None:\r
100                         self.progress.SetValue(0)\r
101                         if self.gcodeList != None:\r
102                                 status += 'Line: -/%d\n' % (len(self.gcodeList))\r
103                 else:\r
104                         self.progress.SetValue(self.printIdx)\r
105                         status += 'Line: %d/%d\n' % (self.printIdx, len(self.gcodeList))\r
106                 if self.temp != None:\r
107                         status += 'Temp: %d\n' % (self.temp)\r
108                 self.statsText.SetLabel(status)\r
109         \r
110         def OnConnect(self, e):\r
111                 if self.machineCom != None:\r
112                         self.machineCom.close()\r
113                         self.thread.join()\r
114                 self.machineCom = machineCom.MachineCom()\r
115                 self.thread = threading.Thread(target=self.PrinterMonitor)\r
116                 self.thread.start()\r
117                 self.UpdateButtonStates()\r
118         \r
119         def OnLoad(self, e):\r
120                 pass\r
121         \r
122         def OnPrint(self, e):\r
123                 if not self.machineConnected:\r
124                         return\r
125                 if self.gcodeList == None:\r
126                         return\r
127                 if self.printIdx != None:\r
128                         return\r
129                 self.printIdx = 1\r
130                 self.sendLine(0)\r
131                 self.sendCnt = self.bufferLineCount\r
132                 self.UpdateButtonStates()\r
133         \r
134         def OnCancel(self, e):\r
135                 self.printIdx = None\r
136                 self.UpdateButtonStates()\r
137         \r
138         def OnClose(self, e):\r
139                 global printWindowHandle\r
140                 printWindowHandle = None\r
141                 if self.machineCom != None:\r
142                         self.machineCom.close()\r
143                         self.thread.join()\r
144                 self.Destroy()\r
145 \r
146         def OnTempChange(self, e):\r
147                 self.sendCommand("M104 S%d" % (self.temperatureSelect.GetValue()))\r
148 \r
149         def LoadGCodeFile(self, filename):\r
150                 if self.printIdx != None:\r
151                         return\r
152                 #Send an initial M110 to reset the line counter to zero.\r
153                 gcodeList = ["M110"]\r
154                 for line in open(filename, 'r'):\r
155                         if ';' in line:\r
156                                 line = line[0:line.find(';')]\r
157                         line = line.strip()\r
158                         if len(line) > 0:\r
159                                 gcodeList.append(line)\r
160                 gcode = gcodeInterpreter.gcode()\r
161                 gcode.loadList(gcodeList)\r
162                 print "Loaded: %s (%d)" % (filename, len(gcodeList))\r
163                 self.progress.SetRange(len(gcodeList))\r
164                 self.gcode = gcode\r
165                 self.gcodeList = gcodeList\r
166                 self.UpdateButtonStates()\r
167                 self.UpdateProgress()\r
168                 \r
169         def sendCommand(self, cmd):\r
170                 if self.machineConnected:\r
171                         if self.printIdx == None:\r
172                                 self.machineCom.sendCommand(cmd)\r
173                         else:\r
174                                 self.sendList.append(cmd)\r
175 \r
176         def sendLine(self, lineNr):\r
177                 if lineNr >= len(self.gcodeList):\r
178                         return False\r
179                 checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (lineNr, self.gcodeList[lineNr])))\r
180                 self.machineCom.sendCommand("N%d%s*%d" % (lineNr, self.gcodeList[lineNr], checksum))\r
181                 return True\r
182 \r
183         def PrinterMonitor(self):\r
184                 while True:\r
185                         line = self.machineCom.readline()\r
186                         if line == None:\r
187                                 self.machineConnected = False\r
188                                 wx.CallAfter(self.UpdateButtonStates)\r
189                                 return\r
190                         if self.machineConnected:\r
191                                 while self.sendCnt > 0:\r
192                                         self.sendLine(self.printIdx)\r
193                                         self.printIdx += 1\r
194                                         self.sendCnt -= 1\r
195                         elif line.startswith("start"):\r
196                                 self.machineConnected = True\r
197                                 wx.CallAfter(self.UpdateButtonStates)\r
198                         if 'T:' in line:\r
199                                 self.temp = float(re.search("[0-9\.]*", line.split('T:')[1]).group(0))\r
200                                 wx.CallAfter(self.UpdateProgress)\r
201                         if self.printIdx == None:\r
202                                 if line == '':  #When we have a communication "timeout" and we're not sending gcode read the temperature.\r
203                                         self.machineCom.sendCommand("M105")\r
204                         else:\r
205                                 if line.startswith("ok"):\r
206                                         if len(self.sendList) > 0:\r
207                                                 self.machineCom.sendCommand(self.sendList.pop(0))\r
208                                         else:\r
209                                                 if self.sendLine(self.printIdx):\r
210                                                         self.printIdx += 1\r
211                                                 else:\r
212                                                         self.printIdx = None\r
213                                                         wx.CallAfter(self.UpdateButtonStates)\r
214                                                 wx.CallAfter(self.UpdateProgress)\r
215                                 elif "resend" in line.lower() or "rs" in line:\r
216                                         try:\r
217                                                 lineNr=int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])\r
218                                         except:\r
219                                                 if "rs" in line:\r
220                                                         lineNr=int(line.split()[1])\r
221                                         self.printIdx = lineNr\r
222                                         #we should actually resend the line here, but we also get an "ok" for each error from Marlin. And thus we'll resend on the OK.\r
223 \r