diff --git a/nsfarm/board/_board.py b/nsfarm/board/_board.py
index 313789fb0730c5277e15e06304c61ac309976287..4ec3519c10b3728de119750a7356a7739a6c8441 100644
--- a/nsfarm/board/_board.py
+++ b/nsfarm/board/_board.py
@@ -26,10 +26,8 @@ class Board(abc.ABC):
         self.config = target_config
         # Open serial console to board
         self._serial = serial.Serial(self.config['serial'], 115200)
-        #self._fdlogging = cli.FDLogging(self._serial, logging.getLogger(f"{__package__}[{target}]"))
-        #self._pexpect = fdpexpect.fdspawn(self._fdlogging.socket())
-        self._pexpect = fdpexpect.fdspawn(self._serial)
-        self._pexpect.logfile_read = cli.PexpectLogging(logging.getLogger(f"{__package__}[{target}]"))
+        self._fdlogging = cli.FDLogging(self._serial, logging.getLogger(f"{__package__}[{target}]"))
+        self._pexpect = fdpexpect.fdspawn(self._fdlogging.socket)
         # Set board to some known state
         self.reset(True)  # Hold in reset state
 
diff --git a/nsfarm/cli.py b/nsfarm/cli.py
index b9f2c4754c4ae2cfbddba283d036f6abec68285f..4bfd9b350fb60cbe35ee3c13bdc5fe97c2af5ed0 100644
--- a/nsfarm/cli.py
+++ b/nsfarm/cli.py
@@ -14,6 +14,7 @@ import abc
 import logging
 import base64
 import fcntl
+import select
 import socket
 import threading
 import typing
@@ -207,77 +208,78 @@ class FDLogging:
     """
     _EXPECTED_EOL = b'\n\r'
 
-    def __init__(self, fd, logger, in_level=logging.INFO, out_level=logging.DEBUG):
-        self.logger = logger
-        self.in_level = in_level
-        self.out_level = out_level
-        self.fileno = fd.fileno()
-        self.our_sock, self.user_sock = socket.socketpair()
-
-        # Input
-        self.inputthread = threading.Thread(target=self._input, daemon=True)
-        self.inputthread.start()
-        # Output
-        self.outputthread = threading.Thread(target=self._output, daemon=True)
-        self.outputthread.start()
+    def __init__(self, fileno, logger, in_level=logging.INFO, out_level=logging.DEBUG):
+        self._logger = logger
+        self._in_level = in_level
+        self._out_level = out_level
+        self._fileno = fileno if isinstance(fileno, int) else fileno.fileno()
+        self._our_sock, self._user_sock = socket.socketpair()
+
+        self._orig_filestatus = fcntl.fcntl(self._fileno, fcntl.F_GETFL)
+        fcntl.fcntl(self._fileno, fcntl.F_SETFL, self._orig_filestatus | os.O_NONBLOCK)
+        self._our_sock.setblocking(False)
 
+        self._thread = threading.Thread(target=self._thread_func, daemon=True)
+        self._thread.start()
+
+    @property
     def socket(self):
         """Returns socket for user to use to communicate trough this logged passtrough.
         """
-        return self.user_sock
+        return self._user_sock
 
     def close(self):
         """Close socket and stop logging.
         """
-        if self.our_sock is not None:
-            # Terminates and cleans _input
-            _orig_filestatus = fcntl.fcntl(self.fileno, fcntl.F_GETFL)
-            fcntl.fcntl(self.fileno, fcntl.F_SETFL, _orig_filestatus | os.O_NONBLOCK)
-            self.inputthread.join()
-            fcntl.fcntl(self.fileno, fcntl.F_SETFL, _orig_filestatus)
-            # Terminates and cleans _output
-            self.our_sock.close()
-            self.outputthread.join()
-            self.our_sock = None
+        if self._our_sock is None:
+            return
+        self._our_sock.close()
+        self._our_sock = None
+        self._thread.join()
+        fcntl.fcntl(self._fileno, fcntl.F_SETFL, self._orig_filestatus)
 
     def __del__(self):
         self.close()
 
     def _log_line(self, line, level):
-        self.logger.log(level, repr(line.rstrip(self._EXPECTED_EOL).expandtabs())[2:-1])
+        self._logger.log(level, repr(line.rstrip(self._EXPECTED_EOL).expandtabs())[2:-1])
 
     def _log(self, prev_data, new_data, level):
         data = prev_data + new_data
         lines = data.splitlines(keepends=True)
         if not lines:
-            return
+            return data
         # The last line does not have to be terminated (no new line character) so just preserve it
-        reminder = lines.pop() if lines[-1] or lines[-1][-1] not in self._EXPECTED_EOL else b''
+        reminder = lines.pop() if lines[-1] and lines[-1][-1] not in self._EXPECTED_EOL else b''
         for line in lines:
             self._log_line(line, level)
         return reminder
 
-    def _input(self):
-        data = b''
-        while True:
-            try:
-                new_data = os.read(self.fileno, io.DEFAULT_BUFFER_SIZE)
-            except io.BlockingIOError:
-                self._log_line(data, self.in_level)
-                return
-            self.our_sock.sendall(new_data)
-            data = self._log(data, new_data, self.in_level)
-
-    def _output(self):
-        data = b''
+    def _thread_func(self):
+        data = {
+            self._fileno: b'',
+            self._our_sock.fileno(): b'',
+        }
+        level = {
+            self._fileno: self._in_level,
+            self._our_sock.fileno(): self._out_level,
+        }
+        output = {
+            self._fileno: self._our_sock.fileno(),
+            self._our_sock.fileno(): self._fileno,
+        }
+
+        poll = select.poll()
+        poll.register(self._fileno, select.POLLIN)
+        poll.register(self._our_sock.fileno(), select.POLLIN | select.POLLNVAL)
         while True:
-            try:
-                new_data = self.our_sock.recv(io.DEFAULT_BUFFER_SIZE)
-            except io.BlockingIOError:
-                self._log_line(data, self.out_level)
-                return
-            os.write(self.fileno, new_data)
-            data = self._log(data, new_data, self.out_level)
+            for poll_event in poll.poll():
+                fileno, event = poll_event
+                if event == select.POLLNVAL:
+                    return
+                new_data = os.read(fileno, io.DEFAULT_BUFFER_SIZE)
+                os.write(output[fileno], new_data)
+                data[fileno] = self._log(data[fileno], new_data, level[fileno])
 
 
 class PexpectLogging:
@@ -288,7 +290,7 @@ class PexpectLogging:
     _EXPECTED_EOL = b'\n\r'
 
     def __init__(self, logger):
-        self._level = logging.DEBUG
+        self._level = logging.INFO
         self.logger = logger
         self.linebuf = b''