created LimitEncoderReader
diff --git a/aos/common/libstdc++/README b/aos/common/libstdc++/README
new file mode 100644
index 0000000..df8269e
--- /dev/null
+++ b/aos/common/libstdc++/README
@@ -0,0 +1,3 @@
+This directory contains replacement include files for ones that the libstdc++ we're using on the cRIO either don't implement completely or doesn't have at all.
+The ones in aos/crio/libstdc++ are copied from the libstdc++ that came with the compiler and tweaked so that they work.
+When used for compiles not for vxworks, they just #include the usual standard library header.
diff --git a/aos/common/libstdc++/memory b/aos/common/libstdc++/memory
new file mode 100644
index 0000000..31ab6e9
--- /dev/null
+++ b/aos/common/libstdc++/memory
@@ -0,0 +1,4 @@
+#include <memory>
+#ifdef __VXWORKS__
+#include "aos/crio/libstdc++/unique_ptr.h"
+#endif
diff --git a/aos/common/libstdc++/utility b/aos/common/libstdc++/utility
new file mode 100644
index 0000000..50b8aa3
--- /dev/null
+++ b/aos/common/libstdc++/utility
@@ -0,0 +1,4 @@
+#include <utility>
+#ifdef __VXWORKS__
+#include "aos/crio/libstdc++/move.h"
+#endif
diff --git a/aos/common/zero_switch_value.h b/aos/common/zero_switch_value.h
new file mode 100644
index 0000000..fa8609d
--- /dev/null
+++ b/aos/common/zero_switch_value.h
@@ -0,0 +1,32 @@
+#ifndef AOS_COMMON_ZERO_SWITCH_VALUE_H_
+#define AOS_COMMON_ZERO_SWITCH_VALUE_H_
+
+#include "aos/common/type_traits.h"
+#include "aos/common/byteorder.h"
+
+namespace aos {
+
+// Contains all of the information from a zeroing sensor of some kind.
+// It is all contained here because it all has to be retrieved at the same time
+// or else there are race conditions with the sensor triggering and retrieving
+// the encoder values that would make writing code to deal with the information
+// hard (ie if the trigger sensor is read, then it changes->triggers the
+// interrupt which reads the encoder value).
+struct ZeroSwitchValue {
+ // What the curent encoder value is.
+ int32_t current_encoder;
+ // What the value of the encoder was when the interrupt triggered.
+ int32_t edge_encoder;
+ // What the current value of the sensor is.
+ bool current_value;
+
+ void NetworkToHost() {
+ current_encoder = ntoh(current_encoder);
+ edge_encoder = ntoh(edge_encoder);
+ }
+};
+static_assert(shm_ok<ZeroSwitchValue>::value, "it's getting sent over the wire");
+
+} // namespace aos
+
+#endif // AOS_COMMON_ZERO_SWITCH_VALUE_H_
diff --git a/aos/crio/libstdc++/move.h b/aos/crio/libstdc++/move.h
new file mode 100644
index 0000000..425fcb6
--- /dev/null
+++ b/aos/crio/libstdc++/move.h
@@ -0,0 +1,117 @@
+// Move, forward and identity for C++0x + swap -*- C++ -*-
+
+// Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file move.h
+ * This is an internal header file, included by other library headers.
+ * You should not attempt to use it directly.
+ */
+
+#ifndef _MOVE_H
+#define _MOVE_H 1
+
+#include "aos/crio/type_traits/type_traits"
+
+namespace std {
+
+ /// identity
+ template<typename _Tp>
+ struct identity
+ {
+ typedef _Tp type;
+ };
+
+ /// forward (as per N2835)
+ /// Forward lvalues as rvalues.
+ template<typename _Tp>
+ inline typename enable_if<!is_lvalue_reference<_Tp>::value, _Tp&&>::type
+ forward(typename std::identity<_Tp>::type& __t)
+ { return static_cast<_Tp&&>(__t); }
+
+ /// Forward rvalues as rvalues.
+ template<typename _Tp>
+ inline typename enable_if<!is_lvalue_reference<_Tp>::value, _Tp&&>::type
+ forward(typename std::identity<_Tp>::type&& __t)
+ { return static_cast<_Tp&&>(__t); }
+
+ // Forward lvalues as lvalues.
+ template<typename _Tp>
+ inline typename enable_if<is_lvalue_reference<_Tp>::value, _Tp>::type
+ forward(typename std::identity<_Tp>::type __t)
+ { return __t; }
+
+ // Prevent forwarding rvalues as const lvalues.
+ template<typename _Tp>
+ inline typename enable_if<is_lvalue_reference<_Tp>::value, _Tp>::type
+ forward(typename std::remove_reference<_Tp>::type&& __t) = delete;
+
+ /**
+ * @brief Move a value.
+ * @ingroup mutating_algorithms
+ * @param __t A thing of arbitrary type.
+ * @return Same, moved.
+ */
+ template<typename _Tp>
+ inline typename std::remove_reference<_Tp>::type&&
+ move(_Tp&& __t)
+ { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
+
+ /// declval, from type_traits.
+
+#define _GLIBCXX_MOVE(_Tp) std::move(_Tp)
+#define _GLIBCXX_FORWARD(_Tp, __val) std::forward<_Tp>(__val)
+
+#if 0
+ /**
+ * @brief Swaps two values.
+ * @ingroup mutating_algorithms
+ * @param __a A thing of arbitrary type.
+ * @param __b Another thing of arbitrary type.
+ * @return Nothing.
+ */
+ template<typename _Tp>
+ inline void
+ swap(_Tp& __a, _Tp& __b)
+ {
+ // concept requirements
+ __glibcxx_function_requires(_SGIAssignableConcept<_Tp>)
+
+ _Tp __tmp = _GLIBCXX_MOVE(__a);
+ __a = _GLIBCXX_MOVE(__b);
+ __b = _GLIBCXX_MOVE(__tmp);
+ }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // DR 809. std::swap should be overloaded for array types.
+ template<typename _Tp, size_t _Nm>
+ inline void
+ swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
+ {
+ for (size_t __n = 0; __n < _Nm; ++__n)
+ swap(__a[__n], __b[__n]);
+ }
+#endif
+
+} // namespace std
+
+#endif /* _MOVE_H */
diff --git a/aos/crio/libstdc++/unique_ptr.h b/aos/crio/libstdc++/unique_ptr.h
new file mode 100644
index 0000000..f6bda76d
--- /dev/null
+++ b/aos/crio/libstdc++/unique_ptr.h
@@ -0,0 +1,419 @@
+// unique_ptr implementation -*- C++ -*-
+
+// Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file unique_ptr.h
+ * This is an internal header file, included by other library headers.
+ * You should not attempt to use it directly.
+ */
+
+#ifndef _UNIQUE_PTR_H
+#define _UNIQUE_PTR_H 1
+
+#include "aos/crio/type_traits/type_traits"
+#include "aos/common/libstdc++/utility"
+#include <assert.h>
+
+namespace std {
+
+ /**
+ * @addtogroup pointer_abstractions
+ * @{
+ */
+
+ /// Primary template, default_delete.
+ template<typename _Tp>
+ struct default_delete
+ {
+ default_delete() { }
+
+ template<typename _Up>
+ default_delete(const default_delete<_Up>&) { }
+
+ void
+ operator()(_Tp* __ptr) const
+ {
+ static_assert(sizeof(_Tp)>0,
+ "can't delete pointer to incomplete type");
+ delete __ptr;
+ }
+ };
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // DR 740 - omit specialization for array objects with a compile time length
+ /// Specialization, default_delete.
+ template<typename _Tp>
+ struct default_delete<_Tp[]>
+ {
+ void
+ operator()(_Tp* __ptr) const
+ {
+ static_assert(sizeof(_Tp)>0,
+ "can't delete pointer to incomplete type");
+ delete [] __ptr;
+ }
+ };
+
+ /// 20.7.12.2 unique_ptr for single objects.
+ template <typename _Tp, typename _Tp_Deleter = default_delete<_Tp> >
+ class unique_ptr
+ {
+ typedef _Tp* unique_ptr::* __unspecified_pointer_type;
+
+ public:
+ typedef _Tp* pointer;
+ typedef _Tp element_type;
+ typedef _Tp_Deleter deleter_type;
+
+ // Constructors.
+ unique_ptr()
+ : _t(pointer()), _deleter(deleter_type())
+ { static_assert(!std::is_pointer<deleter_type>::value,
+ "constructed with null function pointer deleter"); }
+
+ explicit
+ unique_ptr(pointer __p)
+ : _t(__p), _deleter(deleter_type())
+ { static_assert(!std::is_pointer<deleter_type>::value,
+ "constructed with null function pointer deleter"); }
+
+ unique_ptr(pointer __p,
+ typename std::conditional<std::is_reference<deleter_type>::value,
+ deleter_type, const deleter_type&>::type __d)
+ : _t(__p), _deleter(__d) { }
+
+ unique_ptr(pointer __p,
+ typename std::remove_reference<deleter_type>::type&& __d)
+ : _t(std::move(__p)), _deleter(std::move(__d))
+ { static_assert(!std::is_reference<deleter_type>::value,
+ "rvalue deleter bound to reference"); }
+
+ // Move constructors.
+ unique_ptr(unique_ptr&& __u)
+ : _t(__u.release()), _deleter(std::forward<deleter_type>(__u.get_deleter())) { }
+
+ template<typename _Up, typename _Up_Deleter>
+ unique_ptr(unique_ptr<_Up, _Up_Deleter>&& __u)
+ : _t(__u.release()), _deleter(std::forward<deleter_type>(__u.get_deleter()))
+ { }
+
+ // Destructor.
+ ~unique_ptr() { reset(); }
+
+ // Assignment.
+ unique_ptr&
+ operator=(unique_ptr&& __u)
+ {
+ reset(__u.release());
+ get_deleter() = std::move(__u.get_deleter());
+ return *this;
+ }
+
+ template<typename _Up, typename _Up_Deleter>
+ unique_ptr&
+ operator=(unique_ptr<_Up, _Up_Deleter>&& __u)
+ {
+ reset(__u.release());
+ get_deleter() = std::move(__u.get_deleter());
+ return *this;
+ }
+
+ unique_ptr&
+ operator=(__unspecified_pointer_type)
+ {
+ reset();
+ return *this;
+ }
+
+ // Observers.
+ typename std::add_lvalue_reference<element_type>::type
+ operator*() const
+ {
+ assert(get() != pointer());
+ return *get();
+ }
+
+ pointer
+ operator->() const
+ {
+ assert(get() != pointer());
+ return get();
+ }
+
+ pointer
+ get() const
+ { return _t; }
+
+ deleter_type&
+ get_deleter()
+ { return _deleter; }
+
+ const deleter_type&
+ get_deleter() const
+ { return _deleter; }
+
+ explicit operator bool() const
+ { return get() == pointer() ? false : true; }
+
+ // Modifiers.
+ pointer
+ release()
+ {
+ pointer __p = get();
+ _t = pointer();
+ return __p;
+ }
+
+ void
+ reset(pointer __p = pointer())
+ {
+ using std::swap;
+ swap(_t, __p);
+ if (__p != pointer())
+ get_deleter()(__p);
+ }
+
+ void
+ swap(unique_ptr& __u)
+ {
+ using std::swap;
+ swap(_t, __u._t);
+ swap(_deleter, __u._deleter);
+ }
+
+ // Disable copy from lvalue.
+ unique_ptr(const unique_ptr&) = delete;
+ unique_ptr& operator=(const unique_ptr&) = delete;
+
+ private:
+ _Tp *_t;
+ _Tp_Deleter _deleter;
+ };
+
+ /// 20.7.12.3 unique_ptr for array objects with a runtime length
+ // [unique.ptr.runtime]
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // DR 740 - omit specialization for array objects with a compile time length
+ template<typename _Tp, typename _Tp_Deleter>
+ class unique_ptr<_Tp[], _Tp_Deleter>
+ {
+ typedef _Tp* unique_ptr::* __unspecified_pointer_type;
+
+ public:
+ typedef _Tp* pointer;
+ typedef _Tp element_type;
+ typedef _Tp_Deleter deleter_type;
+
+ // Constructors.
+ unique_ptr()
+ : _t(pointer()), _deleter(deleter_type())
+ { static_assert(!std::is_pointer<deleter_type>::value,
+ "constructed with null function pointer deleter"); }
+
+ explicit
+ unique_ptr(pointer __p)
+ : _t(__p), _deleter(deleter_type())
+ { static_assert(!std::is_pointer<deleter_type>::value,
+ "constructed with null function pointer deleter"); }
+
+ unique_ptr(pointer __p,
+ typename std::conditional<std::is_reference<deleter_type>::value,
+ deleter_type, const deleter_type&>::type __d)
+ : _t(__p), _deleter(__d) { }
+
+ unique_ptr(pointer __p,
+ typename std::remove_reference<deleter_type>::type && __d)
+ : _t(std::move(__p)), _deleter(std::move(__d))
+ { static_assert(!std::is_reference<deleter_type>::value,
+ "rvalue deleter bound to reference"); }
+
+ // Move constructors.
+ unique_ptr(unique_ptr&& __u)
+ : _t(__u.release()), _deleter(std::forward<deleter_type>(__u.get_deleter())) { }
+
+ template<typename _Up, typename _Up_Deleter>
+ unique_ptr(unique_ptr<_Up, _Up_Deleter>&& __u)
+ : _t(__u.release()), _deleter(std::forward<deleter_type>(__u.get_deleter()))
+ { }
+
+ // Destructor.
+ ~unique_ptr() { reset(); }
+
+ // Assignment.
+ unique_ptr&
+ operator=(unique_ptr&& __u)
+ {
+ reset(__u.release());
+ get_deleter() = std::move(__u.get_deleter());
+ return *this;
+ }
+
+ template<typename _Up, typename _Up_Deleter>
+ unique_ptr&
+ operator=(unique_ptr<_Up, _Up_Deleter>&& __u)
+ {
+ reset(__u.release());
+ get_deleter() = std::move(__u.get_deleter());
+ return *this;
+ }
+
+ unique_ptr&
+ operator=(__unspecified_pointer_type)
+ {
+ reset();
+ return *this;
+ }
+
+ // Observers.
+ typename std::add_lvalue_reference<element_type>::type
+ operator[](size_t __i) const
+ {
+ assert(get() != pointer());
+ return get()[__i];
+ }
+
+ pointer
+ get() const
+ { return _t; }
+
+ deleter_type&
+ get_deleter()
+ { return _deleter; }
+
+ const deleter_type&
+ get_deleter() const
+ { return _deleter; }
+
+ explicit operator bool() const
+ { return get() == pointer() ? false : true; }
+
+ // Modifiers.
+ pointer
+ release()
+ {
+ pointer __p = get();
+ _t = pointer();
+ return __p;
+ }
+
+ void
+ reset(pointer __p = pointer())
+ {
+ using std::swap;
+ swap(_t, __p);
+ if (__p != pointer())
+ get_deleter()(__p);
+ }
+
+ // DR 821.
+ template<typename _Up>
+ void reset(_Up) = delete;
+
+ void
+ swap(unique_ptr& __u)
+ {
+ swap(_t, __u._t);
+ swap(_deleter, __u._deleter);
+ }
+
+ // Disable copy from lvalue.
+ unique_ptr(const unique_ptr&) = delete;
+ unique_ptr& operator=(const unique_ptr&) = delete;
+
+ // Disable construction from convertible pointer types.
+ // (N2315 - 20.6.5.3.1)
+ template<typename _Up>
+ unique_ptr(_Up*, typename
+ std::conditional<std::is_reference<deleter_type>::value,
+ deleter_type, const deleter_type&>::type,
+ typename std::enable_if<std::is_convertible<_Up*,
+ pointer>::value>::type* = 0) = delete;
+
+ template<typename _Up>
+ unique_ptr(_Up*, typename std::remove_reference<deleter_type>::type&&,
+ typename std::enable_if<std::is_convertible<_Up*,
+ pointer>::value>::type* = 0) = delete;
+
+ template<typename _Up>
+ explicit
+ unique_ptr(_Up*, typename std::enable_if<std::is_convertible<_Up*,
+ pointer>::value>::type* = 0) = delete;
+
+ private:
+ _Tp *_t;
+ _Tp_Deleter _deleter;
+ };
+
+ template<typename _Tp, typename _Tp_Deleter>
+ inline void
+ swap(unique_ptr<_Tp, _Tp_Deleter>& __x,
+ unique_ptr<_Tp, _Tp_Deleter>& __y)
+ { __x.swap(__y); }
+
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
+ operator==(const unique_ptr<_Tp, _Tp_Deleter>& __x,
+ const unique_ptr<_Up, _Up_Deleter>& __y)
+ { return __x.get() == __y.get(); }
+
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
+ operator!=(const unique_ptr<_Tp, _Tp_Deleter>& __x,
+ const unique_ptr<_Up, _Up_Deleter>& __y)
+ { return !(__x.get() == __y.get()); }
+
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
+ operator<(const unique_ptr<_Tp, _Tp_Deleter>& __x,
+ const unique_ptr<_Up, _Up_Deleter>& __y)
+ { return __x.get() < __y.get(); }
+
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
+ operator<=(const unique_ptr<_Tp, _Tp_Deleter>& __x,
+ const unique_ptr<_Up, _Up_Deleter>& __y)
+ { return !(__y.get() < __x.get()); }
+
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
+ operator>(const unique_ptr<_Tp, _Tp_Deleter>& __x,
+ const unique_ptr<_Up, _Up_Deleter>& __y)
+ { return __y.get() < __x.get(); }
+
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
+ operator>=(const unique_ptr<_Tp, _Tp_Deleter>& __x,
+ const unique_ptr<_Up, _Up_Deleter>& __y)
+ { return !(__x.get() < __y.get()); }
+
+ // @} group pointer_abstractions
+
+} // namespace std
+
+#endif /* _UNIQUE_PTR_H */
diff --git a/aos/crio/shared_libs/limit_encoder_reader.cc b/aos/crio/shared_libs/limit_encoder_reader.cc
new file mode 100644
index 0000000..f3391f1
--- /dev/null
+++ b/aos/crio/shared_libs/limit_encoder_reader.cc
@@ -0,0 +1,102 @@
+#include "aos/crio/shared_libs/limit_encoder_reader.h"
+
+#include <functional>
+
+#include "WPILib/AnalogTrigger.h"
+
+using ::std::unique_ptr;
+
+namespace aos {
+namespace crio {
+
+class LimitEncoderReader::AnalogOnOffGetter
+ : public LimitEncoderReader::OnOffGetter {
+ public:
+ AnalogOnOffGetter(unique_ptr<AnalogChannel> channel,
+ unique_ptr<AnalogTrigger> trigger,
+ unique_ptr<AnalogTriggerOutput> source)
+ : channel_(::std::move(channel)), trigger_(::std::move(trigger)),
+ source_(::std::move(source)) {}
+
+ virtual bool Get() {
+ return source_->Get();
+ }
+
+ private:
+ unique_ptr<AnalogChannel> channel_;
+ unique_ptr<AnalogTrigger> trigger_;
+ unique_ptr<AnalogTriggerOutput> source_;
+};
+class LimitEncoderReader::DigitalOnOffGetter
+ : public LimitEncoderReader::OnOffGetter {
+ public:
+ DigitalOnOffGetter(DigitalInput *source)
+ : source_(source) {}
+
+ virtual bool Get() {
+ return source_->Get();
+ }
+
+ private:
+ DigitalInput *source_;
+};
+
+LimitEncoderReader::LimitEncoderReader(const unique_ptr<Encoder> &encoder,
+ unique_ptr<AnalogChannel> channel,
+ AnalogTriggerOutput::Type type,
+ AnalogTriggerOutput::Type triggeredType,
+ bool posEdge, bool negEdge,
+ float lowerVoltage,
+ float upperVoltage)
+ : encoder_(encoder),
+ getter_(NULL),
+ source_(NULL) {
+ unique_ptr<AnalogTrigger> trigger(new AnalogTrigger(channel.get()));
+ trigger->SetLimitsVoltage(lowerVoltage, upperVoltage);
+ source_ = unique_ptr<AnalogTriggerOutput>(trigger->CreateOutput(type));
+ getter_ = unique_ptr<AnalogOnOffGetter>(
+ new AnalogOnOffGetter(::std::move(channel), ::std::move(trigger),
+ unique_ptr<AnalogTriggerOutput>(
+ trigger->CreateOutput(triggeredType))));
+ Init(posEdge, negEdge);
+}
+
+LimitEncoderReader::LimitEncoderReader(const unique_ptr<Encoder> &encoder,
+ unique_ptr<DigitalInput> source,
+ bool posEdge, bool negEdge)
+ : encoder_(encoder),
+ getter_(new DigitalOnOffGetter(source.get())),
+ source_(::std::move(source)) {
+ Init(posEdge, negEdge);
+}
+
+void LimitEncoderReader::Init(bool posEdge, bool negEdge) {
+ notifier_ = unique_ptr<InterruptNotifier<LimitEncoderReader>>(
+ new InterruptNotifier<LimitEncoderReader>(ReadValueStatic,
+ source_.get(),
+ this));
+ source_->SetUpSourceEdge(posEdge, negEdge);
+}
+
+void LimitEncoderReader::ReadValue() {
+ // Retrieve the value before potentially waiting for somebody else currently
+ // looking at the saved one.
+ int32_t new_value = encoder_->GetRaw();
+ {
+ MutexLocker locker(&value_sync_);
+ value_ = new_value;
+ }
+}
+
+ZeroSwitchValue LimitEncoderReader::Get() {
+ MutexLocker locker(&value_sync_);
+ return ZeroSwitchValue{encoder_->GetRaw(), value_, getter_->Get()};
+}
+
+void LimitEncoderReader::Start() {
+ encoder_->Start();
+ notifier_->Start();
+}
+
+} // namespace crio
+} // namespace aos
diff --git a/aos/crio/shared_libs/limit_encoder_reader.h b/aos/crio/shared_libs/limit_encoder_reader.h
new file mode 100644
index 0000000..1bd2d57
--- /dev/null
+++ b/aos/crio/shared_libs/limit_encoder_reader.h
@@ -0,0 +1,102 @@
+#ifndef AOS_CRIO_SHARED_LIBS_ENCODER_READER_H_
+#define AOS_CRIO_SHARED_LIBS_ENCODER_READER_H_
+
+#include "aos/common/libstdc++/memory"
+
+#include "WPILib/DigitalSource.h"
+#include "WPILib/AnalogChannel.h"
+#include "WPILib/AnalogTriggerOutput.h"
+#include "WPILib/DigitalInput.h"
+#include "WPILib/Encoder.h"
+
+#include "aos/common/mutex.h"
+#include "aos/common/zero_switch_value.h"
+#include "aos/common/macros.h"
+#include "aos/crio/shared_libs/interrupt_notifier.h"
+
+namespace aos {
+namespace crio {
+
+// This class handles reading an Encoder's value each time a digital sensor
+// triggers, including all of the irritating WPILib setup and synchronization.
+class LimitEncoderReader {
+ public:
+ // Defaults for the voltages for AnalogTriggers. They work well for digital
+ // sensors connected to analog inputs.
+ // TODO(brians): make sure these values are reasonable
+ static const float kDefaultLowerVoltage = 1;
+ static const float kDefaultUpperVoltage = 3;
+
+ // See InterruptNotifier for details about the state of the sensor object
+ // before the constructor is called.
+ // The different constructors take in different types of inputs and configure
+ // them to give interrupts.
+ //
+ // type is the type for triggering interrupts while triggeredType is the one
+ // to use for writing *triggered in Get().
+ // AnalogTriggerOutput::Type::k*Pulse don't seem to do anything...
+ LimitEncoderReader(const ::std::unique_ptr<Encoder> &encoder,
+ ::std::unique_ptr<AnalogChannel> channel,
+ AnalogTriggerOutput::Type type,
+ AnalogTriggerOutput::Type triggeredType,
+ bool posEdge, bool negEdge,
+ float lowerVoltage = kDefaultLowerVoltage,
+ float upperVoltage = kDefaultUpperVoltage);
+ LimitEncoderReader(const ::std::unique_ptr<Encoder> &encoder,
+ ::std::unique_ptr<DigitalInput> sensor,
+ bool posEdge, bool negEdge);
+
+ // Retrieves the values. See ZeroSwitchValue's declaration for an explanation
+ // of why retrieving all of them is necessary.
+ ZeroSwitchValue Get();
+
+ // Calls Start() on all contained objects.
+ void Start();
+
+ // Only to set things up etc. Getting values through these methods will always
+ // have race conditions!
+ // Also helpful for debugging.
+ const ::std::unique_ptr<Encoder> &encoder() const { return encoder_; }
+ const ::std::unique_ptr<DigitalSource> &source() const { return source_; }
+
+ private:
+ // A class to deal with the fact that WPILib's AnalogTriggerOutput and
+ // DigitalInput have no common superclass with their Get() functions.
+ // Also handles taking ownership of some attached objects for
+ // AnalogTriggerOutput.
+ class OnOffGetter {
+ public:
+ virtual bool Get() = 0;
+
+ virtual ~OnOffGetter() {}
+ };
+ class AnalogOnOffGetter;
+ class DigitalOnOffGetter;
+
+ // The common initialization code.
+ // Gets called by all of the constructors.
+ // getter_, encoder_, and source_ must be set before calling this.
+ void Init(bool posEdge, bool negEdge);
+
+ static void ReadValueStatic(LimitEncoderReader *self) {
+ self->ReadValue();
+ }
+ void ReadValue();
+
+ ::std::unique_ptr<InterruptNotifier<LimitEncoderReader>> notifier_;
+ const ::std::unique_ptr<Encoder> &encoder_;
+
+ ::std::unique_ptr<OnOffGetter> getter_;
+ ::std::unique_ptr<DigitalSource> source_;
+
+ // The most recently read value.
+ int32_t value_;
+ Mutex value_sync_;
+
+ DISALLOW_COPY_AND_ASSIGN(LimitEncoderReader);
+};
+
+} // namespace crio
+} // namespace aos
+
+#endif // AOS_CRIO_SHARED_LIBS_ENCODER_READER_H_