1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
11 from Cura.util import machineCom
12 from Cura.util.printerConnection import printerConnectionBase
14 class serialConnectionGroup(printerConnectionBase.printerConnectionGroup):
16 super(serialConnectionGroup, self).__init__("USB")
17 self._connectionMap = {}
19 def getAvailableConnections(self):
20 serialList = machineCom.serialList(True)
21 for port in machineCom.serialList(True):
22 if port not in self._connectionMap:
23 self._connectionMap[port] = serialConnection(port)
24 for key in self._connectionMap.keys():
25 if key not in serialList and not self._connectionMap[key].isActiveConnectionOpen():
26 self._connectionMap.pop(key)
27 return self._connectionMap.values()
32 def getPriority(self):
35 class serialConnection(printerConnectionBase.printerConnectionBase):
36 def __init__(self, port):
37 super(serialConnection, self).__init__(port)
43 self._temperature = []
44 self._targetTemperature = []
45 self._bedTemperature = 0
46 self._targetBedTemperature = 0
49 self._commState = None
50 self._commStateString = None
53 #Load the data into memory for printing, returns True on success
54 def loadGCodeData(self, dataStream):
55 if self.isPrinting() is None:
58 for line in dataStream:
59 #Strip out comments, we do not need to send comments
61 line = line[:line.index(';')]
62 #Strip out whitespace at the beginning/end this saves data to send.
67 self._gcodeData.append(line)
70 #Start printing the previously loaded file
72 if self.isPrinting() or len(self._gcodeData) < 1 or self._process is None:
74 self._process.stdin.write('STOP\n')
75 for line in self._gcodeData:
76 self._process.stdin.write('G:%s\n' % (line))
77 self._process.stdin.write('START\n')
78 self._printProgress = 0
80 #Abort the previously loaded print file
81 def cancelPrint(self):
82 if not self.isPrinting()or self._process is None:
84 self._process.stdin.write('STOP\n')
85 self._printProgress = 0
88 return self._commState == machineCom.MachineCom.STATE_PRINTING
90 #Amount of progression of the current print file. 0.0 to 1.0
91 def getPrintProgress(self):
92 if len(self._gcodeData) < 1:
94 return float(self._printProgress) / float(len(self._gcodeData))
96 # Return if the printer with this connection type is available
97 def isAvailable(self):
100 # Get the connection status string. This is displayed to the user and can be used to communicate
101 # various information to the user.
102 def getStatusString(self):
103 return "%s" % (self._commStateString)
105 #Returns true if we need to establish an active connection. True for serial connections.
106 def hasActiveConnection(self):
109 #Open the active connection to the printer so we can send commands
110 def openActiveConnection(self):
111 self.closeActiveConnection()
112 self._thread = threading.Thread(target=self._serialCommunicationThread)
113 self._thread.daemon = True
116 #Close the active connection to the printer
117 def closeActiveConnection(self):
118 if self._process is not None:
119 self._process.terminate()
122 #Is the active connection open right now.
123 def isActiveConnectionOpen(self):
124 if self._process is None:
126 return self._commState == machineCom.MachineCom.STATE_OPERATIONAL or self._commState == machineCom.MachineCom.STATE_PRINTING or self._commState == machineCom.MachineCom.STATE_PAUSED
128 def getTemperature(self, extruder):
129 if extruder >= len(self._temperature):
131 return self._temperature[extruder]
133 def getBedTemperature(self):
134 return self._bedTemperature
136 #Are we able to send a direct coammand with sendCommand at this moment in time.
137 def isAbleToSendDirectCommand(self):
138 return self.isActiveConnectionOpen()
140 #Directly send a command to the printer.
141 def sendCommand(self, command):
142 if self._process is None:
144 self._process.stdin.write('C:%s\n' % (command))
146 #Returns true if we got some kind of error. The getErrorLog returns all the information to diagnose the problem.
147 def isInErrorState(self):
148 return self._commState == machineCom.MachineCom.STATE_ERROR or self._commState == machineCom.MachineCom.STATE_CLOSED_WITH_ERROR
150 #Returns the error log in case there was an error.
151 def getErrorLog(self):
152 return '\n'.join(self._log)
154 def _serialCommunicationThread(self):
155 if platform.system() == "Darwin" and hasattr(sys, 'frozen'):
156 cmdList = [os.path.join(os.path.dirname(sys.executable), 'Cura'), '--serialCommunication']
158 cmdList = [sys.executable, '-m', 'Cura.serialCommunication']
159 cmdList += [self._portName]
160 if platform.system() == "Darwin":
161 if platform.machine() == 'i386':
162 cmdList = ['arch', '-i386'] + cmdList
163 self._process = subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
164 line = self._process.stdout.readline()
167 line = line.split(':', 1)
170 elif line[0] == 'log':
171 self._log.append(line[1])
172 if len(self._log) > 30:
174 elif line[0] == 'temp':
175 line = line[1].split(':')
176 self._temperature = json.loads(line[0])
177 self._targetTemperature = json.loads(line[1])
178 self._bedTemperature = float(line[2])
179 self._targetBedTemperature = float(line[3])
181 elif line[0] == 'message':
182 self._doCallback(line[1])
183 elif line[0] == 'state':
184 line = line[1].split(':', 1)
185 self._commState = int(line[0])
186 self._commStateString = line[1]
188 elif line[0] == 'progress':
189 self._printProgress = int(line[1])
193 line = self._process.stdout.readline()