2012-03-24 17:12:10 +00:00
from __future__ import absolute_import
import __init__
2012-04-19 15:35:08 +00:00
import wx , threading , re , subprocess , sys , os
from wx . lib import buttons
2012-04-01 17:16:31 +00:00
from gui import machineCom
2012-04-02 12:43:39 +00:00
from gui import icon
2012-04-12 12:26:03 +00:00
from util import profile
2012-04-02 16:56:44 +00:00
from util import gcodeInterpreter
2012-03-24 17:12:10 +00:00
2012-04-13 16:14:38 +00:00
printWindowMonitorHandle = None
2012-03-24 17:12:10 +00:00
def printFile ( filename ) :
2012-04-13 16:14:38 +00:00
global printWindowMonitorHandle
if printWindowMonitorHandle == None :
printWindowMonitorHandle = printProcessMonitor ( )
printWindowMonitorHandle . loadFile ( filename )
def startPrintInterface ( filename ) :
#startPrintInterface is called from the main script when we want the printer interface to run in a seperate process.
# It needs to run in a seperate process, as any running python code blocks the GCode sender pyton code (http://wiki.python.org/moin/GlobalInterpreterLock).
app = wx . App ( False )
printWindowHandle = printWindow ( )
2012-03-24 17:12:10 +00:00
printWindowHandle . Show ( True )
printWindowHandle . Raise ( )
2012-04-13 16:14:38 +00:00
printWindowHandle . OnConnect ( None )
2012-04-01 17:16:31 +00:00
printWindowHandle . LoadGCodeFile ( filename )
2012-04-13 16:14:38 +00:00
app . MainLoop ( )
class printProcessMonitor ( ) :
def __init__ ( self ) :
self . handle = None
def loadFile ( self , filename ) :
if self . handle == None :
self . handle = subprocess . Popen ( [ sys . executable , sys . argv [ 0 ] , ' -r ' , filename ] , stdin = subprocess . PIPE , stdout = subprocess . PIPE , stderr = subprocess . STDOUT )
self . thread = threading . Thread ( target = self . Monitor )
self . thread . start ( )
else :
self . handle . stdin . write ( filename + ' \n ' )
def Monitor ( self ) :
p = self . handle
line = p . stdout . readline ( )
while ( len ( line ) > 0 ) :
print line . rstrip ( )
line = p . stdout . readline ( )
p . wait ( )
self . handle = None
self . thread = None
2012-03-24 17:12:10 +00:00
2012-04-19 15:35:08 +00:00
class PrintCommandButton ( buttons . GenBitmapButton ) :
def __init__ ( self , parent , command , bitmapFilename , size = ( 20 , 20 ) ) :
self . bitmap = wx . Bitmap ( os . path . join ( os . path . split ( __file__ ) [ 0 ] , " ../images " , bitmapFilename ) )
super ( PrintCommandButton , self ) . __init__ ( parent . directControlPanel , - 1 , self . bitmap , size = size )
self . command = command
self . parent = parent
self . SetBezelWidth ( 1 )
self . SetUseFocusIndicator ( False )
self . Bind ( wx . EVT_BUTTON , self . OnClick )
def OnClick ( self , e ) :
2012-05-10 19:29:42 +00:00
self . parent . sendCommand ( " G91 " )
2012-04-19 15:35:08 +00:00
self . parent . sendCommand ( self . command )
e . Skip ( )
2012-03-24 17:12:10 +00:00
class printWindow ( wx . Frame ) :
" Main user interface window "
def __init__ ( self ) :
super ( printWindow , self ) . __init__ ( None , - 1 , title = ' Printing ' )
2012-04-01 17:16:31 +00:00
self . machineCom = None
2012-04-02 16:56:44 +00:00
self . machineConnected = False
2012-04-01 17:16:31 +00:00
self . thread = None
2012-04-03 10:06:02 +00:00
self . gcode = None
2012-04-01 17:16:31 +00:00
self . gcodeList = None
2012-04-04 15:02:22 +00:00
self . sendList = [ ]
2012-04-01 17:16:31 +00:00
self . printIdx = None
2012-04-04 15:02:22 +00:00
self . temp = None
2012-04-01 17:16:31 +00:00
self . bufferLineCount = 4
self . sendCnt = 0
2012-04-02 12:43:39 +00:00
2012-04-03 08:44:53 +00:00
#self.SetIcon(icon.getMainIcon())
2012-04-01 17:16:31 +00:00
2012-03-28 18:36:46 +00:00
self . SetSizer ( wx . BoxSizer ( ) )
self . panel = wx . Panel ( self )
self . GetSizer ( ) . Add ( self . panel , 1 , flag = wx . EXPAND )
self . sizer = wx . GridBagSizer ( 2 , 2 )
self . panel . SetSizer ( self . sizer )
2012-03-24 17:12:10 +00:00
2012-03-28 18:36:46 +00:00
sb = wx . StaticBox ( self . panel , label = " Statistics " )
boxsizer = wx . StaticBoxSizer ( sb , wx . VERTICAL )
2012-04-03 18:27:46 +00:00
self . statsText = wx . StaticText ( self . panel , - 1 , " Filament: ####.##m #.##g \n Print time: #####:## " )
2012-04-02 16:56:44 +00:00
boxsizer . Add ( self . statsText , flag = wx . LEFT , border = 5 )
2012-03-24 17:12:10 +00:00
2012-03-28 18:36:46 +00:00
self . sizer . Add ( boxsizer , pos = ( 0 , 0 ) , span = ( 4 , 1 ) , flag = wx . EXPAND )
2012-04-03 18:27:46 +00:00
self . connectButton = wx . Button ( self . panel , - 1 , ' Connect ' )
2012-04-03 15:01:51 +00:00
#self.loadButton = wx.Button(self.panel, -1, 'Load GCode')
2012-04-01 17:16:31 +00:00
self . printButton = wx . Button ( self . panel , - 1 , ' Print GCode ' )
self . cancelButton = wx . Button ( self . panel , - 1 , ' Cancel print ' )
2012-04-02 16:56:44 +00:00
self . progress = wx . Gauge ( self . panel , - 1 )
2012-04-04 15:02:22 +00:00
h = self . connectButton . GetSize ( ) . GetHeight ( )
self . temperatureSelect = wx . SpinCtrl ( self . panel , - 1 , ' 0 ' , size = ( 21 * 3 , 21 ) , style = wx . SP_ARROW_KEYS )
self . temperatureSelect . SetRange ( 0 , 400 )
2012-04-03 18:27:46 +00:00
self . sizer . Add ( self . connectButton , pos = ( 0 , 1 ) )
2012-04-03 15:01:51 +00:00
#self.sizer.Add(self.loadButton, pos=(1,1))
2012-04-01 17:16:31 +00:00
self . sizer . Add ( self . printButton , pos = ( 2 , 1 ) )
self . sizer . Add ( self . cancelButton , pos = ( 3 , 1 ) )
2012-04-02 16:56:44 +00:00
self . sizer . Add ( self . progress , pos = ( 4 , 0 ) , span = ( 1 , 2 ) , flag = wx . EXPAND )
2012-04-19 15:35:08 +00:00
2012-04-04 15:02:22 +00:00
self . sizer . Add ( wx . StaticText ( self . panel , - 1 , " Temp: " ) , pos = ( 0 , 3 ) )
self . sizer . Add ( self . temperatureSelect , pos = ( 0 , 4 ) )
2012-04-19 15:35:08 +00:00
self . directControlPanel = wx . Panel ( self . panel )
self . sizer . Add ( self . directControlPanel , pos = ( 1 , 3 ) , span = ( 5 , 4 ) )
sizer = wx . GridBagSizer ( 2 , 2 )
self . directControlPanel . SetSizer ( sizer )
2012-04-19 19:39:44 +00:00
sizer . Add ( PrintCommandButton ( self , ' G1 Y100 F6000 ' , ' print-move-y100.png ' ) , pos = ( 0 , 3 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Y10 F6000 ' , ' print-move-y10.png ' ) , pos = ( 1 , 3 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Y1 F6000 ' , ' print-move-y1.png ' ) , pos = ( 2 , 3 ) )
2012-04-19 15:35:08 +00:00
2012-04-19 19:39:44 +00:00
sizer . Add ( PrintCommandButton ( self , ' G1 Y-1 F6000 ' , ' print-move-y-1.png ' ) , pos = ( 4 , 3 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Y-10 F6000 ' , ' print-move-y-10.png ' ) , pos = ( 5 , 3 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Y-100 F6000 ' , ' print-move-y-100.png ' ) , pos = ( 6 , 3 ) )
2012-04-19 15:35:08 +00:00
2012-04-19 19:39:44 +00:00
sizer . Add ( PrintCommandButton ( self , ' G1 X-100 F6000 ' , ' print-move-x-100.png ' ) , pos = ( 3 , 0 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 X-10 F6000 ' , ' print-move-x-10.png ' ) , pos = ( 3 , 1 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 X-1 F6000 ' , ' print-move-x-1.png ' ) , pos = ( 3 , 2 ) )
2012-04-19 15:35:08 +00:00
2012-05-11 08:14:25 +00:00
sizer . Add ( PrintCommandButton ( self , ' G28 X0 Y0 ' , ' print-move-home.png ' ) , pos = ( 3 , 3 ) )
2012-05-10 19:29:42 +00:00
2012-04-19 19:39:44 +00:00
sizer . Add ( PrintCommandButton ( self , ' G1 X1 F6000 ' , ' print-move-x1.png ' ) , pos = ( 3 , 4 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 X10 F6000 ' , ' print-move-x10.png ' ) , pos = ( 3 , 5 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 X100 F6000 ' , ' print-move-x100.png ' ) , pos = ( 3 , 6 ) )
2012-04-19 15:35:08 +00:00
2012-05-11 08:14:25 +00:00
sizer . Add ( PrintCommandButton ( self , ' G1 Z10 F200 ' , ' print-move-z10.png ' ) , pos = ( 0 , 7 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Z1 F200 ' , ' print-move-z1.png ' ) , pos = ( 1 , 7 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Z0.1 F200 ' , ' print-move-z0.1.png ' ) , pos = ( 2 , 7 ) )
2012-04-19 15:35:08 +00:00
2012-05-11 08:14:25 +00:00
sizer . Add ( PrintCommandButton ( self , ' G28 Z0 ' , ' print-move-home.png ' ) , pos = ( 3 , 7 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Z-0.1 F200 ' , ' print-move-z-0.1.png ' ) , pos = ( 4 , 7 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Z-1 F200 ' , ' print-move-z-1.png ' ) , pos = ( 5 , 7 ) )
sizer . Add ( PrintCommandButton ( self , ' G1 Z-10 F200 ' , ' print-move-z-10.png ' ) , pos = ( 6 , 7 ) )
2012-04-04 15:02:22 +00:00
2012-03-28 18:36:46 +00:00
self . sizer . AddGrowableRow ( 3 )
self . sizer . AddGrowableCol ( 0 )
2012-03-24 17:12:10 +00:00
self . Bind ( wx . EVT_CLOSE , self . OnClose )
2012-04-03 18:27:46 +00:00
self . connectButton . Bind ( wx . EVT_BUTTON , self . OnConnect )
2012-04-03 15:01:51 +00:00
#self.loadButton.Bind(wx.EVT_BUTTON, self.OnLoad)
2012-04-01 17:16:31 +00:00
self . printButton . Bind ( wx . EVT_BUTTON , self . OnPrint )
self . cancelButton . Bind ( wx . EVT_BUTTON , self . OnCancel )
2012-03-24 17:12:10 +00:00
2012-04-04 15:02:22 +00:00
self . Bind ( wx . EVT_SPINCTRL , self . OnTempChange , self . temperatureSelect )
2012-03-24 17:12:10 +00:00
self . Layout ( )
self . Fit ( )
self . Centre ( )
2012-04-02 16:56:44 +00:00
self . UpdateButtonStates ( )
self . UpdateProgress ( )
def UpdateButtonStates ( self ) :
2012-04-03 18:27:46 +00:00
self . connectButton . Enable ( not self . machineConnected )
2012-04-03 15:01:51 +00:00
#self.loadButton.Enable(self.printIdx == None)
2012-04-02 16:56:44 +00:00
self . printButton . Enable ( self . machineConnected and self . gcodeList != None and self . printIdx == None )
self . cancelButton . Enable ( self . printIdx != None )
2012-04-19 15:35:08 +00:00
self . temperatureSelect . Enable ( self . machineConnected )
self . directControlPanel . Enable ( self . machineConnected )
2012-04-02 16:56:44 +00:00
def UpdateProgress ( self ) :
status = " "
2012-04-03 10:06:02 +00:00
if self . gcode != None :
status + = " Filament: %.2f m %.2f g \n " % ( self . gcode . extrusionAmount / 1000 , self . gcode . calculateWeight ( ) * 1000 )
2012-04-29 10:00:13 +00:00
cost = self . gcode . calculateCost ( )
if cost != False :
status + = " Filament cost: %s \n " % ( cost )
2012-04-03 10:06:02 +00:00
status + = " Print time: %02d : %02d \n " % ( int ( self . gcode . totalMoveTimeMinute / 60 ) , int ( self . gcode . totalMoveTimeMinute % 60 ) )
2012-04-02 16:56:44 +00:00
if self . printIdx == None :
self . progress . SetValue ( 0 )
2012-04-03 10:06:02 +00:00
if self . gcodeList != None :
status + = ' Line: -/ %d \n ' % ( len ( self . gcodeList ) )
2012-04-02 16:56:44 +00:00
else :
status + = ' Line: %d / %d \n ' % ( self . printIdx , len ( self . gcodeList ) )
2012-04-13 16:14:38 +00:00
self . progress . SetValue ( self . printIdx )
2012-04-04 15:02:22 +00:00
if self . temp != None :
status + = ' Temp: %d \n ' % ( self . temp )
2012-04-11 21:49:09 +00:00
self . statsText . SetLabel ( status . strip ( ) )
self . Layout ( )
2012-03-24 17:12:10 +00:00
2012-04-01 17:16:31 +00:00
def OnConnect ( self , e ) :
if self . machineCom != None :
self . machineCom . close ( )
self . thread . join ( )
self . machineCom = machineCom . MachineCom ( )
self . thread = threading . Thread ( target = self . PrinterMonitor )
self . thread . start ( )
2012-04-02 16:56:44 +00:00
self . UpdateButtonStates ( )
2012-04-01 17:16:31 +00:00
def OnLoad ( self , e ) :
pass
def OnPrint ( self , e ) :
2012-04-02 16:56:44 +00:00
if not self . machineConnected :
2012-04-01 17:16:31 +00:00
return
if self . gcodeList == None :
return
if self . printIdx != None :
return
self . printIdx = 1
self . sendLine ( 0 )
self . sendCnt = self . bufferLineCount
2012-04-02 16:56:44 +00:00
self . UpdateButtonStates ( )
2012-04-01 17:16:31 +00:00
def OnCancel ( self , e ) :
2012-04-02 16:56:44 +00:00
self . printIdx = None
self . UpdateButtonStates ( )
2012-04-01 17:16:31 +00:00
2012-03-24 17:12:10 +00:00
def OnClose ( self , e ) :
global printWindowHandle
printWindowHandle = None
2012-04-01 17:16:31 +00:00
if self . machineCom != None :
self . machineCom . close ( )
self . thread . join ( )
2012-03-24 17:12:10 +00:00
self . Destroy ( )
2012-04-01 17:16:31 +00:00
2012-04-04 15:02:22 +00:00
def OnTempChange ( self , e ) :
self . sendCommand ( " M104 S %d " % ( self . temperatureSelect . GetValue ( ) ) )
2012-04-01 17:16:31 +00:00
def LoadGCodeFile ( self , filename ) :
2012-04-03 15:01:51 +00:00
if self . printIdx != None :
return
2012-04-04 15:02:22 +00:00
#Send an initial M110 to reset the line counter to zero.
2012-04-01 17:16:31 +00:00
gcodeList = [ " M110 " ]
for line in open ( filename , ' r ' ) :
if ' ; ' in line :
line = line [ 0 : line . find ( ' ; ' ) ]
line = line . strip ( )
if len ( line ) > 0 :
gcodeList . append ( line )
2012-04-02 16:56:44 +00:00
gcode = gcodeInterpreter . gcode ( )
gcode . loadList ( gcodeList )
2012-04-01 17:16:31 +00:00
print " Loaded: %s ( %d ) " % ( filename , len ( gcodeList ) )
2012-04-02 16:56:44 +00:00
self . progress . SetRange ( len ( gcodeList ) )
2012-04-03 10:06:02 +00:00
self . gcode = gcode
2012-04-01 17:16:31 +00:00
self . gcodeList = gcodeList
2012-04-02 16:56:44 +00:00
self . UpdateButtonStates ( )
self . UpdateProgress ( )
2012-04-04 15:02:22 +00:00
def sendCommand ( self , cmd ) :
if self . machineConnected :
if self . printIdx == None :
self . machineCom . sendCommand ( cmd )
else :
self . sendList . append ( cmd )
2012-04-01 17:16:31 +00:00
def sendLine ( self , lineNr ) :
if lineNr > = len ( self . gcodeList ) :
2012-04-03 10:06:02 +00:00
return False
2012-04-01 17:16:31 +00:00
checksum = reduce ( lambda x , y : x ^ y , map ( ord , " N %d %s " % ( lineNr , self . gcodeList [ lineNr ] ) ) )
self . machineCom . sendCommand ( " N %d %s * %d " % ( lineNr , self . gcodeList [ lineNr ] , checksum ) )
2012-04-03 10:06:02 +00:00
return True
2012-04-01 17:16:31 +00:00
def PrinterMonitor ( self ) :
while True :
line = self . machineCom . readline ( )
if line == None :
2012-04-02 16:56:44 +00:00
self . machineConnected = False
2012-04-03 10:06:02 +00:00
wx . CallAfter ( self . UpdateButtonStates )
2012-04-01 17:16:31 +00:00
return
2012-04-02 16:56:44 +00:00
if self . machineConnected :
while self . sendCnt > 0 :
self . sendLine ( self . printIdx )
self . printIdx + = 1
self . sendCnt - = 1
elif line . startswith ( " start " ) :
self . machineConnected = True
2012-04-03 10:06:02 +00:00
wx . CallAfter ( self . UpdateButtonStates )
2012-04-04 15:02:22 +00:00
if ' T: ' in line :
self . temp = float ( re . search ( " [0-9 \ .]* " , line . split ( ' T: ' ) [ 1 ] ) . group ( 0 ) )
wx . CallAfter ( self . UpdateProgress )
if self . printIdx == None :
2012-04-05 14:50:59 +00:00
if line == ' ' : #When we have a communication "timeout" and we're not sending gcode, then read the temperature.
2012-04-04 15:02:22 +00:00
self . machineCom . sendCommand ( " M105 " )
else :
2012-04-01 17:16:31 +00:00
if line . startswith ( " ok " ) :
2012-04-04 15:02:22 +00:00
if len ( self . sendList ) > 0 :
self . machineCom . sendCommand ( self . sendList . pop ( 0 ) )
2012-04-01 17:16:31 +00:00
else :
2012-04-03 10:06:02 +00:00
if self . sendLine ( self . printIdx ) :
self . printIdx + = 1
2012-04-03 15:01:51 +00:00
else :
self . printIdx = None
wx . CallAfter ( self . UpdateButtonStates )
2012-04-02 16:56:44 +00:00
wx . CallAfter ( self . UpdateProgress )
2012-04-01 17:16:31 +00:00
elif " resend " in line . lower ( ) or " rs " in line :
try :
lineNr = int ( line . replace ( " N: " , " " ) . replace ( " N " , " " ) . replace ( " : " , " " ) . split ( ) [ - 1 ] )
except :
if " rs " in line :
lineNr = int ( line . split ( ) [ 1 ] )
self . printIdx = lineNr
2012-04-02 17:34:27 +00:00
#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.
2012-04-03 10:06:02 +00:00