diff --git a/apex.gemspec b/apex.gemspec
index 576235ceec3e3ddf81529cc051c6df66a6586053..ba05c0330b20828fd09419f4eedf4cbbbac0cb4f 100644
--- a/apex.gemspec
+++ b/apex.gemspec
@@ -35,5 +35,6 @@ Gem::Specification.new do |spec|
   spec.add_development_dependency 'rake', '~> 11.3.0'
   spec.add_development_dependency 'rdoc'
   spec.add_development_dependency 'aruba'
+  spec.add_development_dependency 'serialport'
   spec.add_dependency 'methadone'
 end
diff --git a/lib/kiss/kiss_abstract.rb b/lib/kiss/kiss_abstract.rb
index 5528c1d897f49f9366145db9fe76c24db5ccb566..7ba7917d9e8c111d9e243fc4d0826b95bbdafa21 100644
--- a/lib/kiss/kiss_abstract.rb
+++ b/lib/kiss/kiss_abstract.rb
@@ -3,13 +3,12 @@ require 'abstraction'
 require_relative 'constants'
 
 module KISS
-    class KISS
+    class KISSAbstract
         abstract
 
         protected
-        def initialize(strip_df_start=true, exit_kiss=true)
+        def initialize(strip_df_start=true)
             @strip_df_start = strip_df_start
-            @exit_kiss = exit_kiss
             @frame_buffer = []
             @lock = Mutex.new
         end
@@ -25,7 +24,7 @@ module KISS
             while frame[-1]&.chr == ' '
                 frame.pop
             end
-            return frame
+            frame
         end
 
         private
@@ -40,7 +39,7 @@ module KISS
                     encoded_bytes += [raw_code_byte]
                 end
             end
-            return encoded_bytes
+            encoded_bytes
         end
 
         private
@@ -50,12 +49,12 @@ module KISS
             elsif command_code > 127 or command_code < 0
                 raise 'command_Code out of range'
             end
-            return (port << 4) & command_code
+            (port << 4) & command_code
         end
 
         protected
         def write_setting(command, value)
-            return self.write_interface(
+            write_interface(
                 [FEND] +
                 [command] +
                 escape_special_codes(value) +
@@ -114,7 +113,7 @@ module KISS
             new_frames.each do |new_frame|
                 if new_frame.length > 0 and new_frame[0] == 0
                     if @strip_df_start
-                        new_frame = KISS.strip_df_start(new_frame)
+                        new_frame = KISSAbstract.strip_df_start(new_frame)
                     end
                     @frame_buffer << new_frame
                 end
@@ -127,9 +126,6 @@ module KISS
 
         public
         def close
-            if @exit_kiss
-                write_interface(MODE_END)
-            end
         end
 
         public
@@ -152,10 +148,10 @@ module KISS
         public
         def write(frame_bytes, port=0)
             @lock.synchronize do
-                kiss_packet = [FEND] + [KISS.command_byte_combine(port, DATA_FRAME)] +
-                    KISS.escape_special_codes(frame_bytes) + [FEND]
+                kiss_packet = [FEND] + [KISSAbstract.command_byte_combine(port, DATA_FRAME)] +
+                    KISSAbstract.escape_special_codes(frame_bytes) + [FEND]
 
-                return write_interface(kiss_packet)
+                write_interface(kiss_packet)
             end
         end
     end
diff --git a/lib/kiss/kiss_serial.rb b/lib/kiss/kiss_serial.rb
new file mode 100644
index 0000000000000000000000000000000000000000..76f43922181d4a326fa4dd7c4a7bbde0e7be6ed4
--- /dev/null
+++ b/lib/kiss/kiss_serial.rb
@@ -0,0 +1,75 @@
+require 'serialport'
+require_relative 'kiss_abstract'
+
+module KISS
+    class KISSSerial < KISSAbstract
+
+        DEFAULT_READ_BYTES = 1000
+        SERIAL_READ_TIMEOUT = -1
+        SERIAL_WRITE_TIMEOUT = 1000
+
+        protected
+        def initialize(com_port,
+                       baud=38400,
+                       parity=SerialPort::NONE,
+                       stop_bits=1,
+                       byte_size=8,
+                       read_bytes=DEFAULT_READ_BYTES,
+                       strip_df_start=true)
+            super(strip_df_start)
+            @com_port = com_port
+            @baud = baud
+            @parity = parity
+            @stop_bits = stop_bits
+            @byte_size = byte_size
+            @read_bytes = read_bytes
+            @serial = nil
+            @exit_kiss = false
+        end
+
+        protected
+        def read_interface
+            read_data = @serial.read(@read_bytes)
+            read_data.map { |c| ord(c) }
+        end
+
+        protected
+        def write_interface(data)
+            @serial.write(data)
+        end
+
+        public
+        def connect(mode_init=nil, **kwargs)
+            @serial = SerialPort.new(@com_port, @baud, @byte_size, @stop_bits, @parity)
+            @serial.read_timeout = SERIAL_READ_TIMEOUT
+            @serial.write_timeout = SERIAL_WRITE_TIMEOUT
+
+            if mode_init
+                @serial.write(mode_init)
+                @exit_kiss = true
+            else
+                @exit_kiss = false
+            end
+
+            # Previous verious defaulted to Xastir-friendly configs. Unfortunately
+            # those don't work with Bluetooth TNCs, so we're reverting to None.
+            kwargs&.each do |name,value|
+                write_setting(name, value)
+            end
+        end
+
+        public
+        def close
+            super
+            if @exit_kiss
+                write_interface(MODE_END)
+            end
+
+            if @serial == nil or @serial&.closed?
+                raise 'Attempting to close before the class has been started.'
+            else
+                @serial.close
+            end
+        end
+    end
+end
\ No newline at end of file
diff --git a/test/tc_kiss.rb b/test/tc_kiss.rb
index 57d29e8d900b4693038a50e147653dc0be52a580..329bccb9f13ec63bd4ed9218ef218549089f9fe1 100644
--- a/test/tc_kiss.rb
+++ b/test/tc_kiss.rb
@@ -12,7 +12,7 @@ module KISS
                      88, 45, 47, 107, 103, 54, 119, 116, 102, 64, 103, 111, 115, 115, 101, 108, 105, 110, 102, 97, 109,
                      105, 108, 121, 46, 99, 111, 109]
     
-    class KISSMock < KISS
+    class KISSMock < KISSAbstract
         
         def initialize(strip_df_start=true)
             super(strip_df_start)
@@ -66,7 +66,7 @@ module KISS
         end
 
         def test_new_abstract_kiss
-            assert_raise(AbstractClassError) { KISS.new }
+            assert_raise(AbstractClassError) { KISSAbstract.new }
         end
     end
 end
\ No newline at end of file