diff --git a/src/com/t_oster/liblasercut/LibInfo.java b/src/com/t_oster/liblasercut/LibInfo.java
index 1da3a5de245b9363e42443da4c2956bfb509a1c3..a7c9cf0e58dd2ace34135032b4cd921e34c13aba 100644
--- a/src/com/t_oster/liblasercut/LibInfo.java
+++ b/src/com/t_oster/liblasercut/LibInfo.java
@@ -48,6 +48,7 @@ public class LibInfo
       ExportSVG.class,
       MakeBlockXYPlotter.class,
       GenericGcodeDriver.class,
+      Grbl.class,
       SmoothieBoard.class,
       Marlin.class
     };
diff --git a/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java b/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java
index 7594ad36c26ac66e2ba8b1a80f2f737dd77a5877..64e3bca14451106950eed277dde05c49ed52e786 100644
--- a/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java
+++ b/src/com/t_oster/liblasercut/drivers/GenericGcodeDriver.java
@@ -245,7 +245,7 @@ public class GenericGcodeDriver extends LaserCutter {
   
   @Override
   public String getModelName() {
-    return "Generic GRBL GCode Driver";
+    return "Generic GCode Driver";
   }
   
   /**
@@ -473,8 +473,8 @@ public class GenericGcodeDriver extends LaserCutter {
     }
   }
 
-  private BufferedReader in;
-  private PrintStream out;
+  protected BufferedReader in;
+  protected PrintStream out;
   private Socket socket;
   private CommPort port;
   private CommPortIdentifier portIdentifier;
@@ -534,10 +534,11 @@ public class GenericGcodeDriver extends LaserCutter {
   /**
    * Waits for the Identification line and returns null if it's allright
    * Otherwise it returns the wrong line
+   * @param pl Progress listener to update during connect process
    * @return
    * @throws IOException 
    */
-  protected String waitForIdentificationLine() throws IOException
+  protected String waitForIdentificationLine(ProgressListener pl) throws IOException
   {
     if (getIdentificationLine() != null && getIdentificationLine().length() > 0)
     {
@@ -591,7 +592,7 @@ public class GenericGcodeDriver extends LaserCutter {
             Thread.currentThread().interrupt();
           }
         }
-        if (waitForIdentificationLine() != null)
+        if (waitForIdentificationLine(pl) != null)
         {
           in.close();
           out.close();
@@ -637,7 +638,7 @@ public class GenericGcodeDriver extends LaserCutter {
       socket.connect(new InetSocketAddress(getHost(), 23), 1000);
       in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
       out = new PrintStream(socket.getOutputStream(), true, "US-ASCII");
-      String line = waitForIdentificationLine();
+      String line = waitForIdentificationLine(pl);
       if (line != null)
       {
         in.close();
diff --git a/src/com/t_oster/liblasercut/drivers/Grbl.java b/src/com/t_oster/liblasercut/drivers/Grbl.java
new file mode 100644
index 0000000000000000000000000000000000000000..10c1236d087c93adff2c0238802d4a0a2b424318
--- /dev/null
+++ b/src/com/t_oster/liblasercut/drivers/Grbl.java
@@ -0,0 +1,170 @@
+/**
+ * This file is part of LibLaserCut.
+ * Copyright (C) 2011 - 2014 Thomas Oster <mail@thomas-oster.de>
+ *
+ * LibLaserCut is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LibLaserCut is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LibLaserCut. If not, see <http://www.gnu.org/licenses/>.
+ *
+ **/
+package com.t_oster.liblasercut.drivers;
+
+import com.t_oster.liblasercut.ProgressListener;
+import com.t_oster.liblasercut.platform.Util;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class implements a driver for Grbl based firmwares.
+ * 
+ * @author Michael Adams <zap@michaeladams.org>
+ */
+public class Grbl extends GenericGcodeDriver
+{
+  public Grbl()
+  {
+    System.out.println("Running grbl constructor");
+    
+    //set some grbl-specific defaults
+    setLineend("CR");
+    setIdentificationLine("Grbl");
+    // Grbl uses "ok" flow control
+    setWaitForOKafterEachLine(true);
+    setPreJobGcode(getPreJobGcode()+",M3");
+    // turn off laser before returning to home position
+    setPostJobGcode("M5,"+getPostJobGcode());
+    // Grbl & MrBeam use 1000 for 100% PWM on the spindle/laser
+    setSpindleMax(1000.0f);
+    // Grbl doesn't turn off laser during G0 rapids
+    setBlankLaserDuringRapids(true);
+    // grbl can take a while to answer if doing a lot of slow moves
+    setSerialTimeout(30000);
+    
+    // blank these so that connect automatically uses serial first
+    setHttpUploadUrl(null);
+    setHost(null);
+  }
+  
+  protected static final String SETTING_AUTO_HOME = "Automatically home laser cutter";
+  
+  @Override
+  public String[] getPropertyKeys()
+  {
+    List<String> result = new LinkedList<String>();
+    result.addAll(Arrays.asList(super.getPropertyKeys()));
+    result.remove(GenericGcodeDriver.SETTING_HOST);
+    result.remove(GenericGcodeDriver.SETTING_HTTP_UPLOAD_URL);
+    result.remove(GenericGcodeDriver.SETTING_AUTOPLAY);
+    result.remove(GenericGcodeDriver.SETTING_IDENTIFICATION_STRING);
+    result.remove(GenericGcodeDriver.SETTING_WAIT_FOR_OK);
+    result.remove(GenericGcodeDriver.SETTING_TRAVEL_SPEED);
+    result.remove(GenericGcodeDriver.SETTING_LINEEND);
+    result.add(SETTING_AUTO_HOME);
+    return result.toArray(new String[0]);
+  }
+  
+  @Override
+  public Object getProperty(String attribute) {
+    if (SETTING_AUTO_HOME.equals(attribute)) {
+      return this.getAutoHome();
+    }
+    else {
+      return super.getProperty(attribute);
+    }
+  }
+  
+  @Override
+  public void setProperty(String attribute, Object value) {
+    if (SETTING_AUTO_HOME.equals(attribute)) {
+      this.setAutoHome((Boolean) value);
+    }
+    else {
+      super.setProperty(attribute, value);
+    }
+  }
+  
+  protected boolean autoHome = true;
+  
+  public boolean getAutoHome()
+  {
+    return autoHome;
+  }
+  
+  public void setAutoHome(boolean auto_home)
+  {
+    this.autoHome = auto_home;
+  }
+
+
+  @Override
+  public String getModelName()
+  {
+    return "Grbl Gcode Driver";
+  }
+  
+  protected void sendLineWithoutWait(String text, Object... parameters) throws IOException
+  {
+    boolean wasSetWaitingForOk = isWaitForOKafterEachLine();
+    setWaitForOKafterEachLine(false);
+    sendLine(text, parameters);
+    setWaitForOKafterEachLine(wasSetWaitingForOk);
+  }
+  
+  /**
+   * Initializes Grbl, handling issuing of soft-reset and initial homing
+   * (if desired & required).
+   * @param pl Progress listener to update during connect/homing process
+   * @return
+   * @throws IOException 
+   */
+  @Override
+  protected String waitForIdentificationLine(ProgressListener pl) throws IOException
+  {
+    // send reset character to Grbl to get it to print out its welcome message
+    pl.taskChanged(this, "Sending soft reset");
+    out.write(0x18);
+    
+    String error = super.waitForIdentificationLine(pl);
+    if (error != null) return error;
+    
+    // check if board is locked and if so home/unlock
+    if (in.ready() && waitForLine().equals("['$H'|'$X' to unlock]")) {
+      if (getAutoHome() == true) {
+        pl.taskChanged(this, "Homing");
+        sendLineWithoutWait("$H");
+        
+        // wait for "ok" or "[Caution: Unlocked]" followed by "ok"
+        String line = waitForLine();
+        if (!line.equals("ok"))
+          line = waitForLine();
+        if (!line.equals("ok"))
+          throw new IOException("Homing cycle failed to complete");
+      }
+      else {
+        throw new IOException("Grbl is locked");
+      }
+    }
+    
+    return null;
+  }
+
+  @Override
+  public Grbl clone()
+  {
+    Grbl clone = new Grbl();
+    clone.copyProperties(this);
+    return clone;
+  }
+}
diff --git a/src/com/t_oster/liblasercut/drivers/Marlin.java b/src/com/t_oster/liblasercut/drivers/Marlin.java
index c4238694530019563d29575ad181aa7a594aba35..ca62e1b910c131a4a0416bec7c0e28843bceaeec 100644
--- a/src/com/t_oster/liblasercut/drivers/Marlin.java
+++ b/src/com/t_oster/liblasercut/drivers/Marlin.java
@@ -18,6 +18,7 @@
  **/
 package com.t_oster.liblasercut.drivers;
 
+import com.t_oster.liblasercut.ProgressListener;
 import com.t_oster.liblasercut.drivers.GenericGcodeDriver;
 import java.io.IOException;
 import java.util.Arrays;
@@ -90,7 +91,7 @@ public class Marlin extends GenericGcodeDriver {
    * @throws IOException 
    */
  @Override
-  protected String waitForIdentificationLine() throws IOException
+  protected String waitForIdentificationLine(ProgressListener pl) throws IOException
   {
     if (getIdentificationLine() != null && getIdentificationLine().length() > 0)
     {