diff --git a/red/src/printer/mod.rs b/red/src/printer/mod.rs
index 2173ffb..30946ea 100644
--- a/red/src/printer/mod.rs
+++ b/red/src/printer/mod.rs
@@ -1,5 +1,4 @@
 pub mod gcode;
-use futures::AsyncWriteExt;
 use lazy_static::lazy_static;
 
 use core::panic;
@@ -28,7 +27,7 @@ use self::gcode::{G0Command, G28Command, G90Command, GcodeReplyError};
 /// Recv buffer string will be initialized with this capacity.
 /// This should fit a simple "OK Pnn Bn" reply for GCODE commands that
 /// do not return any data.
-const RECV_BUFFER_CAPACITY: usize = 32;
+const BUF_SIZE_READ_LINE: usize = 1024;
 const BAUD_RATE: u32 = 115200;
 
 const DEFAULT_COMMAND_TIMEOUT: Duration = Duration::from_secs(2);
@@ -70,6 +69,7 @@ pub enum MovementMode {
     RelativeMovements,
 }
 
+#[derive(Debug, Clone)]
 pub struct State {
     pub position: PrinterPosition,
     pub movement_mode: MovementMode,
@@ -174,8 +174,8 @@ impl Printer {
         Ok(res)
     }
 
-    pub fn printer_state(&self) -> &State {
-        &self.state.lock().unwrap().deref().clone()
+    pub fn printer_state(&self) -> State {
+        self.state.lock().unwrap().deref().clone()
     }
 
     /// The maximum capacity of the machines GCODE buffer.
@@ -209,7 +209,7 @@ impl Printer {
 
     /// Update the internal position by asking the printer for it
     fn update_position(&mut self) -> Result<PrinterPosition, PrinterError> {
-        let res = self.send_gcode(M114Command, false, DEFAULT_COMMAND_TIMEOUT)?;
+        let res = self.send_gcode(M114Command)?;
         self.state.lock().unwrap().deref_mut().position = res;
         Ok(res)
     }
@@ -222,7 +222,7 @@ impl Printer {
     /// itself. (See its documentation)
     pub fn use_absolute_movements(&mut self) -> Result<(), PrinterError> {
         self.state.lock().unwrap().deref_mut().movement_mode = MovementMode::AbsoluteMovements;
-        self.send_gcode(G90Command, true, DEFAULT_COMMAND_TIMEOUT)
+        self.send_gcode(G90Command)
     }
 
     /// Switch the printer to relative movement mode.
@@ -233,16 +233,16 @@ impl Printer {
     /// itself. (See its documentation)
     pub fn use_relative_movements(&mut self) -> Result<(), PrinterError> {
         self.state.lock().unwrap().deref_mut().movement_mode = MovementMode::RelativeMovements;
-        self.send_gcode(G91Command, true, DEFAULT_COMMAND_TIMEOUT)
+        self.send_gcode(G91Command)
     }
 
     /// Home the printer using the hardware endstops
     ///
     /// # Arguments
     /// * `x, y, z` - Whether the axis should be homed. Axis that are set to `false` will not be
-    /// homed.,
+    ///   homed.
     pub fn auto_home(&mut self, x: bool, y: bool, z: bool) -> Result<(), PrinterError> {
-        self.send_gcode(G28Command::new(x, y, z), true, DEFAULT_COMMAND_TIMEOUT)?;
+        self.send_gcode(G28Command::new(x, y, z))?;
         self.state.lock().unwrap().deref_mut().position = PrinterPosition {
             x: 0.0,
             y: 0.0,
@@ -366,7 +366,8 @@ fn handle_printer_autoreport(port: &mut TTYPort, state: Arc<Mutex<State>>) {
 ///
 /// Parameters
 /// * `port` - The port to read from
-/// * `already_read` - Read bytes from a previous call. May not contain `\n`
+/// * `already_read` - Read bytes from a previous call. May not contain `\n`.
+///   On a successful read, the buffer will be cleared and then filled with the new residual bytes
 /// * `timeout` - Time to wait for new bytes from the `port` before raising a timeout error
 ///
 /// Returns
@@ -378,10 +379,11 @@ fn read_line(
     port: &mut TTYPort,
     already_read: &mut Vec<u8>,
     timeout: Duration,
-) -> io::Result<Option<Vec<u8>>> {
+) -> io::Result<Vec<u8>> {
     let deadline = Instant::now() + timeout;
+    let mut buf = [0; BUF_SIZE_READ_LINE];
     while Instant::now() < deadline {
-        match port.read(already_read) {
+        match port.read(&mut buf) {
             Err(e) => {
                 if let io::ErrorKind::TimedOut = e.kind() {
                     continue;
@@ -391,9 +393,14 @@ fn read_line(
             }
             Ok(0) => panic!("TTYPort returned 0 bytes!"),
             Ok(n) => {
+                already_read.extend_from_slice(&buf[..n]);
                 if let Some(line_break_idx) = already_read[..n].iter().position(|x| *x == b'\n') {
-                    return Ok(Some(already_read[..line_break_idx].into()));
+                    let res = Ok(already_read[..line_break_idx].into());
+                    *already_read = already_read[line_break_idx..].into();
+                    return res;
                 }
+
+                std::thread::sleep(Duration::from_millis(5));
             }
         }
     }
@@ -409,29 +416,21 @@ fn handle_user_command(
     state: Arc<Mutex<State>>,
     to_user_thread: Sender<Vec<u8>>,
 ) {
-    port.write(user_command.as_bytes())
+    // TODO: Add timeout?
+    port.write_all(user_command.as_bytes())
         .expect("Failed to write to printer serial port");
     port.flush().unwrap();
 
     let mut already_read_lines = Vec::new();
     let mut rest = Vec::new();
     loop {
-        let mut line;
-        loop {
-            line = read_line(port, &mut rest, DEFAULT_COMMAND_TIMEOUT)
-                .expect("Failed to read from printer");
-            if line.is_some() {
-                break;
-            } else {
-                std::thread::sleep(Duration::from_millis(5));
-            }
-        }
-        let line = line.expect("Line must be set as otherwise we don't leave the loop");
+        let line = read_line(port, &mut rest, DEFAULT_COMMAND_TIMEOUT)
+            .expect("Failed to read from printer");
 
         let str_line = String::from_utf8(line.clone()).expect("Read line was no valid utf8");
 
         if str_line.starts_with("ok") {
-            (*state.lock().unwrap()).last_buffer_capacity =
+            state.lock().unwrap().last_buffer_capacity =
                 Printer::parse_ok(&str_line).expect("Couldn't parse line as 'ok'-message");
             to_user_thread
                 .send(already_read_lines.join(&b'\n'))