threaded: add write_line() to LineReader, doc update

also update corresponding example
diff --git a/examples/at_protocol.py b/examples/at_protocol.py
index faa00bc..d9e881b 100644
--- a/examples/at_protocol.py
+++ b/examples/at_protocol.py
@@ -41,10 +41,6 @@
         self._event_thread.start()
         self.lock = threading.Lock()
 
-    def connection_made(self, transport):
-        super(ATProtocol, self).connection_made(transport)
-        self.transport = transport
-
     def stop(self):
         """
         Stop the event processing thread, abort pending commands, if any.
@@ -84,7 +80,7 @@
         Set an AT command and wait for the response.
         """
         with self.lock:  # ensure that just one thread is sending commands at once
-            self.transport.write(b'%s\r\n' % (command.encode(self.ENCODING, self.UNICODE_HANDLING),))
+            self.write_line(command)
             lines = []
             while True:
                 try:
@@ -100,13 +96,12 @@
 
 # test
 if __name__ == '__main__':
-    import sys
     import time
 
     class PAN1322(ATProtocol):
         """
         Example communication with PAN1322 BT module.
-        
+
         Some commands do not respond with OK but with a '+...' line. This is
         implemented via command_with_event_response and handle_event, because
         '+...' lines are also used for real events.
@@ -131,7 +126,7 @@
                 mac = ':'.join('%02X' % ord(x) for x in rev.decode('hex')[::-1])
                 self.event_responses.put(mac)
             else:
-                log.warning('unhandled event: %r' % event)
+                logging.warning('unhandled event: %r' % event)
 
         def command_with_event_response(self, command):
             """Send a command that responds with '+...' line"""
@@ -151,7 +146,6 @@
             # requests hardware / calibrationinfo as event
             return self.command_with_event_response("AT+JRBD")
 
-
     ser = serial.serial_for_url('spy://COM1', baudrate=115200, timeout=1)
     #~ ser = serial.Serial('COM1', baudrate=115200, timeout=1)
     with serial.threaded.SerialPortWorker(ser, PAN1322) as bt_module:
diff --git a/serial/threaded/__init__.py b/serial/threaded/__init__.py
index fac007f..b100115 100644
--- a/serial/threaded/__init__.py
+++ b/serial/threaded/__init__.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Working with thrading and pySerial
+# Working with threading and pySerial
 #
 # (C) 2015 Chris Liechti <cliechti@gmx.net>
 #
@@ -33,7 +33,12 @@
 
 
 class Packetizer(Protocol):
-    """read binary packets from serial port"""
+    """
+    Read binary packets from serial port. Packets are expected to be terminates
+    with a TERMINATOR byte (null byte by default).
+
+    The class also keeps track of the transport.
+    """
 
     TERMINATOR = b'\0'
 
@@ -42,52 +47,68 @@
         self.transport = None
 
     def connection_made(self, transport):
+        """Store transport"""
         self.transport = transport
 
     def connection_lost(self, exc):
+        """Forget transport"""
         self.transport = None
 
     def data_received(self, data):
+        """Buffer received data, find TERMINATOR, call handle_packet"""
         self.buffer.extend(data)
         while self.TERMINATOR in self.buffer:
             packet, self.buffer = self.buffer.split(self.TERMINATOR)
             self.handle_packet(packet)
 
     def handle_packet(self, packet):
-        """Process packets - to be overriden by subclassing"""
+        """Process packets - to be overridden by subclassing"""
         raise NotImplementedError('please implement functionality in handle_packet')
 
 
 class LineReader(Packetizer):
-    """read (unicode) lines from serial port. the encoding is applied"""
+    """
+    Read and write (Unicode) lines from/to serial port.
+    The encoding is applied.
+    """
 
-    TERMINATOR = b'\n'
+    TERMINATOR = b'\r\n'
     ENCODING = 'utf-8'
     UNICODE_HANDLING = 'replace'
 
     def handle_packet(self, packet):
-        self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING).rstrip())
+        self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING))
 
     def handle_line(self, line):
-        """Process one line - to be overriden by subclassing"""
+        """Process one line - to be overridden by subclassing"""
         raise NotImplementedError('please implement functionality in handle_line')
 
+    def write_line(self, text):
+        """
+        Write text to the transport. ``text`` is a Unicode string and the encoding
+        is applied before sending ans also the newline is append.
+        """
+        # + is not the best choice but bytes does not support % or .format in py3 and we want a single write call
+        self.transport.write(text.encode(self.ENCODING, self.UNICODE_HANDLING) + self.TERMINATOR)
+
 
 class SerialPortWorker(threading.Thread):
     """\
     Implement a serial port read loop and dispatch to a Protocol instance (like
-    the asyncio.Procotol) but do it with threads.
+    the asyncio.Protocol) but do it with threads.
 
-    Calls to close() will close the serial port but its also possible to just
+    Calls to close() will close the serial port but it is also possible to just
     stop() this thread and continue the serial port instance otherwise.
     """
 
     def __init__(self, serial_instance, protocol_factory, use_logging=True):
         """\
         Initialize thread.
-        Note that the serial_instance' timeout is set to one second!
 
-        When use_logging, log messages are printed on exceptions.
+        Note that the serial_instance' timeout is set to one second!
+        Other settings are not changed.
+
+        When use_logging is true, log messages are printed on exceptions.
         """
         super(SerialPortWorker, self).__init__()
         self.daemon = True
@@ -95,11 +116,12 @@
         self.protocol_factory = protocol_factory
         self.use_logging = use_logging
         self.alive = True
-        self.lock = threading.Lock()
+        self._lock = threading.Lock()
         self._connection_made = threading.Event()
         self.protocol = None
 
     def stop(self):
+        """Stop the reader thread"""
         self.alive = False
         self.join(2)
 
@@ -114,14 +136,14 @@
                 # read all that is there or wait for one byte (blocking)
                 data = self.serial.read(self.serial.in_waiting or 1)
             except serial.SerialException:
-                # probably some IO problem such as disconnected USB serial
+                # probably some I/O problem such as disconnected USB serial
                 # adapters -> exit
                 self.alive = False
                 if self.use_logging:
                     logging.exception('Error in %s (thread stops):', self.name)
             else:
                 if data:
-                    # make a separated try-except for user called code
+                    # make a separated try-except for called used code
                     try:
                         self.protocol.data_received(data)
                     except:
@@ -132,13 +154,13 @@
 
     def write(self, data):
         """Thread safe writing (uses lock)"""
-        with self.lock:
+        with self._lock:
             self.serial.write(data)
 
     def close(self):
         """Close the serial port and exit reader thread (uses lock)"""
         # use the lock to let other threads finish writing
-        with self.lock:
+        with self._lock:
             # first stop reading, so that closing can be done on idle port
             self.stop()
             self.serial.close()
@@ -163,7 +185,7 @@
 
     def __exit__(self, *args, **kwargs):
         self.close()
-        
+
 
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 # test