migrate to local environment #39

Merged
james merged 17 commits from chore/migrate-to-local into main 2023-11-24 20:15:54 +13:00
22 changed files with 523 additions and 425 deletions

5
.check.exs Normal file
View file

@ -0,0 +1,5 @@
[
tools: [
{:sobelow, false}
]
]

View file

@ -1,164 +0,0 @@
# This file contains the configuration for Credo and you are probably reading
# this after creating it with `mix credo.gen.config`.
#
# If you find anything wrong or unclear in this file, please report an
# issue on GitHub: https://github.com/rrrene/credo/issues
#
%{
#
# You can have as many configs as you like in the `configs:` field.
configs: [
%{
#
# Run any exec using `mix credo -C <name>`. If no exec name is given
# "default" is used.
#
name: "default",
#
# These are the files included in the analysis:
files: %{
#
# You can give explicit globs or simply directories.
# In the latter case `**/*.{ex,exs}` will be used.
#
included: ["lib/", "src/", "test/", "web/", "apps/"],
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
},
#
# Load and configure plugins here:
#
plugins: [],
#
# If you create your own checks, you must specify the source files for
# them here, so they can be loaded by Credo before running the analysis.
#
requires: [],
#
# If you want to enforce a style guide and need a more traditional linting
# experience, you can change `strict` to `true` below:
#
strict: false,
#
# If you want to use uncolored output by default, you can change `color`
# to `false` below:
#
color: true,
#
# You can customize the parameters of any check by adding a second element
# to the tuple.
#
# To disable a check put `false` as second element:
#
# {Credo.Check.Design.DuplicatedCode, false}
#
checks: [
#
## Consistency Checks
#
{Credo.Check.Consistency.ExceptionNames, []},
{Credo.Check.Consistency.LineEndings, []},
{Credo.Check.Consistency.ParameterPatternMatching, []},
{Credo.Check.Consistency.SpaceAroundOperators, false},
{Credo.Check.Consistency.SpaceInParentheses, []},
{Credo.Check.Consistency.TabsOrSpaces, []},
#
## Design Checks
#
# You can customize the priority of any check
# Priority values are: `low, normal, high, higher`
#
{Credo.Check.Design.AliasUsage,
[priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
# You can also customize the exit_status of each check.
# If you don't want TODO comments to cause `mix credo` to fail, just
# set this value to 0 (zero).
#
{Credo.Check.Design.TagTODO, [exit_status: 2]},
{Credo.Check.Design.TagFIXME, []},
#
## Readability Checks
#
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
{Credo.Check.Readability.ParenthesesInCondition, []},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
{Credo.Check.Readability.PredicateFunctionNames, []},
{Credo.Check.Readability.PreferImplicitTry, []},
{Credo.Check.Readability.RedundantBlankLines, []},
{Credo.Check.Readability.Semicolons, []},
{Credo.Check.Readability.SpaceAfterCommas, []},
{Credo.Check.Readability.StringSigils, []},
{Credo.Check.Readability.TrailingBlankLine, []},
{Credo.Check.Readability.TrailingWhiteSpace, []},
# TODO: enable by default in Credo 1.1
{Credo.Check.Readability.UnnecessaryAliasExpansion, false},
{Credo.Check.Readability.VariableNames, []},
#
## Refactoring Opportunities
#
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MapInto, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, []},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.WithClauses, []},
#
## Warnings
#
{Credo.Check.Warning.BoolOperationOnSameValues, []},
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.LazyLogging, []},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
{Credo.Check.Warning.UnusedEnumOperation, []},
{Credo.Check.Warning.UnusedFileOperation, []},
{Credo.Check.Warning.UnusedKeywordOperation, []},
{Credo.Check.Warning.UnusedListOperation, []},
{Credo.Check.Warning.UnusedPathOperation, []},
{Credo.Check.Warning.UnusedRegexOperation, []},
{Credo.Check.Warning.UnusedStringOperation, []},
{Credo.Check.Warning.UnusedTupleOperation, []},
#
# Controversial and experimental checks (opt-in, just replace `false` with `[]`)
#
{Credo.Check.Consistency.MultiAliasImportRequireUse, false},
{Credo.Check.Consistency.UnusedVariableNames, false},
{Credo.Check.Design.DuplicatedCode, false},
{Credo.Check.Readability.AliasAs, false},
{Credo.Check.Readability.MultiAlias, false},
{Credo.Check.Readability.Specs, false},
{Credo.Check.Readability.SinglePipe, false},
{Credo.Check.Refactor.ABCSize, false},
{Credo.Check.Refactor.AppendSingleItem, false},
{Credo.Check.Refactor.DoubleBooleanNegation, false},
{Credo.Check.Refactor.ModuleDependencies, false},
{Credo.Check.Refactor.PipeChainStart, false},
{Credo.Check.Refactor.VariableRebinding, false},
{Credo.Check.Warning.MapGetUnsafePass, false},
{Credo.Check.Warning.UnsafeToAtom, false}
#
# Custom checks can be created using `mix credo.gen.check`.
#
]
}
]
}

15
.doctor.exs Normal file
View file

@ -0,0 +1,15 @@
%Doctor.Config{
ignore_modules: [Wafer.Registers],
ignore_paths: [],
min_module_doc_coverage: 40,
min_module_spec_coverage: 0,
min_overall_doc_coverage: 50,
min_overall_moduledoc_coverage: 100,
min_overall_spec_coverage: 0,
exception_moduledoc_required: true,
raise: false,
reporter: Doctor.Reporters.Full,
struct_type_spec_required: true,
umbrella: false,
failed: false
}

389
.drone.yml Normal file
View file

