Import grbl v1.1h
diff --git a/doc/script/stream.py b/doc/script/stream.py
new file mode 100755
index 0000000..4a637ab
--- /dev/null
+++ b/doc/script/stream.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python
+"""\
+
+Stream g-code to grbl controller
+
+This script differs from the simple_stream.py script by 
+tracking the number of characters in grbl's serial read
+buffer. This allows grbl to fetch the next line directly
+from the serial buffer and does not have to wait for a 
+response from the computer. This effectively adds another
+buffer layer to prevent buffer starvation.
+
+CHANGELOG:
+- 20170531: Status report feedback at 1.0 second intervals.
+    Configurable baudrate and report intervals. Bug fixes.
+- 20161212: Added push message feedback for simple streaming
+- 20140714: Updated baud rate to 115200. Added a settings
+  write mode via simple streaming method. MIT-licensed.
+
+TODO: 
+- Add realtime control commands during streaming.
+
+---------------------
+The MIT License (MIT)
+
+Copyright (c) 2012-2017 Sungeun K. Jeon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+---------------------
+"""
+
+import serial
+import re
+import time
+import sys
+import argparse
+import threading
+
+RX_BUFFER_SIZE = 128
+BAUD_RATE = 115200
+ENABLE_STATUS_REPORTS = True
+REPORT_INTERVAL = 1.0 # seconds
+
+is_run = True # Controls query timer
+
+# Define command line argument interface
+parser = argparse.ArgumentParser(description='Stream g-code file to grbl. (pySerial and argparse libraries required)')
+parser.add_argument('gcode_file', type=argparse.FileType('r'),
+        help='g-code filename to be streamed')
+parser.add_argument('device_file',
+        help='serial device path')
+parser.add_argument('-q','--quiet',action='store_true', default=False, 
+        help='suppress output text')
+parser.add_argument('-s','--settings',action='store_true', default=False, 
+        help='settings write mode')        
+parser.add_argument('-c','--check',action='store_true', default=False,
+        help='stream in check mode')
+args = parser.parse_args()
+
+# Periodic timer to query for status reports
+# TODO: Need to track down why this doesn't restart consistently before a release.
+def send_status_query():
+    s.write('?')
+    
+def periodic_timer() :
+    while is_run:
+      send_status_query()
+      time.sleep(REPORT_INTERVAL)
+  
+
+# Initialize
+s = serial.Serial(args.device_file,BAUD_RATE)
+f = args.gcode_file
+verbose = True
+if args.quiet : verbose = False
+settings_mode = False
+if args.settings : settings_mode = True
+check_mode = False
+if args.check : check_mode = True
+
+# Wake up grbl
+print "Initializing Grbl..."
+s.write("\r\n\r\n")
+
+# Wait for grbl to initialize and flush startup text in serial input
+time.sleep(2)
+s.flushInput()
+
+if check_mode :
+    print "Enabling Grbl Check-Mode: SND: [$C]",
+    s.write("$C\n")
+    while 1:
+        grbl_out = s.readline().strip() # Wait for grbl response with carriage return
+        if grbl_out.find('error') >= 0 :
+            print "REC:",grbl_out
+            print "  Failed to set Grbl check-mode. Aborting..."
+            quit()
+        elif grbl_out.find('ok') >= 0 :
+            if verbose: print 'REC:',grbl_out
+            break
+
+start_time = time.time();
+
+# Start status report periodic timer
+if ENABLE_STATUS_REPORTS :
+    timerThread = threading.Thread(target=periodic_timer)
+    timerThread.daemon = True
+    timerThread.start()
+
+# Stream g-code to grbl
+l_count = 0
+error_count = 0
+if settings_mode:
+    # Send settings file via simple call-response streaming method. Settings must be streamed
+    # in this manner since the EEPROM accessing cycles shut-off the serial interrupt.
+    print "SETTINGS MODE: Streaming", args.gcode_file.name, " to ", args.device_file
+    for line in f:
+        l_count += 1 # Iterate line counter    
+        # l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
+        l_block = line.strip() # Strip all EOL characters for consistency
+        if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
+        s.write(l_block + '\n') # Send g-code block to grbl
+        while 1:
+            grbl_out = s.readline().strip() # Wait for grbl response with carriage return
+            if grbl_out.find('ok') >= 0 :
+                if verbose: print "  REC<"+str(l_count)+": \""+grbl_out+"\""
+                break
+            elif grbl_out.find('error') >= 0 :
+                if verbose: print "  REC<"+str(l_count)+": \""+grbl_out+"\""
+                error_count += 1
+                break
+            else:
+                print "    MSG: \""+grbl_out+"\""
+else:    
+    # Send g-code program via a more agressive streaming protocol that forces characters into
+    # Grbl's serial read buffer to ensure Grbl has immediate access to the next g-code command
+    # rather than wait for the call-response serial protocol to finish. This is done by careful
+    # counting of the number of characters sent by the streamer to Grbl and tracking Grbl's 
+    # responses, such that we never overflow Grbl's serial read buffer. 
+    g_count = 0
+    c_line = []
+    for line in f:
+        l_count += 1 # Iterate line counter
+        l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
+        # l_block = line.strip()
+        c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
+        grbl_out = '' 
+        while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
+            out_temp = s.readline().strip() # Wait for grbl response
+            if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
+                print "    MSG: \""+out_temp+"\"" # Debug response
+            else :
+                if out_temp.find('error') >= 0 : error_count += 1
+                g_count += 1 # Iterate g-code counter
+                if verbose: print "  REC<"+str(g_count)+": \""+out_temp+"\""
+                del c_line[0] # Delete the block character count corresponding to the last 'ok'
+        s.write(l_block + '\n') # Send g-code block to grbl
+        if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
+    # Wait until all responses have been received.
+    while l_count > g_count :
+        out_temp = s.readline().strip() # Wait for grbl response
+        if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
+            print "    MSG: \""+out_temp+"\"" # Debug response
+        else :
+            if out_temp.find('error') >= 0 : error_count += 1
+            g_count += 1 # Iterate g-code counter
+            del c_line[0] # Delete the block character count corresponding to the last 'ok'
+            if verbose: print "  REC<"+str(g_count)+": \""+out_temp + "\""
+
+# Wait for user input after streaming is completed
+print "\nG-code streaming finished!"
+end_time = time.time();
+is_run = False;
+print " Time elapsed: ",end_time-start_time,"\n"
+if check_mode :
+    if error_count > 0 :
+        print "CHECK FAILED:",error_count,"errors found! See output for details.\n"
+    else :
+        print "CHECK PASSED: No errors found in g-code program.\n"
+else :
+   print "WARNING: Wait until Grbl completes buffered g-code blocks before exiting."
+   raw_input("  Press <Enter> to exit and disable Grbl.") 
+
+# Close file and serial port
+f.close()
+s.close()