AdaCore / Ada-SPARK-Crate-Of-The-Year

19 stars 2 forks source link

[2021][libsimpleio] Ada Bindings for the Linux Simple I/O Library #4

Closed pmunts closed 2 years ago

pmunts commented 3 years ago

libsimpleio

The Linux Simple I/O Library (aka libsimpleio) is an attempt to encapsulate (as much as possible) the ugliness of Linux I/O device access. It provides services for the following types of I/O devices:

This crate contains the C wrapper functions that constitute the core of libsimpleio, Ada thin binding packages for those C wrapper functions, as well as many object oriented Ada packages for abstract interfaces, device drivers, and other services.

This crate also contains all of the functionality of the mcp2221 and remoteio crates. Unlike those crates, which can be used on Linux or Windows, this crate can only be used on Linux.

libsimpleio is a general purpose library I have used and continue to use for a variety of projects, including submissions to the Make with Ada contest in 2017 (Ada Embedded Linux Framework) and 2019 (Modbus RTU Framework for Ada).

All source files in this crate are my original work.

Purpose

Like libsimpleio itself, the purpose of this crate is to make it easier to develop embedded systems software on Linux platforms, especially small and low cost Linux microcomputers like the BeagleBone or the Raspberry Pi. These Linux microcomputers typically have a myriad of on-board I/O devices, such as GPIO pins, ADC inputs, PWM outputs, various kinds of sensors, and many others.

Although Linux desktop and laptop computers do not generally have these kinds of on-board I/O devices, this crate is still useful on them because it provides rich services for communicating with slave I/O processors implemented with Linux microcomputers such as a MuntsOS Embedded Linux GPIO Thin Server or even with a single chip microcontroller as small as a PIC16F1455.

Nearly all of the libsimpleio device driver packages can be used with a device directly attached to the target computer or to a slave I/O processor, or both.

A first Ada program to flash an LED connected to a GPIO pin (the embedded systems equivalent of Hello, World!) would look like:

WITH Ada.Text_IO; USE Ada.Text_IO;

WITH GPIO.libsimpleio;
WITH RaspberryPi;

PROCEDURE test_led IS

  LED : GPIO.Pin;

BEGIN
  New_Line;
  Put_Line("LED Test");
  New_Line;

  -- Configure a GPIO output to drive an LED

  LED := GPIO.libsimpleio.Create(RaspberryPi.GPIO26, GPIO.Output);

  -- Flash the LED

  LOOP
    LED.Put(NOT LED.Get);
    DELAY 0.5;
  END LOOP;
END test_led;

Design

The Ada bindings for libsimpleio have a layered structure:

The lowest layer consists of C wrapper functions. These wrapper functions are written to present a more unified and coherent API (Application Programming Interface) than the Linux kernel provides. The wrapper functions are all proper procedures that return an errno error code in the last argument, error. The wrapper functions are designed to be easily called from Ada, Pascal, C# and other programming languages.

All of the C source and header files are found in src/c/.

The next layer consists of binding packages that bind an Ada procedure to each one of the C wrapper functions, using pragma import. Many of the binding packages also declare constants (usually either named numbers or 32-bit integers), as needed for each API.

The binding packages are found in src/bindings/.

The next layer consists of abstract interface packages. Each abstract interface package defines one or more interface types (type FooInterface is interface), each with an associated classwide access type (type Foo is access all FooInterface'Class). This allows an access to any implementation of the interface type to be assigned to the access variable. For example, the abstract type GPIO.PinInterface encapsulates all kinds of GPIO pins. An array of GPIO.Pin can contain accesses to all kinds of GPIO pins, local and remote, that can be in manipulated exactly the same manner, no matter how each pin is actually implemented. As with Free Pascal and .Net, interface types are used pervasively in the Ada binding to libsimpleio.

Many of the abstract interface packages internally instantiate the generic package IO_Interfaces, which contains a lot of boilerplate common to all sorts of abstract interface types.

The abstract interface packages are found in src/interfaces/.

The next layer consists of miscellaneous service packages that are not specific to any particular device.

The service packages are found in src/objects/ and its subdirectories.

The uppermost layer consists of device packages, which are specific to particular I/O devices. The device packages generally depend only on interface packages and therefore can be reused in different contexts. For example, the package MCP3202 depends on Analog and SPI. The constructor inside MCP3202 requires an SPI.Device access, since the MCP3202 Analog to Digital Converter is an SPI slave device. Any service that implements SPI.DeviceInterface can be used.

The device packages are found in src/devices/.

Authors

Philip Munts

License

BSD-1-Clause

Documentation

Crate README.pdf

Linux Simple I/O Library User Manual