@ -0,0 +1,389 @@
kind: pipeline
type: docker
name: build
platform:
os: linux
arch: arm64
steps:
- name: restore ASDF cache
image: meltwater/drone-cache
pull: "always"
environment:
AWS_ACCESS_KEY_ID:
from_secret: ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: SECRET_ACCESS_KEY
AWS_PLUGIN_PATH_STYLE: true
settings:
restore: true
endpoint:
from_secret: S3_ENDPOINT
bucket:
from_secret: CACHE_BUCKET
region: us-east-1
path-style: true
cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}'
mount:
- .asdf
- name: restore build cache
image: meltwater/drone-cache
environment:
AWS_ACCESS_KEY_ID:
from_secret: ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: SECRET_ACCESS_KEY
AWS_PLUGIN_PATH_STYLE: true
settings:
restore: true
endpoint:
from_secret: S3_ENDPOINT
bucket:
from_secret: CACHE_BUCKET
region: us-east-1
path-style: true
cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}'
mount:
- deps
- _build
- .hex
- .mix
- .rebar3
- name: install dependencies
image: code.harton.nz/james/asdf_container:latest
pull: "always"
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
ASDF_DIR: /root/.asdf
depends_on:
- restore ASDF cache
- restore build cache
commands:
- asdf_install
- rm -rf .asdf/downloads
- . $ASDF_DIR/asdf.sh
- mix local.hex --if-missing --force
- mix local.rebar --if-missing --force
- mix deps.get
- mix deps.compile
- mix dialyzer --plt
- name: store ASDF cache
image: meltwater/drone-cache
environment:
AWS_ACCESS_KEY_ID:
from_secret: ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: SECRET_ACCESS_KEY
AWS_PLUGIN_PATH_STYLE: true
depends_on:
- install dependencies
settings:
rebuild: true
override: false
endpoint:
from_secret: S3_ENDPOINT
bucket:
from_secret: CACHE_BUCKET
region: us-east-1
path-style: true
cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}'
mount:
- .asdf
- name: store build cache
image: meltwater/drone-cache
environment:
AWS_ACCESS_KEY_ID:
from_secret: ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: SECRET_ACCESS_KEY
AWS_PLUGIN_PATH_STYLE: true
depends_on:
- install dependencies
settings:
rebuild: true
override: false
endpoint:
from_secret: S3_ENDPOINT
bucket:
from_secret: CACHE_BUCKET
region: us-east-1
path-style: true
cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}'
mount:
- deps
- _build
- .hex
- .mix
- .rebar3
- name: mix compile
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- install dependencies
commands:
- asdf mix compile --warnings-as-errors
- name: mix test
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- asdf mix test
- name: mix test.sense_hat
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
SENSE_HAT_PRESENT: true
privileged: true
depends_on:
- mix compile
commands:
- asdf mix test
- name: mix credo
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- asdf mix credo --strict
- name: mix hex.audit
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- asdf mix hex.audit
- name: mix format
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- asdf mix format --check-formatted
- name: mix deps.unlock
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- asdf mix deps.unlock --check-unused
- name: mix doctor
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- asdf mix doctor --full
- name: mix git_ops.check_message
image: code.harton.nz/james/asdf_container:latest
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
depends_on:
- mix compile
commands:
- git log -1 --format=%s > .last_commit_message
- asdf mix git_ops.check_message .last_commit_message
- name: mix git_ops.release
image: code.harton.nz/james/asdf_container:latest
when:
branch:
- main
event:
exclude:
- pull_request
depends_on:
- mix test
- mix credo
- mix hex.audit
- mix format
- mix test.sense_hat
- mix deps.unlock
- mix doctor
- mix git_ops.check_message
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
ASDF_DIR: /root/.asdf
DRONE_TOKEN:
from_secret: DRONE_TOKEN
commands:
- git fetch --tags
- . $ASDF_DIR/asdf.sh
- mix git_ops.project_info --format=shell > before.env
- mix git_ops.release --yes --no-major || true
- mix git_ops.project_info --format=shell > after.env
- . ./before.env
- export OLD_APP_VERSION=$${APP_VERSION}
- . ./after.env
- export NEW_APP_VERSION=$${APP_VERSION}
- if [ "v$${OLD_APP_VERSION}" != "v$${NEW_APP_VERSION}" ]; then
- export GIT_URL=$(echo $DRONE_GIT_HTTP_URL | sed -e "s/:\\/\\//:\\/\\/$DRONE_REPO_OWNER:$DRONE_TOKEN@/")
- git push $${GIT_URL} "HEAD:${DRONE_COMMIT_REF}" "refs/tags/v$${NEW_APP_VERSION}"
- fi
- name: build artifacts
image: code.harton.nz/james/asdf_container:latest
when:
event:
- tag
refs:
include:
- refs/tags/v*
depends_on:
- mix test
- mix credo
- mix hex.audit
- mix format
- mix test.sense_hat
- mix deps.unlock
- mix doctor
- mix git_ops.check_message
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
ASDF_DIR: /root/.asdf
commands:
- . $ASDF_DIR/asdf.sh
- mix git_ops.project_info --format=shell > app.env
- . ./app.env
- mkdir artifacts
- mix hex.build -o "artifacts/$${APP_NAME}-$${APP_VERSION}-pkg.tar"
- gzip "artifacts/$${APP_NAME}-$${APP_VERSION}-pkg.tar"
- mix docs
- tar zcvf "artifacts/$${APP_NAME}-$${APP_VERSION}-docs.tar.gz" doc/
- git tag -l --format='%(contents:subject)' v$${APP_VERSION} > tag_subject
- git tag -l --format='%(contents:body)' v$${APP_VERSION} > tag_body
- name: gitea release
image: plugins/gitea-release
when:
event:
- tag
refs:
include:
- refs/tags/v*
depends_on:
- build artifacts
settings:
api_key:
from_secret: DRONE_TOKEN
base_url: https://code.harton.nz
files: artifacts/*.tar.gz
checksum: sha256
title: tag_subject
note: tag_body
- name: docs release
when:
event:
- tag
refs:
include:
- refs/tags/v*
image: minio/mc
environment:
S3_ENDPOINT:
from_secret: S3_ENDPOINT
ACCESS_KEY:
from_secret: ACCESS_KEY_ID
SECRET_KEY:
from_secret: SECRET_ACCESS_KEY
depends_on:
- build artifacts
commands:
- mc alias set store $${S3_ENDPOINT} $${ACCESS_KEY} $${SECRET_KEY}
- mc mb -p store/docs.harton.nz
- mc anonymous set download store/docs.harton.nz
- mc mirror --overwrite doc/ store/docs.harton.nz/$${DRONE_REPO}/$${DRONE_TAG}
- mc mirror --overwrite doc/ store/docs.harton.nz/$${DRONE_REPO}
- name: hex release
image: code.harton.nz/james/asdf_container:latest
when:
event:
- tag
refs:
include:
- refs/tags/v*
depends_on:
- build artifacts
environment:
MIX_ENV: test
HEX_HOME: /drone/src/.hex
MIX_HOME: /drone/src/.mix
REBAR_BASE_DIR: /drone/src/.rebar3
ASDF_DATA_DIR: /drone/src/.asdf
ASDF_DIR: /root/.asdf
HEX_API_KEY:
from_secret: HEX_API_KEY
commands:
- . $ASDF_DIR/asdf.sh
- mix hex.publish --yes

View file

@ -1,177 +0,0 @@
image: elixir:latest
stages:
- build
- test
- release
variables:
MIX_ENV: "test"
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/"
HEX_HOME: "$CI_PROJECT_DIR/.hex"
MIX_HOME: "$CI_PROJECT_DIR/.mix"
build:
image: elixir:latest
stage: build
cache:
key: "$CI_JOB_NAME"
paths:
- deps
- _build
- .hex
- .mix
script:
- mix local.hex --force
- mix local.rebar --force
- mix deps.get
- mix deps.compile
- mix git_ops.project_info -f dotenv > project_info.env
artifacts:
paths:
- _build/
- deps/
- .hex
- .mix
reports:
dotenv: project_info.env
test:
image: elixir:latest
dependencies:
- build
stage: test
script:
- mix test
build_and_test_i2c_1_x:
image: elixir:latest
stage: test
cache:
key: "$CI_JOB_NAME"
paths:
- deps
- _build
- .hex
- .mix
script:
- mix local.hex --force
- mix local.rebar --force
- CI_I2C_1_X=true mix deps.get
- mix deps.compile
- mix test
artifacts:
paths:
- _build/
- deps/
- .hex
- .mix
integrate:
image: elixir:latest
stage: test
tags:
- sense-hat
script:
- mix local.hex --force
- mix local.rebar --force
- rm -rf deps _build
- mix deps.get
- mix deps.compile
- SENSE_HAT_PRESENT=true mix test
credo:
image: elixir:latest
dependencies:
- build
stage: test
script:
- mix credo
audit:
image: elixir:latest
dependencies:
- build
stage: test
script:
- mix hex.audit
format:
image: elixir:latest
dependencies:
- build
stage: test
script:
- mix format --check-formatted
pages:
image: elixir:latest
dependencies:
- build
stage: release
script:
- mix docs -o public
artifacts:
paths:
- public
only:
- main
git_ops:
image: elixir:latest
dependencies:
- build
stage: release
only:
refs:
- main
except:
variables:
- $CI_COMMIT_MESSAGE =~ /chore\:\ release version/
script:
- |
export OLD_APP_VERSION=$APP_VERSION
mkdir -p artifacts
git config --global user.name "Gitlab Runner for ${GITLAB_USER_NAME}"
git config --global user.email "${GITLAB_USER_EMAIL}"
mix git_ops.release --yes || true
mix git_ops.project_info -f shell > artifacts/env
source artifacts/env
if [ "v${OLD_APP_VERSION}" != "v${APP_VERSION}" ]; then
mix hex.build -o "artifacts/${APP_NAME}-${APP_VERSION}.tar"
gzip "artifacts/${APP_NAME}-${APP_VERSION}.tar"
mix docs && tar zcvf "artifacts/${APP_NAME}-${APP_VERSION}-docs.tar.gz" doc/
curl --header "JOB_TOKEN: ${CI_JOB_TOKEN}" --upload-file "artifacts/${APP_NAME}-${APP_VERSION}.tar.gz" "${PACKAGE_REGISTRY_URL}/${APP_NAME}/${APP_VERSION}/${APP_NAME}-${APP_VERSION}.tar.gz"
curl --header "JOB_TOKEN: ${CI_JOB_TOKEN}" --upload-file "artifacts/${APP_NAME}-${APP_VERSION}-docs.tar.gz" "${PACKAGE_REGISTRY_URL}/${APP_NAME}/${APP_VERSION}/${APP_NAME}-${APP_VERSION}-docs.tar.gz"
git push "https://project_${CI_PROJECT_ID}_bot:${RELEASE_TOKEN}@gitlab.com/${CI_PROJECT_PATH}.git" "HEAD:${CI_COMMIT_REF_NAME}" "refs/tags/v${APP_VERSION}"
fi
artifacts:
paths:
- artifacts/*
release-gitlab:
image: registry.gitlab.com/gitlab-org/release-cli:latest
dependencies:
- build
stage: release
only:
- tags
- /^v\d+\.\d+\.\d+(-\w+)?$/
script:
- release-cli create \
--name "Release ${APP_NAME} ${APP_VERSION}" \
--description "./CHANGELOG.md" \
--tag-name "v${APP_VERSION}" \
--assets-link "{\"name\":\"${APP_NAME}-${APP_VERSION}.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/${APP_NAME}/${APP_VERSION}/${APP_NAME}-${APP_VERSION}.tar.gz\"}" \
--assets-link "{\"name\":\"${APP_NAME}-${APP_VERSION}-docs.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/${APP_NAME}/${APP_VERSION}/${APP_NAME}-${APP_VERSION}-docs.tar.gz\"}"
release-hex:
image: elixir:latest
dependencies:
- build
stage: release
only:
- tags
- /^v\d+\.\d+\.\d+(-\w+)?$/
script:
- mix hex.publish --yes

2
.tool-versions Normal file
View file

@ -0,0 +1,2 @@
erlang 26.1.2
elixir 1.15.7

View file

@ -1,6 +1,6 @@
# Wafer # Wafer
[![pipeline status](https://gitlab.com/jimsy/wafer/badges/main/pipeline.svg)](https://gitlab.com/jimsy/wafer/commits/main) [![Build Status](https://drone.harton.nz/api/badges/james/wafer/status.svg?ref=refs/heads/main)](https://drone.harton.nz/james/wafer)
[![Hex.pm](https://img.shields.io/hexpm/v/wafer.svg)](https://hex.pm/packages/wafer) [![Hex.pm](https://img.shields.io/hexpm/v/wafer.svg)](https://hex.pm/packages/wafer)
[![Hippocratic License HL3-FULL](https://img.shields.io/static/v1?label=Hippocratic%20License&message=HL3-FULL&labelColor=5e2751&color=bc8c3d)](https://firstdonoharm.dev/version/3/0/full.html) [![Hippocratic License HL3-FULL](https://img.shields.io/static/v1?label=Hippocratic%20License&message=HL3-FULL&labelColor=5e2751&color=bc8c3d)](https://firstdonoharm.dev/version/3/0/full.html)
@ -8,13 +8,14 @@ Wafer is an OTP application that assists with writing drivers for peripherals us
Wafer provides Elixir protocols for interacting with device registers and dealing with GPIO, so that you can use directly connected hardware GPIO pins or GPIO expanders such as the [MCP23008](https://www.microchip.com/wwwproducts/en/MCP23008) or the [CD74HC595](http://www.ti.com/product/CD74HC595) SPI shift register. Wafer provides Elixir protocols for interacting with device registers and dealing with GPIO, so that you can use directly connected hardware GPIO pins or GPIO expanders such as the [MCP23008](https://www.microchip.com/wwwproducts/en/MCP23008) or the [CD74HC595](http://www.ti.com/product/CD74HC595) SPI shift register.
Wafer implements the [GPIO](https://hexdocs.pm/wafer/Wafer.GPIOProto.html) and [Chip](https://hexdocs.pm/wafer/Wafer.Chip.html) protocols for [ElixirALE](https://hex.pm/packages/elixir_ale)'s GPIO and I2C drivers, [Circuits.GPIO](https://hex.pm/packages/circuits_gpio) and [Circuits.I2C](https://hex.pm/packages/circuits_i2c). Implementing it for SPI should also be trivial, I just don't have any SPI devices to test with at the moment. Wafer implements the [GPIO](https://hexdocs.pm/wafer/Wafer.GPIOProto.html) and [Chip](https://hexdocs.pm/wafer/Wafer.Chip.html) protocols for [ElixirALE](https://hex.pm/packages/elixir_ale)'s GPIO and I2C drivers, [Circuits.GPIO](https://hex.pm/packages/circuits_gpio) and [Circuits.I2C](https://hex.pm/packages/circuits_i2c). Implementing it for SPI should also be trivial, I just don't have any SPI devices to test with at the moment.
Documentation for the main branch can always be found [here](https://jimsy.gitlab.io/wafer/). Documentation for the main branch can always be found [here](https://docs.harton.nz/james/wafer/).
Some examples of how to use this project: Some examples of how to use this project:
- [Augie](https://gitlab.com/jimsy/augie), a hexapod robot.
- [PCA9641](https://gitlab.com/jimsy/pca9641), an example of how easy it is to write a driver with Wafer. - [Augie](https://gitlab.com/jimsy/augie), a hexapod robot.
- [PCA9641](https://gitlab.com/jimsy/pca9641), an example of how easy it is to write a driver with Wafer.
## Working with registers ## Working with registers
@ -113,7 +114,7 @@ end
I've included stub implementations of the parts of `ElixirALE` and `Circuits` I've included stub implementations of the parts of `ElixirALE` and `Circuits`
that are interacted with by this project, so the tests should run and pass on that are interacted with by this project, so the tests should run and pass on
machines without physical hardware interfaces. If you have a Raspberry Pi with machines without physical hardware interfaces. If you have a Raspberry Pi with
a Pi Sense Hat connected you can run the tests with the `SENSE_HAT_PRESENT=true` a Pi Sense Hat connected you can run the tests with the `SENSE_HAT_PRESENT=true`
environment variable set and it will perform integration tests with two of the environment variable set and it will perform integration tests with two of the
sensors on this device. sensors on this device.
@ -135,6 +136,10 @@ Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_do
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/wafer](https://hexdocs.pm/wafer). be found at [https://hexdocs.pm/wafer](https://hexdocs.pm/wafer).
## Gitlab Mirror
This repository is mirrored [on Gitlab](https://gitlab.com/jimsy/wafer) from it's primary location [on my Forgejo instance](https://code.harton.nz/james/smokestack). Feel free to raise issues and open PRs on Gitlab.
## License ## License
This software is licensed under the terms of the This software is licensed under the terms of the
@ -142,7 +147,7 @@ This software is licensed under the terms of the
this package for the terms. this package for the terms.
This license actively proscribes this software being used by and for some This license actively proscribes this software being used by and for some
industries, countries and activities. If your usage of this software doesn't industries, countries and activities. If your usage of this software doesn't
comply with the terms of this license, then [contact me](mailto:james@harton.nz) comply with the terms of this license, then [contact me](mailto:james@harton.nz)
with the details of your use-case to organise the purchase of a license - the with the details of your use-case to organise the purchase of a license - the
cost of which may include a donation to a suitable charity or NGO. cost of which may include a donation to a suitable charity or NGO.

View file

@ -5,6 +5,7 @@ defmodule Wafer.Application do
use Application use Application
@doc false
def start(_type, _args) do def start(_type, _args) do
children = [ children = [
{Registry, [keys: :duplicate, name: Wafer.InterruptRegistry]}, {Registry, [keys: :duplicate, name: Wafer.InterruptRegistry]},

View file

@ -57,11 +57,11 @@ defimpl Wafer.GPIO, for: Wafer.Driver.Circuits.GPIO do
import Wafer.Guards import Wafer.Guards
def read(%{ref: ref}) when is_reference(ref) do def read(%{ref: ref}) when is_reference(ref) do
case(Wrapper.read(ref)) do case Wrapper.read(ref) do
value when is_pin_value(value) -> {:ok, value} value when is_pin_value(value) -> {:ok, value}
{:error, reason} -> {:error, reason}
other -> {:error, "Invalid response from driver: #{inspect(other)}"}
end end
rescue
error -> {:error, error}
end end
def write(%{ref: ref} = conn, value) when is_reference(ref) and is_pin_value(value) do def write(%{ref: ref} = conn, value) when is_reference(ref) and is_pin_value(value) do
@ -80,11 +80,11 @@ defimpl Wafer.GPIO, for: Wafer.Driver.Circuits.GPIO do
def enable_interrupt(conn, pin_condition, metadata \\ nil) def enable_interrupt(conn, pin_condition, metadata \\ nil)
when is_pin_condition(pin_condition) do when is_pin_condition(pin_condition) do
with :ok <- Dispatcher.enable(conn, pin_condition, metadata), do: {:ok, conn} Dispatcher.enable(conn, pin_condition, metadata)
end end
def disable_interrupt(conn, pin_condition) when is_pin_condition(pin_condition) do def disable_interrupt(conn, pin_condition) when is_pin_condition(pin_condition) do
with :ok <- Dispatcher.disable(conn, pin_condition), do: {:ok, conn} Dispatcher.disable(conn, pin_condition)
end end
def pull_mode(%{ref: ref} = conn, mode) when is_reference(ref) and is_pin_pull_mode(mode) do def pull_mode(%{ref: ref} = conn, mode) when is_reference(ref) and is_pin_pull_mode(mode) do

View file

@ -1,7 +1,7 @@
defmodule Wafer.Driver.Circuits.I2C do defmodule Wafer.Driver.Circuits.I2C do
defstruct ~w[address bus ref]a defstruct ~w[address bus conn]a
@behaviour Wafer.Conn @behaviour Wafer.Conn
alias Circuits.I2C.I2CDev alias Circuits.I2C.Bus
alias Wafer.Driver.Circuits.I2C.Wrapper alias Wafer.Driver.Circuits.I2C.Wrapper
alias Wafer.I2C alias Wafer.I2C
import Wafer.Guards import Wafer.Guards
@ -12,7 +12,7 @@ defmodule Wafer.Driver.Circuits.I2C do
Implements the `Wafer.Conn` behaviour as well as the `Wafer.Chip` and `Wafer.I2C` protocols. Implements the `Wafer.Conn` behaviour as well as the `Wafer.Chip` and `Wafer.I2C` protocols.
""" """
@type t :: %__MODULE__{address: I2C.address(), bus: binary, ref: reference} @type t :: %__MODULE__{address: I2C.address(), bus: binary, conn: Bus.t()}
@type options :: [option] @type options :: [option]
@type option :: {:bus_name, binary} | {:address, I2C.address()} | {:force, boolean} @type option :: {:bus_name, binary} | {:address, I2C.address()} | {:force, boolean}
@ -24,10 +24,10 @@ defmodule Wafer.Driver.Circuits.I2C do
def acquire(opts) when is_list(opts) do def acquire(opts) when is_list(opts) do
with {:ok, bus} when is_binary(bus) <- Keyword.fetch(opts, :bus_name), with {:ok, bus} when is_binary(bus) <- Keyword.fetch(opts, :bus_name),
{:ok, address} when is_i2c_address(address) <- Keyword.fetch(opts, :address), {:ok, address} when is_i2c_address(address) <- Keyword.fetch(opts, :address),
{:ok, ref} when is_reference(ref) or is_struct(ref, I2CDev) <- Wrapper.open(bus), {:ok, conn} <- Wrapper.open(bus),
devices when is_list(devices) <- Wrapper.detect_devices(ref), devices when is_list(devices) <- Wrapper.detect_devices(conn),
true <- Keyword.get(opts, :force, false) || Enum.member?(devices, address) do true <- Keyword.get(opts, :force, false) || Enum.member?(devices, address) do
{:ok, %__MODULE__{bus: bus, address: address, ref: ref}} {:ok, %__MODULE__{bus: bus, address: address, conn: conn}}
else else
false -> false ->
{:error, "No device detected at address. Pass `force: true` to override."} {:error, "No device detected at address. Pass `force: true` to override."}
@ -49,24 +49,24 @@ defimpl Wafer.Release, for: Wafer.Driver.Circuits.I2C do
Release all resources associated with this device. Release all resources associated with this device.
""" """
@spec release(I2C.t()) :: :ok | {:error, reason :: any} @spec release(I2C.t()) :: :ok | {:error, reason :: any}
def release(%I2C{ref: ref} = _conn), do: Wrapper.close(ref) def release(%I2C{conn: conn} = _conn), do: Wrapper.close(conn)
end end
defimpl Wafer.Chip, for: Wafer.Driver.Circuits.I2C do defimpl Wafer.Chip, for: Wafer.Driver.Circuits.I2C do
alias Wafer.Driver.Circuits.I2C.Wrapper alias Wafer.Driver.Circuits.I2C.Wrapper
import Wafer.Guards import Wafer.Guards
def read_register(%{ref: ref, address: address}, register_address, bytes) def read_register(%{conn: conn, address: address}, register_address, bytes)
when is_i2c_address(address) and is_register_address(register_address) and when is_i2c_address(address) and is_register_address(register_address) and
is_byte_size(bytes), is_byte_size(bytes),
do: Wrapper.write_read(ref, address, <<register_address>>, bytes) do: Wrapper.write_read(conn, address, <<register_address>>, bytes)
def read_register(_conn, _register_address, _bytes), do: {:error, "Invalid argument"} def read_register(_conn, _register_address, _bytes), do: {:error, "Invalid argument"}
def write_register(%{ref: ref, address: address} = conn, register_address, data) def write_register(%{conn: inner, address: address} = conn, register_address, data)
when is_i2c_address(address) and is_register_address(register_address) and when is_i2c_address(address) and is_register_address(register_address) and
is_binary(data) do is_binary(data) do
with :ok <- Wrapper.write(ref, address, <<register_address, data::binary>>), do: {:ok, conn} with :ok <- Wrapper.write(inner, address, <<register_address, data::binary>>), do: {:ok, conn}
end end
def write_register(_conn, _register_address, _data), do: {:error, "Invalid argument"} def write_register(_conn, _register_address, _data), do: {:error, "Invalid argument"}
@ -86,36 +86,35 @@ defimpl Wafer.I2C, for: Wafer.Driver.Circuits.I2C do
import Wafer.Guards import Wafer.Guards
alias Wafer.Driver.Circuits.I2C.Wrapper alias Wafer.Driver.Circuits.I2C.Wrapper
def read(%{ref: ref, address: address}, bytes, options \\ []) def read(%{conn: conn, address: address}, bytes, options \\ [])
when is_i2c_address(address) and is_byte_size(bytes) and when is_i2c_address(address) and is_byte_size(bytes) and
is_list(options) do is_list(options) do
case Wrapper.read(ref, address, bytes, options) do case Wrapper.read(conn, address, bytes, options) do
{:ok, data} when is_binary(data) and byte_size(data) == bytes -> {:ok, data} {:ok, data} when is_binary(data) and byte_size(data) == bytes -> {:ok, data}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
other -> {:error, "Invalid response from driver: #{inspect(other)}"} other -> {:error, "Invalid response from driver: #{inspect(other)}"}
end end
end end
def write(%{ref: ref, address: address} = conn, data, options \\ []) def write(%{conn: inner, address: address} = conn, data, options \\ [])
when is_i2c_address(address) and is_binary(data) and is_list(options) do when is_i2c_address(address) and is_binary(data) and is_list(options) do
with :ok <- Wrapper.write(ref, address, data, options), do: {:ok, conn} with :ok <- Wrapper.write(inner, address, data, options), do: {:ok, conn}
end end
def write_read(%{ref: ref, address: address} = conn, data, bytes, options \\ []) def write_read(%{conn: inner, address: address} = conn, data, bytes, options \\ [])
when is_i2c_address(address) and is_binary(data) and when is_i2c_address(address) and is_binary(data) and
is_byte_size(bytes) and is_list(options) do is_byte_size(bytes) and is_list(options) do
case Wrapper.write_read(ref, address, data, bytes, options) do case Wrapper.write_read(inner, address, data, bytes, options) do
{:ok, data} when is_binary(data) and byte_size(data) == bytes -> {:ok, data, conn} {:ok, data} when is_binary(data) and byte_size(data) == bytes -> {:ok, data, conn}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
other -> {:error, "Invalid response from driver: #{inspect(other)}"} other -> {:error, "Invalid response from driver: #{inspect(other)}"}
end end
end end
def detect_devices(%{ref: ref}) when is_reference(ref) do def detect_devices(%{conn: conn}) do
case Wrapper.detect_devices(ref) do case Wrapper.detect_devices(conn) do
devices when is_list(devices) -> {:ok, devices} devices when is_list(devices) -> {:ok, devices}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
other -> {:error, "Invalid response from driver: #{inspect(other)}"}
end end
end end
end end

View file

@ -115,7 +115,6 @@ defimpl Wafer.I2C, for: Wafer.Driver.ElixirALE.I2C do
case Wrapper.detect_devices(pid) do case Wrapper.detect_devices(pid) do
devices when is_list(devices) -> {:ok, devices} devices when is_list(devices) -> {:ok, devices}
{:error, reason} -> {:error, reason} {:error, reason} -> {:error, reason}
other -> {:error, "Invalid response from driver: #{inspect(other)}"}
end end
end end
end end

View file

@ -35,5 +35,5 @@ defmodule Wafer.Driver.ElixirALE.I2C.Wrapper do
defdelegate write_read(pid, write_data, read_count), to: ElixirALE.I2C defdelegate write_read(pid, write_data, read_count), to: ElixirALE.I2C
@compile {:no_warn_undefined, ElixirALE.I2C} @compile {:no_warn_undefined, ElixirALE.I2C}
defdelegate write_read_device(pid, address, write_data, read_count), to: ElixirALE defdelegate write_read_device(pid, address, write_data, read_count), to: ElixirALE.I2C
end end

View file

@ -14,6 +14,9 @@ defmodule Wafer.Driver.Fake do
protocols. protocols.
""" """
@type t :: %__MODULE__{opts: any}
@doc false
@impl Wafer.Conn @impl Wafer.Conn
def acquire(opts) do def acquire(opts) do
if emit_warning(), if emit_warning(),
@ -87,7 +90,7 @@ defimpl Wafer.I2C, for: Wafer.Driver.Fake do
{:ok, <<0::size(bits)>>, conn} {:ok, <<0::size(bits)>>, conn}
end end
def detect_devices(_conn), do: [] def detect_devices(_conn), do: {:ok, []}
end end
defimpl Wafer.SPI, for: Wafer.Driver.Fake do defimpl Wafer.SPI, for: Wafer.Driver.Fake do

View file

@ -63,7 +63,7 @@ defprotocol Wafer.I2C do
@doc """ @doc """
Detect the devices adjacent to the connection's device on the same I2C bus. Detect the devices adjacent to the connection's device on the same I2C bus.
""" """
@spec detect_devices(Conn.t()) :: {:ok, [address]} @spec detect_devices(Conn.t()) :: {:ok, [address]} | {:error, any}
def detect_devices(conn) def detect_devices(conn)
end end

View file

@ -1,4 +1,3 @@
# credo:disable-for-this-file
defmodule Wafer.Registers do defmodule Wafer.Registers do
@moduledoc """ @moduledoc """
This module provides helpful macros for specifying the registers used to This module provides helpful macros for specifying the registers used to
@ -16,6 +15,7 @@ defmodule Wafer.Registers do
@type access_mode :: :ro | :rw | :wo @type access_mode :: :ro | :rw | :wo
@type bytes :: non_neg_integer @type bytes :: non_neg_integer
@doc false
defmacro __using__(_opts) do defmacro __using__(_opts) do
quote do quote do
import Wafer.Registers import Wafer.Registers
@ -101,7 +101,7 @@ defmodule Wafer.Registers do
defmacro defregister(name, register_address, :ro, bytes) defmacro defregister(name, register_address, :ro, bytes)
when is_atom(name) and is_integer(register_address) and register_address >= 0 and when is_atom(name) and is_integer(register_address) and register_address >= 0 and
is_integer(bytes) and bytes >= 0 do is_integer(bytes) and bytes >= 0 do
empty_bytes = 1..bytes |> Enum.map(fn _ -> 0 end) |> Enum.join(", ") empty_bytes = 1..bytes |> Enum.map_join(", ", fn _ -> 0 end)
quote do quote do
@doc """ @doc """
@ -121,7 +121,7 @@ defmodule Wafer.Registers do
defmacro defregister(name, register_address, :wo, bytes) defmacro defregister(name, register_address, :wo, bytes)
when is_atom(name) and is_integer(register_address) and register_address >= 0 and when is_atom(name) and is_integer(register_address) and register_address >= 0 and
is_integer(bytes) and bytes >= 0 do is_integer(bytes) and bytes >= 0 do
empty_bytes = 1..bytes |> Enum.map(fn _ -> 0 end) |> Enum.join(", ") empty_bytes = 1..bytes |> Enum.map_join(", ", fn _ -> 0 end)
quote do quote do
@doc """ @doc """
@ -142,10 +142,11 @@ defmodule Wafer.Registers do
end end
end end
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
defmacro defregister(name, register_address, :rw, bytes) defmacro defregister(name, register_address, :rw, bytes)
when is_atom(name) and is_integer(register_address) and register_address >= 0 and when is_atom(name) and is_integer(register_address) and register_address >= 0 and
is_integer(bytes) and bytes >= 0 do is_integer(bytes) and bytes >= 0 do
empty_bytes = 1..bytes |> Enum.map(fn _ -> 0 end) |> Enum.join(", ") empty_bytes = 1..bytes |> Enum.map_join(", ", fn _ -> 0 end)
bits = bytes * 8 bits = bytes * 8
quote do quote do
@ -215,8 +216,7 @@ defmodule Wafer.Registers do
Chip.read_register(conn, unquote(register_address), unquote(bytes)), Chip.read_register(conn, unquote(register_address), unquote(bytes)),
new_data when is_binary(new_data) and byte_size(new_data) == unquote(bytes) <- new_data when is_binary(new_data) and byte_size(new_data) == unquote(bytes) <-
callback.(old_data), callback.(old_data),
{:ok, conn} <- Chip.write_register(conn, unquote(register_address), new_data), do: Chip.write_register(conn, unquote(register_address), new_data)
do: {:ok, conn}
end end
def unquote(:"update_#{name}")(_conn, _callback), def unquote(:"update_#{name}")(_conn, _callback),

View file

@ -30,7 +30,7 @@ defprotocol Wafer.Release do
Release all resources associated with the connection. Usually in preparation Release all resources associated with the connection. Usually in preparation
for shutdown. for shutdown.
""" """
@spec release(Conn.t()) :: :ok @spec release(Conn.t()) :: :ok | {:error, any}
def release(conn) def release(conn)
end end

View file

@ -173,7 +173,7 @@ defmodule Wafer.Twiddles do
iex> find_ones(<<0x0A>>) iex> find_ones(<<0x0A>>)
[1, 3] [1, 3]
""" """
@spec find_ones(byte | single_byte_binary) :: non_neg_integer @spec find_ones(byte | single_byte_binary) :: [non_neg_integer]
def find_ones(byte) when is_byte(byte) do def find_ones(byte) when is_byte(byte) do
0..7 0..7
|> Enum.filter(&(get_bit(byte, &1) == 1)) |> Enum.filter(&(get_bit(byte, &1) == 1))
@ -192,7 +192,7 @@ defmodule Wafer.Twiddles do
iex> find_zeroes(<<0xFA>>) iex> find_zeroes(<<0xFA>>)
[0, 2] [0, 2]
""" """
@spec find_zeroes(byte | single_byte_binary) :: non_neg_integer @spec find_zeroes(byte | single_byte_binary) :: [non_neg_integer]
def find_zeroes(byte) when is_byte(byte) do def find_zeroes(byte) when is_byte(byte) do
0..7 0..7
|> Enum.filter(&(get_bit(byte, &1) == 0)) |> Enum.filter(&(get_bit(byte, &1) == 0))

34
mix.exs
View file

@ -18,7 +18,13 @@ defmodule Wafer.MixProject do
package: package(), package: package(),
description: @description, description: @description,
deps: deps(), deps: deps(),
consolidate_protocols: Mix.env() != :test consolidate_protocols: Mix.env() != :test,
source_url: "https://code.harton.nz/james/wafer",
homepage_url: "https://code.harton.nz/james/wafer",
docs: [
source_url_pattern: "https://code.harton.nz/james/wafer/src/branch/main/%{path}#L%{line}",
extras: ["README.md"]
]
] ]
end end
@ -35,13 +41,17 @@ defmodule Wafer.MixProject do
maintainers: ["James Harton <james@harton.nz>"], maintainers: ["James Harton <james@harton.nz>"],
licenses: ["HL3-FULL"], licenses: ["HL3-FULL"],
links: %{ links: %{
"Source" => "https://gitlab.com/jimsy/wafer" "Source" => "https://code.harton.nz/james/smokestack",
} "Gitlab Mirror" => "https://gitlab.com/jimsy/wafer"
},
source_url: "https://code.harton.nz/james/smokestack"
] ]
end end
# Run "mix help deps" to learn about dependencies. # Run "mix help deps" to learn about dependencies.
defp deps do defp deps do
devtest = [only: ~w[dev test]a, runtime: false]
[ [
{:circuits_gpio, "~> 1.0", optional: true}, {:circuits_gpio, "~> 1.0", optional: true},
if System.get_env("CI_I2C_1_X") == "true" do if System.get_env("CI_I2C_1_X") == "true" do
@ -49,13 +59,19 @@ defmodule Wafer.MixProject do
else else
{:circuits_i2c, "~> 2.0 or ~> 1.0", optional: true} {:circuits_i2c, "~> 2.0 or ~> 1.0", optional: true}
end, end,
{:circuits_spi, "~> 1.3", optional: true}, {:circuits_spi, "~> 2.0 or ~> 1.3", optional: true},
{:credo, "~> 1.6", only: ~w[dev test]a, runtime: false},
{:earmark, "~> 1.4", only: ~w[dev test]a},
{:elixir_ale, "~> 1.2", optional: true}, {:elixir_ale, "~> 1.2", optional: true},
{:ex_doc, ">= 0.28.1", only: ~w[dev test]a},
{:git_ops, "~> 2.4", only: ~w[dev test]a, runtime: false}, # Dev/test
{:mimic, "~> 1.5", only: :test} {:credo, "~> 1.6", devtest},
{:dialyxir, "~> 1.4", devtest},
{:doctor, "~> 0.21", devtest},
{:earmark, "~> 1.4", devtest},
{:ex_check, "~> 0.15", devtest},
{:ex_doc, ">= 0.0.0", devtest},
{:git_ops, "~> 2.4", devtest},
{:mimic, "~> 1.5", only: :test},
{:mix_audit, "~> 2.1", devtest}
] ]
end end
end end

View file

@ -1,21 +1,29 @@
%{ %{
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
"circuits_gpio": {:hex, :circuits_gpio, "1.0.0", "b2a493b1822ec712bfba7068a016930f6db5e31713b9b84ed8bc307c7c323682", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "da64c1d9ba1329cd7ca7e63adcd68d73e2294d6b48eb66c9a1064f3db5c523f3"}, "circuits_gpio": {:hex, :circuits_gpio, "1.1.0", "cda895fd0a12fdf50e27f6d61cc349587dff29755fca640b93233a661925d97a", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "11dab3c7b39cbe08588e9527c9fd98117be485f70b61641874abdda50340e991"},
"circuits_i2c": {:hex, :circuits_i2c, "2.0.0", "8343b12879189f844835abeaf31a36c5626b8ace58413a582794fdfe60c2dc0e", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "06eccd33b36bcedf41730cac8da58e359967ea63a2cd899cea58c2a138634cc4"}, "circuits_i2c": {:hex, :circuits_i2c, "2.0.1", "e9ab22f078b403cafd2c5006fff448f9a790f73c04e9135b7ac22f45f2e63c5c", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "a1567004389b49637fe34d9dd8bdf36c26a53c269e654753860b5c09532bc3c4"},
"circuits_spi": {:hex, :circuits_spi, "1.3.0", "d66d4c8818739416958cea1d846d66896ab7c28fa42695f1cae3c2c7a3e9e9ca", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "56e49b346fdd43185832a03d3de3751c2ce9928ee3ce4a31a364f6548fe2b74c"}, "circuits_spi": {:hex, :circuits_spi, "2.0.0", "9198c15c7ffce5bc353e13b7c82df3fe99d7332bd7c28fb9a62c60ce1e7567dc", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2eddec1fe6486a16f77f72eca91d50a806f9365033d96a517381b61d747612c2"},
"credo": {:hex, :credo, "1.6.1", "7dc76dcdb764a4316c1596804c48eada9fff44bd4b733a91ccbf0c0f368be61e", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "698607fb5993720c7e93d2d8e76f2175bba024de964e160e2f7151ef3ab82ac5"}, "credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"},
"earmark": {:hex, :earmark, "1.4.19", "3854a17305c880cc46305af15fb1630568d23a709aba21aaa996ced082fc29d7", [:mix], [{:earmark_parser, ">= 1.4.18", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d5a8c9f9e37159a8fdd3ea8437fb4e229eaf56d5129b9a011dc4780a4872079d"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"earmark_parser": {:hex, :earmark_parser, "1.4.19", "de0d033d5ff9fc396a24eadc2fcf2afa3d120841eb3f1004d138cbf9273210e8", [:mix], [], "hexpm", "527ab6630b5c75c3a3960b75844c314ec305c76d9899bb30f71cb85952a9dc45"}, "dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"},
"doctor": {:hex, :doctor, "0.21.0", "20ef89355c67778e206225fe74913e96141c4d001cb04efdeba1a2a9704f1ab5", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "a227831daa79784eb24cdeedfa403c46a4cb7d0eab0e31232ec654314447e4e0"},
"earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.38", "b42252eddf63bda05554ba8be93a1262dc0920c721f1aaf989f5de0f73a2e367", [:mix], [], "hexpm", "2cd0907795aaef0c7e8442e376633c5b3bd6edc8dbbdc539b22f095501c1cdb6"},
"elixir_ale": {:hex, :elixir_ale, "1.2.1", "07ac2f17a0191b8bd3b0df6b526c7f699a3a4d690c9def573fcb5824eef24d98", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "bfb099137500a3b8c4a1750cf07f2d704897ef9feac3412064bf9edc7d74193c"}, "elixir_ale": {:hex, :elixir_ale, "1.2.1", "07ac2f17a0191b8bd3b0df6b526c7f699a3a4d690c9def573fcb5824eef24d98", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "bfb099137500a3b8c4a1750cf07f2d704897ef9feac3412064bf9edc7d74193c"},
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"ex_doc": {:hex, :ex_doc, "0.28.1", "34fab7e7201c5a1f275f3b2f837125c940c512e8543d181bd4dd7acb19c8dba0", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "10e564dd59101a5edc4de7009a54baed015a246dee01f7200aab24e8f57fc044"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_check": {:hex, :ex_check, "0.15.0", "074b94c02de11c37bba1ca82ae5cc4926e6ccee862e57a485b6ba60fca2d8dc1", [:mix], [], "hexpm", "33848031a0c7e4209c3b4369ce154019788b5219956220c35ca5474299fb6a0e"},
"ex_doc": {:hex, :ex_doc, "0.30.9", "d691453495c47434c0f2052b08dd91cc32bc4e1a218f86884563448ee2502dd2", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d7aaaf21e95dc5cddabf89063327e96867d00013963eadf2c6ad135506a8bc10"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.4.5", "185a724dfde3745edd22f7571d59c47a835cf54ded67e9ccbc951920b7eec4c2", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e323a5b01ad53bc8c19c3a444be3e61ed7803ecd2e95530446ae9327d0143ecc"}, "git_ops": {:hex, :git_ops, "2.6.0", "e0791ee1cf5db03f2c61b7ebd70e2e95cba2bb9b9793011f26609f22c0900087", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "b98fca849b18aaf490f4ac7d1dd8c6c469b0cc3e6632562d366cab095e666ffe"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"},
"mimic": {:hex, :mimic, "1.5.1", "085f7ebfeb5b579a13a167aec3c712d71fecfc6cb8b298c0dd3056f97ea2c2a0", [:mix], [], "hexpm", "33a50ef9ff38f8f24b2586d52e529981a3ba2b8d061c872084aff0e993bf4bd5"}, "mimic": {:hex, :mimic, "1.7.4", "cd2772ffbc9edefe964bc668bfd4059487fa639a5b7f1cbdf4fd22946505aa4f", [:mix], [], "hexpm", "437c61041ecf8a7fae35763ce89859e4973bb0666e6ce76d75efc789204447c3"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.2", "b99ca56bbce410e9d5ee4f9155a212e942e224e259c7ebbf8f2c86ac21d4fa3c", [:mix], [], "hexpm", "98d51bd64d5f6a2a9c6bb7586ee8129e27dfaab1140b5a4753f24dac0ba27d2f"}, "mix_audit": {:hex, :mix_audit, "2.1.1", "653aa6d8f291fc4b017aa82bdb79a4017903902ebba57960ef199cbbc8c008a1", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "541990c3ab3a7bb8c4aaa2ce2732a4ae160ad6237e5dcd5ad1564f4f85354db1"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
"yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"},
} }

View file

@ -1,3 +0,0 @@
{
"extends": ["gitlab>jimsy/renovate"]
}

View file

@ -101,7 +101,7 @@ defmodule WaferDriverCircuits.GPIOTest do
|> expect(:enable, 1, fn conn1, pin_condition, _metadata -> |> expect(:enable, 1, fn conn1, pin_condition, _metadata ->
assert conn1 == conn assert conn1 == conn
assert pin_condition == :rising assert pin_condition == :rising
:ok {:ok, conn1}
end) end)
assert {:ok, ^conn} = GPIO.enable_interrupt(conn, :rising) assert {:ok, ^conn} = GPIO.enable_interrupt(conn, :rising)
@ -116,7 +116,7 @@ defmodule WaferDriverCircuits.GPIOTest do
|> expect(:disable, 1, fn conn1, pin_condition -> |> expect(:disable, 1, fn conn1, pin_condition ->
assert conn1 == conn assert conn1 == conn
assert pin_condition == :rising assert pin_condition == :rising
:ok {:ok, conn1}
end) end)
assert {:ok, ^conn} = GPIO.disable_interrupt(conn, :rising) assert {:ok, ^conn} = GPIO.disable_interrupt(conn, :rising)

View file

@ -77,7 +77,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:close, 1, fn ref -> |> expect(:close, 1, fn ref ->
assert ref == conn.ref assert ref == conn.conn
:ok :ok
end) end)
@ -91,7 +91,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:write_read, 1, fn ref, addr, data, bytes -> |> expect(:write_read, 1, fn ref, addr, data, bytes ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert data == <<0>> assert data == <<0>>
assert bytes == 2 assert bytes == 2
@ -108,7 +108,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:write, 1, fn ref, addr, data -> |> expect(:write, 1, fn ref, addr, data ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert data == <<1, 2, 3>> assert data == <<1, 2, 3>>
:ok :ok
@ -124,7 +124,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:write_read, 1, fn ref, addr, data, bytes -> |> expect(:write_read, 1, fn ref, addr, data, bytes ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert data == <<0>> assert data == <<0>>
assert bytes == 2 assert bytes == 2
@ -133,7 +133,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:write, 1, fn ref, addr, data -> |> expect(:write, 1, fn ref, addr, data ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert data == <<0, 1, 1>> assert data == <<0, 1, 1>>
:ok :ok
@ -149,7 +149,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:read, 1, fn ref, addr, bytes, opts -> |> expect(:read, 1, fn ref, addr, bytes, opts ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert bytes == 2 assert bytes == 2
assert opts == [] assert opts == []
@ -166,7 +166,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:write, 1, fn ref, addr, data, opts -> |> expect(:write, 1, fn ref, addr, data, opts ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert data == <<0, 0>> assert data == <<0, 0>>
assert opts == [] assert opts == []
@ -183,7 +183,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:write_read, 1, fn ref, addr, data, bytes, opts -> |> expect(:write_read, 1, fn ref, addr, data, bytes, opts ->
assert ref == conn.ref assert ref == conn.conn
assert addr == conn.address assert addr == conn.address
assert data == <<1>> assert data == <<1>>
assert bytes == 2 assert bytes == 2
@ -202,7 +202,7 @@ defmodule WaferCircuits.I2CTest do
Wrapper Wrapper
|> expect(:detect_devices, 1, fn ref -> |> expect(:detect_devices, 1, fn ref ->
assert conn.ref == ref assert conn.conn == ref
[conn.address] [conn.address]
end) end)
@ -210,5 +210,5 @@ defmodule WaferCircuits.I2CTest do
end end
end end
defp conn, do: %Subject{ref: :erlang.make_ref(), bus: "i2c-1", address: 0x13} defp conn, do: %Subject{conn: :erlang.make_ref(), bus: "i2c-1", address: 0x13}
end end