Introduce an IO abstraction layer

Separates out the I/O from components, allowing for multiple
target implementations, as well as easier testing of the components.
Note: Current the interface is very Arduino centric,
and the host implementation is just as stub.