diff --git a/adaptors/julia/LICENSE.md b/adaptors/julia/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..84f75e85f4704402976a5ee9a963cbba84c7022f
--- /dev/null
+++ b/adaptors/julia/LICENSE.md
@@ -0,0 +1,23 @@
+MobergIO.jl is licensed under the MIT License:
+
+> Copyright (c) 2021: Anders Blomdell
+>
+> Permission is hereby granted, free of charge, to any person obtaining
+> a copy of this software and associated documentation files (the
+> "Software"), to deal in the Software without restriction, including
+> without limitation the rights to use, copy, modify, merge, publish,
+> distribute, sublicense, and/or sell copies of the Software, and to
+> permit persons to whom the Software is furnished to do so, subject to
+> the following conditions:
+>
+> The above copyright notice and this permission notice shall be
+> included in all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/adaptors/julia/Project.toml.template b/adaptors/julia/Project.toml
similarity index 50%
rename from adaptors/julia/Project.toml.template
rename to adaptors/julia/Project.toml
index 5876c36586a05c557ef3c11ac8ed7c078f68c717..a4b830b35f4fb1d97ab91421518862a62d987dd7 100644
--- a/adaptors/julia/Project.toml.template
+++ b/adaptors/julia/Project.toml
@@ -1,4 +1,13 @@
 name = "MobergIO"
 uuid = "9bdc2bb6-e40d-4944-bd5f-2bf890d3f651"
 authors = ["Anders Blomdell <anders.blomdell@control.lth.se>"]
