Abstract
Go developed a fairly large hardware hacker community in part because the
language and its tooling have the following properties:
- Native support in the tool chain to cross compile to ARM/Linux via
GOOS=linux GOARCH=arm go build .
.
- Significantly faster to execute than python and node.js.
- Significantly lighter in term of memory use than Java or node.js.
- Significantly more productive to code than C/C++.
- Builds reasonably fast on ARM.
- Fairly good OS level support.
Many Go packages, both generic and specialized, were created to fill the space.
This library came out of the desire to have a designed API (contrary to
growing organically) with strict code requirements and a
strong, opinionated philosophy to enable long term
maintenance.
Goals
periph
was created as an answer to specific goals:
- Not more abstract than absolutely needed. Use concrete types whenever
possible.
- Orthogonality and composability
- Each component must own an orthogonal part of the platform and each
components can be composed together.
- Extensible:
- Users can provide additional drivers that are seamlessly loaded
with a structured ordering of priority.
- Performance:
- Execution as performant as possible.
- Overhead as minimal as possible, i.e. irrelevant driver are not be
attempted to be loaded, uses memory mapped GPIO registers instead of sysfs
whenever possible, etc.
- Coverage:
- Be as OS agnostic as possible. Abstract OS specific concepts like
sysfs.
- Each driver implements and exposes as much of the underlying device
capability as possible and relevant.
- cmd implements useful
directly usable tool.
- devices implements common device
drivers. Device drivers is not the core focus of this project for now.
- host must implement a large base of
common platforms that just work. This is in addition to extensibility.
- Simplicity:
- Static typing is thoroughly used, to reduce the risk of runtime failure.
- Minimal coding is needed to accomplish a task.
- Use of the library is defacto portable.
- Include fakes for buses and device interfaces to simplify the life of
device driver developers.
- Stability
- API must be stable without precluding core refactoring.
- Breakage in the API should happen at a yearly parce at most once the library
got to a stable state.
- Strong distinction about the driver (as a user of a
conn.Conn instance) and an application
writer (as a user of a device driver). It’s the application that controls
the objects' lifetime.
- Strong distinction between enablers and devices. See
Background.
Philosophy
The project was designed with a very clear vision:
- Optimize for simplicity, correctness and usability in that order.
- e.g. everything, interfaces and structs, uses strict typing, there’s no
interface{}
in sight.
- OS agnostic. Clear separation of interfaces in
conn,
enablers in host and device
drivers in devices.
- e.g. no devfs or sysfs path in sight.
- e.g. conditional compilation enables only the relevant drivers to be loaded
on each platform.
- … yet doesn’t get in the way of platform specific code.
- e.g. A user can use statically typed global variables
rpi.P1_3,
bcm283x.GPIO2
to refer to the exact same pin on a Raspberry Pi.
- The user can chose to optimize for performance instead of usability.
- Use a divide and conquer approach. Each component has exactly one
responsibility.
- e.g. instead of having a driver per “platform”, there’s a driver per
“component”: one for the CPU, one for the board headers, one for each
bus and sensor, etc.
- Extensible via a driver
registry.
- e.g. a user can inject a custom driver to expose more pins, headers, etc.
A USB device (like an FT232H) can expose headers in addition to the
headers found on the board.
- The drivers must use the fastest possible implementation.
- e.g. both allwinner and
bcm283x leverage sysfs
gpio to expose interrupt driven
edge detection, yet use memory mapped GPIO registers to perform
single-cycle reads and writes.
Success criteria
- Preferred library used by first time Go users and by experts.
- Becomes the defacto HAL library.
- Becomes the central link for hardware support.
Risks
The risks below are being addressed via Go modules versioning, continuous
integration testing and having a high quality bar via an explicit list of
requirements.
The enablers (boards, CPU, buses) is what will break or make this project.
Nobody want to do them but they are needed. You need a large base of enablers so
people can use anything yet they are hard to get right. You want them all in the
same repo so that when someone builds an app, it supports everything
transparently. It just works.
The device drivers do not need to all be in the same repo, that scales since
people know what is physically connected, but a large enough set of enablers is
needed to be in the base repository to enable seemlessness. People do not care
that a Pine64 has a different processor than a Rasberry Pi; both have the same
40 pins header and that’s what they care about. So enablers need to be a great
HAL -> the right hardware abstraction layer (not too deep, not too light) is the
core here.
Users
- The library is rejected by users as being too cryptic or hard to use.
- The device drivers are unreliable or non functional, as observed by users.
- Poor usability of the core interfaces.
- Missing drivers.
Contributors
- Lack of API stability; high churn rate.
- Poor fitting of the core interfaces.
- No uptake in external contribution.
- Poor quality of contribution.
- Duplicate ways to accomplish the same thing, without a clear way to define the
right way.