% @doc GRiSP General Purpose Input/Output (GPIO) API.
%
% General Purpose Input / Output (GPIO) is used to control digital signals on a
% pin. The digital values `0' and `1' correspond to a low or high voltage
% respectively. On GRiSP the voltage for GPIO pins is 3.3V.
%
% A pin can be controlled either as an output pin or an input pin. For an output
% pin, it is possible to set or get the current value. For an input pin, it is
% possible to get the current value.
%
% === Pin Mappings ===
%
% For PMOD connectors, the number column (#) maps to the respective PMOD
% pin (see Figure 1).
%
%
%
GRiSP 2 Pin Mappings
%
%
ID
%
Mapping
%
Direction
%
Description
%
%
%
Slot
%
Type
%
#
%
Schematic
%
%
`gpio1_1'
GPIO1
PMOD 1A
1
X1404.1
In/Out
%
`gpio1_2'
GPIO1
PMOD 1A
2
X1404.2
In/Out
%
`gpio1_3'
GPIO1
PMOD 1A
3
X1404.3
In/Out
%
`gpio1_4'
GPIO1
PMOD 1A
4
X1404.4
In/Out
%
`gpio1_7'
GPIO1
PMOD 1A
7
X1404.7
In/Out
%
`gpio1_8'
GPIO1
PMOD 1A
8
X1404.8
In/Out
%
`gpio1_9'
GPIO1
PMOD 1A
9
X1404.9
In/Out
%
`gpio_1_3'
GPIO_1
Generic
X1300.3
In/Out
%
`gpio_1_4'
GPIO_1
Generic
X1300.4
In/Out
%
`gpio_1_5'
GPIO_1
Generic
X1300.5
In/Out
%
`gpio_1_6'
GPIO_1
Generic
X1300.6
In/Out
%
`gpio_2_3'
GPIO_2/4
Generic
X1301.3
In/Out
%
`gpio_2_4'
GPIO_2/4
Generic
X1301.4
In/Out
%
`gpio_2_5'
GPIO_2/4
Generic
X1301.5
In/Out
%
`gpio_2_6'
GPIO_2/4
Generic
X1301.6
In/Out
%
`gpio_2_7'
GPIO_2/4
Generic
X1301.7
In/Out
%
`gpio_2_8'
GPIO_2/4
Generic
X1301.8
In/Out
%
`gpio_2_9'
GPIO_2/4
Generic
X1301.9
In/Out
%
`gpio_2_10'
GPIO_2/4
Generic
X1301.10
In/Out
%
`gpio_2_11'
GPIO_2/4
Generic
X1301.11
In/Out
%
`gpio_2_12'
GPIO_2/4
Generic
X1301.12
In/Out
%
`gpio_2_13'
GPIO_2/4
Generic
X1301.13
In/Out
%
`gpio_2_14'
GPIO_2/4
Generic
X1301.14
In/Out
%
`led1_r'
LED 1
LED
RGB1red
Out
Reserved by LED driver
%
`led1_g'
LED 1
LED
RGB1green
Out
Reserved by LED driver
%
`led1_b'
LED 1
LED
RGB1blue
Out
Reserved by LED driver
%
`led2_r'
LED 2
LED
RGB2red
Out
Reserved by LED driver
%
`led2_g'
LED 2
LED
RGB2green
Out
Reserved by LED driver
%
`led2_b'
LED 2
LED
RGB3blue
Out
Reserved by LED driver
%
`jumper_1'
Mode
Jumper
JUMPER1
In
Mode Switch Jumper State
%
`jumper_2'
Mode
Jumper
JUMPER2
In
Mode Switch Jumper State
%
`jumper_3'
Mode
Jumper
JUMPER3
In
Mode Switch Jumper State
%
`jumper_4'
Mode
Jumper
JUMPER4
In
Mode Switch Jumper State
%
`jumper_5'
Mode
Jumper
JUMPER5
In
Mode Switch Jumper State
%
Warning! Reserved pins should only be carefully used if their drivers are not in use
%
%
%
GRiSP 1 Pin Mappings
%
%
ID
%
Mapping
%
Direction
%
Description
%
%
%
Slot
%
Type
%
#
%
Schematic
%
%
`gpio1_1'
GPIO1
PMOD 1
1
X502.1
In/Out
%
`gpio1_2'
GPIO1
PMOD 1
2
X502.2
In/Out
%
`gpio1_3'
GPIO1
PMOD 1
3
X502.3
In/Out
%
`gpio1_4'
GPIO1
PMOD 1
4
X502.4
In/Out
%
`gpio2_1'
GPIO2
PMOD 1
1
X503.1
In/Out
%
`gpio2_2'
GPIO2
PMOD 1
2
X503.2
In/Out
%
`gpio2_3'
GPIO2
PMOD 1
3
X503.3
In/Out
%
`gpio2_4'
GPIO2
PMOD 1
4
X503.4
In/Out
%
`led1_r'
LED 1
LED
RGB1red
Out
Reserved by LED driver
%
`led1_g'
LED 1
LED
RGB1green
Out
Reserved by LED driver
%
`led1_b'
LED 1
LED
RGB1blue
Out
Reserved by LED driver
%
`led2_r'
LED 2
LED
RGB2red
Out
Reserved by LED driver
%
`led2_g'
LED 2
LED
RGB2green
Out
Reserved by LED driver
%
`led2_b'
LED 2
LED
RGB3blue
Out
Reserved by LED driver
%
`jumper_1'
Mode
Jumper
JUMPER1
In
Mode Switch Jumper State
%
`jumper_2'
Mode
Jumper
JUMPER2
In
Mode Switch Jumper State
%
`jumper_3'
Mode
Jumper
JUMPER3
In
Mode Switch Jumper State
%
`jumper_4'
Mode
Jumper
JUMPER4
In
Mode Switch Jumper State
%
`jumper_5'
Mode
Jumper
JUMPER5
In
Mode Switch Jumper State
%
`spi1_pin7'
SPI1
PMOD 2A
7
X501.7
In/Out
%
`spi1_pin8'
SPI1
PMOD 2A
8
X501.8
In/Out
%
`spi1_pin9'
SPI1
PMOD 2A
9
X501.9
In/Out
Reserved by SPI driver
%
`spi1_pin10'
SPI1
PMOD 2A
10
X501.10
In/Out
Reserved by SPI driver
%
`spi1_pin1'
SPI1
PMOD 2A
1
X501.1
In/Out
Reserved by SPI driver
%
`spi2_pin1'
SPI2
PMOD 2
1
X509.1
In/Out
Reserved by SPI driver
%
`uart_1_cts'
UART
PMOD 3
1
X508.1
In/Out
%
`uart_2_txd'
UART
PMOD 3
2
X508.2
In/Out
%
`uart_3_rxd'
UART
PMOD 3
3
X508.3
In/Out
%
`uart_4_rts'
UART
PMOD 3
4
X508.4
In/Out
%
Warning! Reserved pins should only be carefully used if their drivers are not in use
%
%
% === PMOD Pin Numbers ===
%
%
%
% Figure 1. PMOD connectors as seen from the side of a GRiSP
% board with number mappings
%
%
% PMOD Type A consists of:
%
%
4 × data, pins #1-4
%
1 × ground, pin #5
%
1 × 3.3V power, pin #6
%
% PMOD Type B consists of:
%
%
8 × data, pins #1-4 and #7-10
%
1 × ground, pins #5 and #11
%
1 × 3.3V power, pins #6 and #12
%
-module(grisp_gpio).
-include("grisp_nif.hrl").
% API
-export([open/1]).
-export([open/2]).
-export([set/2]).
-export([get/1]).
% Callbacks
-export([on_load/0]).
-on_load(on_load/0).
% Macros
-define(DEFAULT_OPTS, #{mode => {output, 0}}).
% Attributes
-compile({no_auto_import, [get/1]}).
%--- Types ---------------------------------------------------------------------
-type pin() :: atom().
-type opts() :: map().
-opaque ref() :: reference().
-type value() :: 0 | 1.
-export_type([pin/0]).
-export_type([opts/0]).
-export_type([ref/0]).
-export_type([value/0]).
%--- API -----------------------------------------------------------------------
% @equiv open(Pin, #{})
-spec open(pin()) -> ref().
open(Pin) -> open(Pin, #{}).
% @doc Creates a reference to a GPIO pin.
%
% === Example ===
% Open the GPIO pin of the red component of LED 1 as an output pin with initial
% value of `0':
% ```
% 1> grisp_gpio:open(led1_r, {output, 0}).
% #Ref<0.2691682867.116916226.176944>
% '''
-spec open(pin(), opts()) -> ref().
open(Pin, UserOpts) ->
#{mode := Mode} = maps:merge(?DEFAULT_OPTS, UserOpts),
gpio_open_nif(pin(Pin), Mode).
% @doc Sets the current value of an output pin.
%
% === Example ===
% Turn off the red component of LED 1:
% ```
% 1> LED1R = grisp_gpio:open(led1_r, {output, 0}).
% #Ref<0.2691682867.116916226.176944>
% 2> grisp_gpio:set(LED1R, 0).
% ok
% '''
% Turn on the red component of LED 1:
% ```
% 3> grisp_gpio:set(LED1R, 1).
% ok
% '''
-spec set(ref(), value()) -> ok.
set(Pin, Value) when is_integer(Value) -> gpio_set_nif(Pin, Value).
% @doc Returns the current value of a pin.
%
% Returns the actual value for input pins or the currently set value for output
% pins.
%
% === Examples ===
% To see whether the red component of LED 1 is enabled:
% ```
% 1> LED1R = grisp_gpio:open(led1_r, {output, 0}).
% #Ref<0.2691682867.116916226.176944>
% 2> grisp_gpio:get(LED1R).
% 0
% 3> grisp_gpio:set(LED1R, 1).
% ok
% 2> grisp_gpio:get(LED1R).
% 1
% '''
-spec get(ref()) -> value().
get(Pin) -> gpio_get_nif(Pin).
%--- Callbacks -----------------------------------------------------------------
% @private
on_load() -> ok = erlang:load_nif(atom_to_list(?MODULE), 0).
%--- Internal ------------------------------------------------------------------
gpio_open_nif(_Attributes, _Mode) -> ?NIF_STUB.
gpio_set_nif(_Pin, _Value) -> ?NIF_STUB.
gpio_get_nif(_Pin) -> ?NIF_STUB.
pin(Pin) -> pin(grisp_hw:platform(), Pin).
% erlfmt-ignore
pin(grisp_base, gpio1_1) -> #{index => 0};
pin(grisp_base, gpio1_2) -> #{index => 1};
pin(grisp_base, gpio1_3) -> #{index => 2};
pin(grisp_base, gpio1_4) -> #{index => 3};
pin(grisp_base, gpio2_1) -> #{index => 4};
pin(grisp_base, gpio2_2) -> #{index => 5};
pin(grisp_base, gpio2_3) -> #{index => 6};
pin(grisp_base, gpio2_4) -> #{index => 7};
pin(grisp_base, led1_r) -> #{index => 8};
pin(grisp_base, led1_g) -> #{index => 9};
pin(grisp_base, led1_b) -> #{index => 10};
pin(grisp_base, led2_r) -> #{index => 11};
pin(grisp_base, led2_g) -> #{index => 12};
pin(grisp_base, led2_b) -> #{index => 13};
pin(grisp_base, jumper_1) -> #{index => 14};
pin(grisp_base, jumper_2) -> #{index => 15};
pin(grisp_base, jumper_3) -> #{index => 16};
pin(grisp_base, jumper_4) -> #{index => 17};
pin(grisp_base, jumper_5) -> #{index => 18};
pin(grisp_base, spi1_pin7) -> #{index => 19};
pin(grisp_base, spi1_pin8) -> #{index => 20};
pin(grisp_base, spi1_pin9) -> #{index => 21};
pin(grisp_base, spi1_pin10) -> #{index => 22};
pin(grisp_base, spi1_pin1) -> #{index => 23};
pin(grisp_base, spi2_pin1) -> #{index => 24};
pin(grisp_base, uart_1_cts) -> #{index => 25};
pin(grisp_base, uart_2_txd) -> #{index => 26};
pin(grisp_base, uart_3_rxd) -> #{index => 27};
pin(grisp_base, uart_4_rts) -> #{index => 28};
pin(grisp2, gpio1_1) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 0};
pin(grisp2, gpio1_2) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 1};
pin(grisp2, gpio1_3) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 2};
pin(grisp2, gpio1_4) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 3};
pin(grisp2, gpio1_7) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 4};
pin(grisp2, gpio1_8) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 5};
pin(grisp2, gpio1_9) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 6};
pin(grisp2, gpio1_10) -> #{path => <<"/pmod-gpio\0">>, property => <<"grisp,gpios\0">>, index => 7};
pin(grisp2, gpio_1_3) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 0};
pin(grisp2, gpio_1_4) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 1};
pin(grisp2, gpio_1_5) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 2};
pin(grisp2, gpio_1_6) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 3};
pin(grisp2, gpio_2_3) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 4};
pin(grisp2, gpio_2_4) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 5};
pin(grisp2, gpio_2_5) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 6};
pin(grisp2, gpio_2_6) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 7};
pin(grisp2, gpio_2_7) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 8};
pin(grisp2, gpio_2_8) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 9};
pin(grisp2, gpio_2_9) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 10};
pin(grisp2, gpio_2_10) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 11};
pin(grisp2, gpio_2_11) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 12};
pin(grisp2, gpio_2_12) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 13};
pin(grisp2, gpio_2_13) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 14};
pin(grisp2, gpio_2_14) -> #{path => <<"/pin-gpio\0">>, property => <<"grisp,gpios\0">>, index => 15};
pin(grisp2, led1_r) -> #{path => <<"/leds/grisp-rgb1-red\0">>, property => <<"gpios\0">>, index => 0};
pin(grisp2, led1_g) -> #{path => <<"/leds/grisp-rgb1-green\0">>, property => <<"gpios\0">>, index => 0};
pin(grisp2, led1_b) -> #{path => <<"/leds/grisp-rgb1-blue\0">>, property => <<"gpios\0">>, index => 0};
pin(grisp2, led2_r) -> #{path => <<"/leds/grisp-rgb2-red\0">>, property => <<"gpios\0">>, index => 0};
pin(grisp2, led2_g) -> #{path => <<"/leds/grisp-rgb2-green\0">>, property => <<"gpios\0">>, index => 0};
pin(grisp2, led2_b) -> #{path => <<"/leds/grisp-rgb2-blue\0">>, property => <<"gpios\0">>, index => 0};
pin(grisp2, jumper_1) -> #{path => <<"/jumper-keys\0">>, property => <<"grisp,gpios\0">>, index => 0};
pin(grisp2, jumper_2) -> #{path => <<"/jumper-keys\0">>, property => <<"grisp,gpios\0">>, index => 1};
pin(grisp2, jumper_3) -> #{path => <<"/jumper-keys\0">>, property => <<"grisp,gpios\0">>, index => 2};
pin(grisp2, jumper_4) -> #{path => <<"/jumper-keys\0">>, property => <<"grisp,gpios\0">>, index => 3};
pin(grisp2, jumper_5) -> #{path => <<"/jumper-keys\0">>, property => <<"grisp,gpios\0">>, index => 4};
pin(Platform, Pin) ->
error({unknown_pin, Platform, Pin}).