Sergey Pastor / grbl1
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers stream.py Source File

stream.py

00001 #!/usr/bin/env python
00002 """\
00003 
00004 Stream g-code to grbl controller
00005 
00006 This script differs from the simple_stream.py script by 
00007 tracking the number of characters in grbl's serial read
00008 buffer. This allows grbl to fetch the next line directly
00009 from the serial buffer and does not have to wait for a 
00010 response from the computer. This effectively adds another
00011 buffer layer to prevent buffer starvation.
00012 
00013 CHANGELOG:
00014 - 20161212: Added push message feedback for simple streaming
00015 - 20140714: Updated baud rate to 115200. Added a settings
00016   write mode via simple streaming method. MIT-licensed.
00017 
00018 TODO: 
00019 - Add runtime command capabilities
00020 
00021 ---------------------
00022 The MIT License (MIT)
00023 
00024 Copyright (c) 2012-2016 Sungeun K. Jeon
00025 
00026 Permission is hereby granted, free of charge, to any person obtaining a copy
00027 of this software and associated documentation files (the "Software"), to deal
00028 in the Software without restriction, including without limitation the rights
00029 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00030 copies of the Software, and to permit persons to whom the Software is
00031 furnished to do so, subject to the following conditions:
00032 
00033 The above copyright notice and this permission notice shall be included in
00034 all copies or substantial portions of the Software.
00035 
00036 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00037 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00038 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00039 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00040 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00041 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00042 THE SOFTWARE.
00043 ---------------------
00044 """
00045 
00046 import serial
00047 import re
00048 import time
00049 import sys
00050 import argparse
00051 # import threading
00052 
00053 RX_BUFFER_SIZE = 128
00054 
00055 # Define command line argument interface
00056 parser = argparse.ArgumentParser(description='Stream g-code file to grbl. (pySerial and argparse libraries required)')
00057 parser.add_argument('gcode_file', type=argparse.FileType('r'),
00058         help='g-code filename to be streamed')
00059 parser.add_argument('device_file',
00060         help='serial device path')
00061 parser.add_argument('-q','--quiet',action='store_true', default=False, 
00062         help='suppress output text')
00063 parser.add_argument('-s','--settings',action='store_true', default=False, 
00064         help='settings write mode')        
00065 args = parser.parse_args()
00066 
00067 # Periodic timer to query for status reports
00068 # TODO: Need to track down why this doesn't restart consistently before a release.
00069 # def periodic():
00070 #     s.write('?')
00071 #     t = threading.Timer(0.1, periodic) # In seconds
00072 #     t.start()
00073 
00074 # Initialize
00075 s = serial.Serial(args.device_file,115200)
00076 f = args.gcode_file
00077 verbose = True
00078 if args.quiet : verbose = False
00079 settings_mode = False
00080 if args.settings : settings_mode = True
00081 
00082 # Wake up grbl
00083 print "Initializing grbl..."
00084 s.write("\r\n\r\n")
00085 
00086 # Wait for grbl to initialize and flush startup text in serial input
00087 time.sleep(2)
00088 s.flushInput()
00089 
00090 # Stream g-code to grbl
00091 l_count = 0
00092 if settings_mode:
00093     # Send settings file via simple call-response streaming method. Settings must be streamed
00094     # in this manner since the EEPROM accessing cycles shut-off the serial interrupt.
00095     print "SETTINGS MODE: Streaming", args.gcode_file.name, " to ", args.device_file
00096     for line in f:
00097         l_count += 1 # Iterate line counter    
00098         # l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
00099         l_block = line.strip() # Strip all EOL characters for consistency
00100         if verbose: print 'SND: ' + str(l_count) + ':' + l_block,
00101         s.write(l_block + '\n') # Send g-code block to grbl
00102         while 1:
00103             grbl_out = s.readline().strip() # Wait for grbl response with carriage return
00104             if grbl_out.find('ok') < 0 and grbl_out.find('error') < 0 :
00105                 print "\n  Debug: ",grbl_out,
00106             else : 
00107                 if verbose: print 'REC:',grbl_out
00108                 break
00109 else:    
00110     # Send g-code program via a more agressive streaming protocol that forces characters into
00111     # Grbl's serial read buffer to ensure Grbl has immediate access to the next g-code command
00112     # rather than wait for the call-response serial protocol to finish. This is done by careful
00113     # counting of the number of characters sent by the streamer to Grbl and tracking Grbl's 
00114     # responses, such that we never overflow Grbl's serial read buffer. 
00115     g_count = 0
00116     c_line = []
00117     # periodic() # Start status report periodic timer
00118     for line in f:
00119         l_count += 1 # Iterate line counter
00120         # l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
00121         l_block = line.strip()
00122         c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
00123         grbl_out = '' 
00124         while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
00125             out_temp = s.readline().strip() # Wait for grbl response
00126             if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
00127                 print "  Debug: ",out_temp # Debug response
00128             else :
00129                 grbl_out += out_temp;
00130                 g_count += 1 # Iterate g-code counter
00131                 grbl_out += str(g_count); # Add line finished indicator
00132                 del c_line[0] # Delete the block character count corresponding to the last 'ok'
00133         if verbose: print "SND: " + str(l_count) + " : " + l_block,
00134         s.write(l_block + '\n') # Send g-code block to grbl
00135         if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out
00136 
00137 # Wait for user input after streaming is completed
00138 print "G-code streaming finished!\n"
00139 print "WARNING: Wait until grbl completes buffered g-code blocks before exiting."
00140 raw_input("  Press <Enter> to exit and disable grbl.") 
00141 
00142 # Close file and serial port
00143 f.close()
00144 s.close()