-version = "<<<VERSION>>>"
+version = "1.0.0"
+
+[compat]
+julia = "1"
+
+[extras]
+Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
+[targets]
+test = ["Test"]
diff --git a/adaptors/julia/README.md b/adaptors/julia/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ec044609cff7b432a3d68f35f969b74d54d9ebad
--- /dev/null
+++ b/adaptors/julia/README.md
@@ -0,0 +1,5 @@
+# MobergIO.jl
+
+A library for connecting to various input/output libraries with a common interface.
+
+You need a local configuration and installation of Moberg for this package to work properly, see: [github.com/ControlLTH/moberg](https://github.com/ControlLTH/moberg).
diff --git a/adaptors/julia/AnalogIn.jl b/adaptors/julia/src/AnalogIn.jl
similarity index 73%
rename from adaptors/julia/AnalogIn.jl
rename to adaptors/julia/src/AnalogIn.jl
index d3a577f2154edb05f3e05662452b7e2403c03b31..a17030bb06a63f46684fe2cfe1b4f9306439e4c1 100644
--- a/adaptors/julia/AnalogIn.jl
+++ b/adaptors/julia/src/AnalogIn.jl
@@ -1,18 +1,13 @@
-mutable struct AnalogInChannel
-    context::Ptr{Nothing}
-    read::Ptr{Nothing}
-end
-
-mutable struct AnalogIn
+mutable struct AnalogIn <: AbstractMobergIn
     moberg::Ptr{Nothing}
     index::UInt32
-    channel::AnalogInChannel
+    channel::MobergInChannel
     function AnalogIn(moberg::Moberg, index::Unsigned)
-        channel = AnalogInChannel(0,0)
+        channel = MobergInChannel(0,0)
         moberg_handle = moberg.handle
         checkOK(ccall((:moberg_analog_in_open, "libmoberg"),
                        Status,
-                       (Ptr{Nothing}, Cint, Ref{AnalogInChannel}),
+                       (Ptr{Nothing}, Cint, Ref{MobergInChannel}),
                        moberg_handle, index, channel))
         self = new(moberg_handle, index, channel)
         finalizer(close, self)
@@ -24,7 +19,7 @@ function close(ain::AnalogIn)
     DEBUG && println("closing $(ain)")
     checkOK(ccall((:moberg_analog_in_close, "libmoberg"),
                   Status,
-                  (Ptr{Nothing}, Cint, AnalogInChannel),
+                  (Ptr{Nothing}, Cint, MobergInChannel),
                   ain.moberg, ain.index, ain.channel))
 end
 
diff --git a/adaptors/julia/AnalogOut.jl b/adaptors/julia/src/AnalogOut.jl
similarity index 74%
rename from adaptors/julia/AnalogOut.jl
rename to adaptors/julia/src/AnalogOut.jl
index 47ae229ae6661d2386c72d1e86ee110af2b1a1c7..9e2e853d92b5abc4fdd6034a664b417f585377a4 100644
--- a/adaptors/julia/AnalogOut.jl
+++ b/adaptors/julia/src/AnalogOut.jl
@@ -1,18 +1,13 @@
-mutable struct AnalogOutChannel
-    context::Ptr{Nothing}
-    write::Ptr{Nothing}
-end
-
-mutable struct AnalogOut
+mutable struct AnalogOut <: AbstractMobergOut
     moberg::Ptr{Nothing}
     index::UInt32
-    channel::AnalogOutChannel
+    channel::MobergOutChannel
     function AnalogOut(moberg::Moberg, index::Unsigned)
-        channel = AnalogOutChannel(0,0)
+        channel = MobergOutChannel(0,0)
         moberg_handle = moberg.handle
         checkOK(ccall((:moberg_analog_out_open, "libmoberg"),
                        Status,
-                       (Ptr{Nothing}, Cint, Ref{AnalogOutChannel}),
+                       (Ptr{Nothing}, Cint, Ref{MobergOutChannel}),
                        moberg_handle, index, channel));
         self = new(moberg_handle, index, channel)
         finalizer(close, self)
@@ -24,7 +19,7 @@ function close(aout::AnalogOut)
     DEBUG && println("closing $(aout)")
     checkOK(ccall((:moberg_analog_out_close, "libmoberg"),
                   Status,
-                  (Ptr{Nothing}, Cint, AnalogOutChannel),
+                  (Ptr{Nothing}, Cint, MobergOutChannel),
                   aout.moberg, aout.index, aout.channel))
 end
 
diff --git a/adaptors/julia/DigitalIn.jl b/adaptors/julia/src/DigitalIn.jl
similarity index 73%
rename from adaptors/julia/DigitalIn.jl
rename to adaptors/julia/src/DigitalIn.jl
index ba3f150db28cc1ffcc7d77782a64821f607f15e7..c396b6ebdeec5e04cee642d2366d5f6f8edeb8c4 100644
--- a/adaptors/julia/DigitalIn.jl
+++ b/adaptors/julia/src/DigitalIn.jl
@@ -1,18 +1,13 @@
-mutable struct DigitalInChannel
-    context::Ptr{Nothing}
-    read::Ptr{Nothing}
-end
-
-mutable struct DigitalIn
+mutable struct DigitalIn <: AbstractMobergIn
     moberg::Ptr{Nothing}
     index::UInt32
-    channel::DigitalInChannel
+    channel::MobergInChannel
     function DigitalIn(moberg::Moberg, index::Unsigned)
-        channel = DigitalInChannel(0,0)
+        channel = MobergInChannel(0,0)
         moberg_handle = moberg.handle
         checkOK(ccall((:moberg_digital_in_open, "libmoberg"),
                        Status,
-                       (Ptr{Nothing}, Cint, Ref{DigitalInChannel}),
+                       (Ptr{Nothing}, Cint, Ref{MobergInChannel}),
                        moberg_handle, index, channel));
         self = new(moberg_handle, index, channel)
         finalizer(close, self)
@@ -24,7 +19,7 @@ function close(din::DigitalIn)
     DEBUG && println("closing $(din)")
     checkOK(ccall((:moberg_digital_in_close, "libmoberg"),
                   Status,
-                  (Ptr{Nothing}, Cint, DigitalInChannel),
+                  (Ptr{Nothing}, Cint, MobergInChannel),
                   din.moberg, din.index, din.channel))
 end
 
diff --git a/adaptors/julia/DigitalOut.jl b/adaptors/julia/src/DigitalOut.jl
similarity index 74%
rename from adaptors/julia/DigitalOut.jl
rename to adaptors/julia/src/DigitalOut.jl
index b65cc1af963bdb243741012178294cf4b00f4801..4e2c4d26bed189d9d78308222a88232f9a5ef3d0 100644
--- a/adaptors/julia/DigitalOut.jl
+++ b/adaptors/julia/src/DigitalOut.jl
@@ -1,18 +1,13 @@
-mutable struct DigitalOutChannel
-    context::Ptr{Nothing}
-    write::Ptr{Nothing}
-end
-
-mutable struct DigitalOut
+mutable struct DigitalOut <: AbstractMobergOut
     moberg::Ptr{Nothing}
     index::UInt32
-    channel::DigitalOutChannel
+    channel::MobergOutChannel
     function DigitalOut(moberg::Moberg, index::Unsigned)
-        channel = DigitalOutChannel(0,0)
+        channel = MobergOutChannel(0,0)
         moberg_handle = moberg.handle
         checkOK(ccall((:moberg_digital_out_open, "libmoberg"),
                        Status,
-                       (Ptr{Nothing}, Cint, Ref{DigitalOutChannel}),
+                       (Ptr{Nothing}, Cint, Ref{MobergOutChannel}),
                        moberg_handle, index, channel))
         self = new(moberg_handle, index, channel)
         finalizer(close, self)
@@ -24,7 +19,7 @@ function close(dout::DigitalOut)
     DEBUG && println("closing $(dout)")
     checkOK(ccall((:moberg_digital_out_close, "libmoberg"),
                   Status,
-                  (Ptr{Nothing}, Cint, DigitalOutChannel),
+                  (Ptr{Nothing}, Cint, MobergOutChannel),
                   dout.moberg, dout.index, dout.channel))
 end
 
diff --git a/adaptors/julia/EncoderIn.jl b/adaptors/julia/src/EncoderIn.jl
similarity index 68%
rename from adaptors/julia/EncoderIn.jl
rename to adaptors/julia/src/EncoderIn.jl
index 58273f65a98d646805cc5bb266149d5f1f90a697..624ee1b1778cc7407e5912175368787f0fe087fb 100644
--- a/adaptors/julia/EncoderIn.jl
+++ b/adaptors/julia/src/EncoderIn.jl
@@ -1,18 +1,21 @@
-mutable struct EncoderInChannel
-    context::Ptr{Nothing}
-    read::Ptr{Nothing}
-end
+"""
+    encoder_in = EncoderIn(moberg::Moberg, index::Unsigned)
+
+Example usage:
 
-mutable struct EncoderIn
+    encoder_in = EncoderIn(m, UInt32(40))
+    result = read(encoder_in)
+"""
+mutable struct EncoderIn <: AbstractMobergIn
     moberg::Ptr{Nothing}
     index::UInt32
-    channel::EncoderInChannel
+    channel::MobergInChannel
     function EncoderIn(moberg::Moberg, index::Unsigned)
-        channel = EncoderInChannel(0,0)
+        channel = MobergInChannel(0,0)
         moberg_handle = moberg.handle
         checkOK(ccall((:moberg_encoder_in_open, "libmoberg"),
                        Status,
-                       (Ptr{Nothing}, Cint, Ref{EncoderInChannel}),
+                       (Ptr{Nothing}, Cint, Ref{MobergInChannel}),
                        moberg_handle, index, channel))
         self = new(moberg_handle, index, channel)
         finalizer(close, self)
@@ -24,7 +27,7 @@ function close(ein::EncoderIn)
     DEBUG && println("closing $(ein)")
     checkOK(ccall((:moberg_encoder_in_close, "libmoberg"),
                   Status,
-                  (Ptr{Nothing}, Cint, EncoderInChannel),
+                  (Ptr{Nothing}, Cint, MobergInChannel),
                   ein.moberg, ein.index, ein.channel))
 end
 
diff --git a/adaptors/julia/MobergIO.jl b/adaptors/julia/src/MobergIO.jl
similarity index 57%
rename from adaptors/julia/MobergIO.jl
rename to adaptors/julia/src/MobergIO.jl
index 7c917b8ffae880a03daf27da0c70282fe91f3fe2..82282a521c5eddcb7e344db7f7a046ecdf95b901 100644
--- a/adaptors/julia/MobergIO.jl
+++ b/adaptors/julia/src/MobergIO.jl
@@ -1,5 +1,25 @@
 module MobergIO
 
+export Moberg
+
+import Base: close, read, write
+
+abstract type AbstractMobergIO end
+abstract type AbstractMobergIn <: AbstractMobergIO end
+abstract type AbstractMobergOut <: AbstractMobergIO end
+
+"""
+    close(io::AbstractMobergIO)
+""" close
+
+"""
+    result = read(io::AbstractMobergIn)
+""" read
+
+"""
+    write(io::AbstractMobergIn)
+""" write
+
 const DEBUG = false
 
 struct Status
@@ -12,6 +32,16 @@ function checkOK(status::Status)
     end
 end
 
+mutable struct MobergOutChannel
+    context::Ptr{Nothing}
+    write::Ptr{Nothing}
+end
+
+mutable struct MobergInChannel
+    context::Ptr{Nothing}
+    read::Ptr{Nothing}
+end
+
 mutable struct Moberg
     handle::Ptr{Nothing}
 end
diff --git a/adaptors/julia/test/runtests.jl b/adaptors/julia/test/runtests.jl
new file mode 100644
index 0000000000000000000000000000000000000000..246b3295a71ef26eca6091e1974218bde9da7bac
--- /dev/null
+++ b/adaptors/julia/test/runtests.jl
@@ -0,0 +1,3 @@
+using Test
+
+@test 1 == 1
\ No newline at end of file
diff --git a/moberg.spec.template b/moberg.spec.template
index 5691bfc07b207c967f4ae86a85567c0172852188..26387a86dbd2b5a1f80d321f3ae98b4cdab890e5 100644
--- a/moberg.spec.template
+++ b/moberg.spec.template
@@ -139,10 +139,8 @@ cp adaptors/matlab/Makefile.mex ${RPM_BUILD_ROOT}/opt/matlab/src/moberg/Makefile
 
 # Julia
 mkdir -p ${RPM_BUILD_ROOT}/opt/julia/local/packages/MobergIO/src
-cp adaptors/julia/*.jl ${RPM_BUILD_ROOT}/opt/julia/local/packages/MobergIO/src
-cat adaptors/julia/Project.toml.template \
-| sed -e 's/<<<VERSION>>>/%{version}/' \
-> ${RPM_BUILD_ROOT}/opt/julia/local/packages/MobergIO/Project.toml
+cp adaptors/julia/src/*.jl ${RPM_BUILD_ROOT}/opt/julia/local/packages/MobergIO/src
+cp adaptors/julia/Project.toml ${RPM_BUILD_ROOT}/opt/julia/local/packages/MobergIO/Project.toml
 (
   cd ${RPM_BUILD_ROOT}/opt/julia/local/packages/MobergIO
   git init