Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • phhw
  • captouch-threshold
  • t
  • dos
  • test2
  • test
  • slewtest
  • simtest
  • view-think
  • vm-pending
  • media-buf
  • scope
  • passthrough
  • wave
  • vsync
  • dos-main-patch-50543
  • json-error
  • rahix/big-flow3r
  • main
  • pippin/media_framework
  • release/1.1.1
  • release/1.1.0
  • fpletz/flake
  • sec/auto-nick
  • rahix/flow3rseeds
  • compressor
  • sec/blinky
  • pippin/uhm_flash_access_bust
  • release/1.0.0
  • fm_fix2
  • fm_fix
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pressable_bugfix
  • moon2_gay_drums
  • moon2_applications
  • schneider/application-remove-name
  • anon/webflasher
  • pippin/display-python-errors-on-display
  • bl00mbox
  • bl00mbox_old
  • schneider/recovery
  • schneider/bhi581
  • anon/update-sim
  • ci-1690580595
  • iggy/stemming_merge
  • schneider/factory_test
  • iggy/stemming
  • ch3/bl00mbox_docs
  • audio_input
  • anon/gpndemo
  • wip-docs
  • sdkconfig-spiram-tinyusb
  • history-rewrite
  • wip-tinyusb
  • audio_io
  • 9Rmain
  • icon-flower
  • dev_p4-iggy-rebased
  • moon2_demo_temp
  • scope_hack
  • raw_captouch_new
  • dev_p4
  • raw_captouch_old
  • q3k/doom-poc
  • dev_p4-iggy
  • events
  • micropython_api
  • uctx-wip
  • rev4_micropython
  • main+schneider
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
83 results

Target

Select target project
  • flow3r / flow3r firmware
  • Vespasian / flow3r firmware
  • Alexander / flow3r firmware
  • Phileas / flow3r firmware
  • Kari / flow3r firmware
  • raimue raimue / flow3r firmware
  • ja kob / flow3r firmware
  • Thore Rathsack / flow3r firmware
  • Clemens Wallrath / flow3r firmware
  • ar / flow3r firmware
  • David / flow3r firmware
  • alibi none / flow3r firmware
  • Manuel Vögele / flow3r firmware
  • Manuel Dipolt / flow3r firmware
  • Max Bachmann / flow3r firmware
  • yGifoom _ / flow3r firmware
  • Frédéric Christ / flow3r firmware
  • Francois Chagnon / flow3r firmware
  • Gnu Dalf / flow3r firmware
  • Sophie Tauchert / flow3r firmware
20 results
Select Git revision
  • main
  • blm_dev_chan
  • release/1.4.0
  • widgets_draw
  • return_of_melodic_demo
  • task_cleanup
  • mixer2
  • dx/fb-save-restore
  • dx/dldldld
  • fpletz/flake
  • dx/jacksense-headset-mic-only
  • release/1.3.0
  • fil3s-limit-filesize
  • allow-reloading-sunmenu
  • wifi-json-error-handling
  • app_text_viewer
  • shoegaze-fps
  • media_has_video_has_audio
  • fil3s-media
  • more-accurate-battery
  • sector_size_512
  • led_fix_fix
  • w1f1-in-sim
  • py_only_update_fps_overlay_when_changing
  • gr33nhouse-improvements
  • restore_blit
  • store_delta_ms_and_ins_as_class_members
  • always-have-a-wifi-instance
  • smaller_gradient_lut
  • pippin/more-accurate-battery
  • dx/hint-hint
  • pippin/ctx_sprite_sheet_support
  • 89-apps-should-be-able-to-specify-if-they-want-wifi-to-be-disabled-when-entering-them
  • q3k/render-to-texture
  • pippin/tune_ctx_config_update_from_upstream
  • pippin/tcp_redirect_hack
  • pippin/make_empty_drawlists_skip_render_and_blit
  • moon2_migrate_apps
  • release/1.2.0
  • release/1.1.1
  • release/1.1.0
  • sec/auto-nick
  • rahix/flow3rseeds
  • sec/blinky
  • pippin/uhm_flash_access_bust
  • release/1.0.0
  • pressable_bugfix
  • schneider/application-remove-name
  • anon/webflasher
  • pippin/display-python-errors-on-display
  • schneider/recovery
  • schneider/bhi581
  • anon/update-sim
  • ci-1690580595
  • iggy/stemming_merge
  • schneider/factory_test
  • iggy/stemming
  • ch3/bl00mbox_docs
  • audio_input
  • anon/gpndemo
  • wip-docs
  • sdkconfig-spiram-tinyusb
  • history-rewrite
  • wip-tinyusb
  • audio_io
  • 9Rmain
  • icon-flower
  • dev_p4-iggy-rebased
  • moon2_demo_temp
  • scope_hack
  • raw_captouch_new
  • dev_p4
  • raw_captouch_old
  • q3k/doom-poc
  • dev_p4-iggy
  • events
  • micropython_api
  • uctx-wip
  • rev4_micropython
  • main+schneider
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
  • v1.4.0
94 results
Show changes

Commits on Source 14669

14,569 additional commits have been omitted to prevent performance issues.
1000 files
+ 4520
0
Compare changes
  • Side-by-side
  • Inline

Files

.git-blame-ignore-revs

0 → 100644
+50 −0
Original line number Diff line number Diff line
# top: Update Python formatting to black "2023 stable style".
8b2748269244304854b3462cb8902952b4dcb892

# all: Reformat remaining C code that doesn't have a space after a comma.
5b700b0af90591d6b1a2c087bb8de6b7f1bfdd2d

# ports: Reformat more C and Python source code.
5c32111fa0e31e451b0f1666bdf926be2fdfd82c

# all: Update Python formatting to latest Black version 22.1.0.
ab2923dfa1174dc177f0a90cb00a7e4ff87958d2

# all: Update Python formatting to latest Black version 21.12b0.
3770fab33449a5dadf8eb06edfae0767e75320a6

# tools/gen-cpydiff.py: Fix formatting of doc strings for new Black.
0f78c36c5aa458a954eed39a46942209107a553e

# tests/run-tests.py: Reformat with Black.
2a38d7103672580882fb621a5b76e8d26805d593

# all: Update Python code to conform to latest black formatting.
06659077a81b85882254cf0953c33b27614e018e

# tools/uncrustify: Enable more opts to remove space between func and '('.
77ed6f69ac35c1663a5633a8ee1d8a2446542204

# tools/codeformat.py: Include extmod/{btstack,nimble} in code formatting.
026fda605e03113d6e753290d65fed774418bc53

# all: Format code to add space after C++-style comment start.
84fa3312cfa7d2237d4b56952f2cd6e3591210c4

# tests: Format all Python code with black, except tests in basics subdir.
3dc324d3f1312e40d3a8ed87e7244966bb756f26

# all: Remove spaces inside and around parenthesis.
1a3e386c67e03a79eb768cb6e9f6777e002d6660

# all: Remove spaces between nested paren and inside function arg paren.
feb25775851ba0c04b8d1013716f442258879d9c

# all: Reformat C and Python source code with tools/codeformat.py.
69661f3343bedf86e514337cff63d96cc42f8859

# stm32/usbdev: Convert files to unix line endings.
abde0fa2267f9062b28c3c015d7662a550125cc6

# all: Remove trailing spaces, per coding conventions.
761e4c7ff62896c7d8f8c3dfc3cc98a4cc4f2f6f

.gitattributes

0 → 100644
+26 −0
Original line number Diff line number Diff line
# Per default everything gets normalized and gets LF line endings on checkout.
* text eol=lf

# These will always have CRLF line endings on checkout.
*.vcxproj text eol=crlf
*.props text eol=crlf
*.bat text eol=crlf

# These are binary so should never be modified by git.
*.a binary
*.png binary
*.jpg binary
*.dxf binary
*.mpy binary

# These should also not be modified by git.
tests/basics/string_cr_conversion.py -text
tests/basics/string_crlf_conversion.py -text
ports/stm32/pybcdc.inf_template -text
ports/stm32/usbhost/** -text
ports/cc3200/hal/aes.c -text
ports/cc3200/hal/aes.h -text
ports/cc3200/hal/des.c -text
ports/cc3200/hal/i2s.c -text
ports/cc3200/hal/i2s.h -text
ports/cc3200/version.h -text

.github/FUNDING.yml

0 → 100644
+1 −0
Original line number Diff line number Diff line
github: micropython
+25 −0
Original line number Diff line number Diff line
---
name: Bug report
about: Report an issue
title: ''
labels: bug
assignees: ''

---

* Please search existing issues before raising a new issue. For questions about MicroPython or for help using MicroPython, or any sort of "how do I?" requests, please use the Discussions tab or raise a documentation request instead.

* In your issue, please include a clear and concise description of what the bug is, the expected output, and how to replicate it.

* If this issue involves external hardware, please include links to relevant datasheets and schematics.

* If you are seeing code being executed incorrectly, please provide a minimal example and expected output (e.g. comparison to CPython).

* For build issues, please include full details of your environment, compiler versions, command lines, and build output.

* Please provide as much information as possible about the version of MicroPython you're running, such as:
 - firmware file name
 - git commit hash and port/board
 - version information shown in the REPL (hit Ctrl-B to see the startup message)

* Remove all placeholder text above before submitting.
+11 −0
Original line number Diff line number Diff line
blank_issues_enabled: false
contact_links:
  - name: MicroPython GitHub Discussions
    url: https://github.com/orgs/micropython/discussions
    about: Community discussion about all things MicroPython. This is the best place to start if you have questions about using MicroPython or getting started with MicroPython development.
  - name: MicroPython Documentation
    url: https://docs.micropython.org/
    about: Documentation for using and working with MicroPython and libraries.
  - name: MicroPython Downloads
    url: https://micropython.org/download/
    about: Pre-built firmware and information for most supported boards.
+16 −0
Original line number Diff line number Diff line
---
name: Documentation issue
about: Report areas of the documentation or examples that need improvement
title: 'docs: '
labels: documentation
assignees: ''

---

* Please search existing issues before raising a new issue. For questions about MicroPython or for help using MicroPython, or any sort of "how do I?" requests, please use the Discussions tab instead.

* Describe what was missing from the documentation and/or what was incorrect/incomplete.

* If possible, please link to the relevant page on https://docs.micropython.org/

* Remove all placeholder text above before submitting.
+24 −0
Original line number Diff line number Diff line
---
name: Feature request
about: Request a feature or improvement
title: ''
labels: enhancement
assignees: ''

---

* Please search existing issues before raising a new issue. For questions about MicroPython or for help using MicroPython, or any sort of "how do I?" requests, please use the Discussions tab or raise a documentation request instead.

* Describe the feature you'd like to see added to MicroPython. In particular, what does this feature enable and why is it useful. MicroPython aims to strike a balance between functionality and code size, so please consider whether this feature can be optionally enabled and whether it can be provided in other ways (e.g. pure-Python library).

* For core Python features, where possible please include a link to the relevant PEP.

* For new architectures / ports / boards, please provide links to relevant documentation, specifications, and toolchains. Any information about the popularity and unique features about this hardware would also be useful.

* For features for existing ports (e.g. new peripherals or microcontroller features), please describe which port(s) it applies too, and whether this is could be an extension to the machine API or a port-specific module?

* For drivers (e.g. for external hardware), please link to datasheets and/or existing drivers from other sources.

* Who do you expect will implement the feature you are requesting? Would you be willing to sponsor this work?

* Remove all placeholder text above before submitting.
+16 −0
Original line number Diff line number Diff line
---
name: Security report
about: Report a security issue or vunerability in MicroPython
title: ''
labels: security
assignees: ''

---

* If you need to raise this issue privately with the MicroPython team, please email contact@micropython.org instead.

* Include a clear and concise description of what the security issue is.

* What does this issue allow an attacker to do?

* Remove all placeholder text above before submitting.

.github/dependabot.yml

0 → 100644
+7 −0
Original line number Diff line number Diff line
version: 2
updates:
  # Maintain dependencies for GitHub Actions
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "daily"
+20 −0
Original line number Diff line number Diff line
name: Check code formatting

on: [push, pull_request]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
    - name: Install packages
      run: source tools/ci.sh && ci_code_formatting_setup
    - name: Run code formatting
      run: source tools/ci.sh && ci_code_formatting_run
    - name: Check code formatting
      run: git diff --exit-code
+45 −0
Original line number Diff line number Diff line
name: Check code size

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'lib/**'
      - 'ports/bare-arm/**'
      - 'ports/minimal/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 100
    - name: Install packages
      run: source tools/ci.sh && ci_code_size_setup
    - name: Build
      run: source tools/ci.sh && ci_code_size_build
    - name: Compute code size difference
      run: tools/metrics.py diff ~/size0 ~/size1 | tee diff
    - name: Save PR number
      if: github.event_name == 'pull_request'
      env:
        PR_NUMBER: ${{ github.event.number }}
      run: echo $PR_NUMBER > pr_number
    - name: Upload diff
      if: github.event_name == 'pull_request'
      uses: actions/upload-artifact@v3
      with:
        name: code-size-report
        path: |
          diff
          pr_number
        retention-days: 1
+105 −0
Original line number Diff line number Diff line
name: Code size comment

on:
  workflow_run:
    workflows: [Check code size]
    types: [completed]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  comment:
    runs-on: ubuntu-20.04
    steps:
      - name: 'Download artifact'
        id: download-artifact
        uses: actions/github-script@v6
        with:
          result-encoding: string
          script: |
            const fs = require('fs');

            const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
               owner: context.repo.owner,
               repo: context.repo.repo,
               run_id: context.payload.workflow_run.id,
            });

            const matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
              return artifact.name == "code-size-report"
            });

            if (matchArtifact.length === 0) {
              console.log('no matching artifact found');
              console.log('result: "skip"');

              return 'skip';
            }

            const download = await github.rest.actions.downloadArtifact({
               owner: context.repo.owner,
               repo: context.repo.repo,
               artifact_id: matchArtifact[0].id,
               archive_format: 'zip',
            });

            fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/code-size-report.zip`, Buffer.from(download.data));

            console.log('artifact downloaded to `code-size-report.zip`');
            console.log('result: "ok"');

            return 'ok';
      - name: 'Unzip artifact'
        if: steps.download-artifact.outputs.result == 'ok'
        run: unzip code-size-report.zip
      - name: Post comment to pull request
        if: steps.download-artifact.outputs.result == 'ok'
        uses: actions/github-script@v6
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            const fs = require('fs');

            const prNumber = Number(fs.readFileSync('pr_number'));
            const codeSizeReport = `Code size report:

            \`\`\`
            ${fs.readFileSync('diff')}
            \`\`\`
            `;

            const comments = await github.paginate(
              github.rest.issues.listComments,
              {
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
              }
            );

            comments.reverse();

            const previousComment = comments.find(comment =>
              comment.user.login === 'github-actions[bot]'
            )

            // if github-actions[bot] already made a comment, update it,
            // otherwise create a new comment.

            if (previousComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: previousComment.id,
                body: codeSizeReport,
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
                body: codeSizeReport,
              });
            }
+18 −0
Original line number Diff line number Diff line
name: Check commit message formatting

on: [push, pull_request]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: '100'
    - uses: actions/setup-python@v4
    - name: Check commit message formatting
      run: source tools/ci.sh && ci_commit_formatting_run
+22 −0
Original line number Diff line number Diff line
name: Build docs

on:
  pull_request:
    paths:
      - docs/**

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
    - name: Install Python packages
      run: pip install Sphinx
    - name: Build docs
      run: make -C docs/ html
+25 −0
Original line number Diff line number Diff line
name: Check examples

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'examples/**'
      - 'ports/unix/**'
      - 'py/**'
      - 'shared/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  embedding:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding
    - name: Run
      run: ./examples/embedding/embed | grep "hello world"
+31 −0
Original line number Diff line number Diff line
name: Package mpremote

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        # Version is determined from git,
        # should be deep enough to get to latest tag
        fetch-depth: '1000'
    - run: |
        git fetch --prune --unshallow --tags
    - uses: actions/setup-python@v4
    - name: Install build tools
      run: pip install build
    - name: Build mpremote wheel
      run: cd tools/mpremote && python -m build --wheel
    - name: Archive mpremote wheel
      uses: actions/upload-artifact@v3
      with:
        name: mpremote
        path: |
          tools/mpremote/dist/mpremote*.whl
+24 −0
Original line number Diff line number Diff line
name: .mpy file format and tools

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'examples/**'
      - 'tests/**'
      - 'tools/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-20.04 # use 20.04 to get python2
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_mpy_format_setup
    - name: Test mpy-tool.py
      run: source tools/ci.sh && ci_mpy_format_test
+22 −0
Original line number Diff line number Diff line
name: Build ports metadata

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - ports/**

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Build ports download metadata
      run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards
+28 −0
Original line number Diff line number Diff line
name: cc3200 port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/cc3200/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_cc3200_setup
    - name: Build
      run: source tools/ci.sh && ci_cc3200_build
+37 −0
Original line number Diff line number Diff line
name: esp32 port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/esp32/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build_idf402:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_esp32_idf402_setup
    - name: Build
      run: source tools/ci.sh && ci_esp32_build

  build_idf44:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_esp32_idf44_setup
    - name: Build
      run: source tools/ci.sh && ci_esp32_build
+28 −0
Original line number Diff line number Diff line
name: esp8266 port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/esp8266/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH
    - name: Build
      run: source tools/ci.sh && ci_esp8266_build
+28 −0
Original line number Diff line number Diff line
name: mimxrt port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/mimxrt/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_mimxrt_setup
    - name: Build
      run: source tools/ci.sh && ci_mimxrt_build
+28 −0
Original line number Diff line number Diff line
name: nrf port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/nrf/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_nrf_setup
    - name: Build
      run: source tools/ci.sh && ci_nrf_build
+28 −0
Original line number Diff line number Diff line
name: powerpc port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/powerpc/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_powerpc_setup
    - name: Build
      run: source tools/ci.sh && ci_powerpc_build
+32 −0
Original line number Diff line number Diff line
name: qemu-arm port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/qemu-arm/**'
      - 'tests/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build_and_test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_qemu_arm_setup
    - name: Build and run test suite
      run: source tools/ci.sh && ci_qemu_arm_build
    - name: Print failures
      if: failure()
      run: grep --before-context=100 --text "FAIL" ports/qemu-arm/build/console.out
+29 −0
Original line number Diff line number Diff line
name: renesas-ra port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/renesas-ra/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build_renesas_ra_board:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_renesas_ra_setup
    - name: Build
      run: source tools/ci.sh && ci_renesas_ra_board_build
+28 −0
Original line number Diff line number Diff line
name: rp2 port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/rp2/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_rp2_setup
    - name: Build
      run: source tools/ci.sh && ci_rp2_build
+28 −0
Original line number Diff line number Diff line
name: samd port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/samd/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_samd_setup
    - name: Build
      run: source tools/ci.sh && ci_samd_build
+37 −0
Original line number Diff line number Diff line
name: stm32 port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/stm32/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build_pyb:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_stm32_setup
    - name: Build
      run: source tools/ci.sh && ci_stm32_pyb_build

  build_nucleo:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_stm32_setup
    - name: Build
      run: source tools/ci.sh && ci_stm32_nucleo_build
+28 −0
Original line number Diff line number Diff line
name: teensy port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'drivers/**'
      - 'ports/teensy/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_teensy_setup
    - name: Build
      run: source tools/ci.sh && ci_teensy_build
+224 −0
Original line number Diff line number Diff line
name: unix port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'examples/**'
      - 'mpy-cross/**'
      - 'ports/unix/**'
      - 'tests/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  minimal:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: source tools/ci.sh && ci_unix_minimal_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_minimal_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  reproducible:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build with reproducible date
      run: source tools/ci.sh && ci_unix_minimal_build
      env:
        SOURCE_DATE_EPOCH: 1234567890
    - name: Check reproducible build date
      run: echo | ports/unix/build-minimal/micropython -i | grep 'on 2009-02-13;'

  standard:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: source tools/ci.sh && ci_unix_standard_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_standard_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  coverage:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_coverage_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_coverage_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_coverage_run_tests
    - name: Test merging .mpy files
      run: source tools/ci.sh && ci_unix_coverage_run_mpy_merge_tests
    - name: Build native mpy modules
      run: source tools/ci.sh && ci_native_mpy_modules_build
    - name: Test importing .mpy generated by mpy_ld.py
      run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests
    - name: Run gcov coverage analysis
      run: |
        (cd ports/unix && gcov -o build-coverage/py ../../py/*.c || true)
        (cd ports/unix && gcov -o build-coverage/extmod ../../extmod/*.c || true)
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        fail_ci_if_error: true
        verbose: true
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  coverage_32bit:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_32bit_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_coverage_32bit_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_coverage_32bit_run_tests
    - name: Build native mpy modules
      run: source tools/ci.sh && ci_native_mpy_modules_32bit_build
    - name: Test importing .mpy generated by mpy_ld.py
      run: source tools/ci.sh && ci_unix_coverage_32bit_run_native_mpy_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  nanbox:
    runs-on: ubuntu-20.04 # use 20.04 to get python2
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_32bit_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_nanbox_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_nanbox_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  float:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: source tools/ci.sh && ci_unix_float_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_float_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  stackless_clang:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_clang_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_stackless_clang_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_stackless_clang_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  float_clang:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_clang_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_float_clang_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_float_clang_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  settrace:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: source tools/ci.sh && ci_unix_settrace_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_settrace_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  settrace_stackless:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build
      run: source tools/ci.sh && ci_unix_settrace_stackless_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_settrace_stackless_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  macos:
    runs-on: macos-11.0
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: '3.8'
    - name: Build
      run: source tools/ci.sh && ci_unix_macos_build
    - name: Run tests
      run: source tools/ci.sh && ci_unix_macos_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  qemu_mips:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_qemu_mips_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_qemu_mips_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_qemu_mips_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures

  qemu_arm:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_unix_qemu_arm_setup
    - name: Build
      run: source tools/ci.sh && ci_unix_qemu_arm_build
    - name: Run main test suite
      run: source tools/ci.sh && ci_unix_qemu_arm_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures
+32 −0
Original line number Diff line number Diff line
name: webassembly port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'ports/webassembly/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_webassembly_setup
    - name: Build
      run: source tools/ci.sh && ci_webassembly_build
    - name: Run tests
      run: source tools/ci.sh && ci_webassembly_run_tests
    - name: Print failures
      if: failure()
      run: tests/run-tests.py --print-failures
+28 −0
Original line number Diff line number Diff line
name: windows port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/*.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'ports/unix/**'
      - 'ports/windows/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_windows_setup
    - name: Build
      run: source tools/ci.sh && ci_windows_build
+29 −0
Original line number Diff line number Diff line
name: zephyr port

on:
  push:
  pull_request:
    paths:
      - '.github/workflows/ports_zephyr.yml'
      - 'tools/**'
      - 'py/**'
      - 'extmod/**'
      - 'shared/**'
      - 'lib/**'
      - 'ports/zephyr/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install packages
      run: source tools/ci.sh && ci_zephyr_setup
    - name: Install Zephyr
      run: source tools/ci.sh && ci_zephyr_install
    - name: Build
      run: source tools/ci.sh && ci_zephyr_build

.gitignore

0 → 100644
+31 −0
Original line number Diff line number Diff line
# This .gitignore file is intended to be minimal.
#
# If you find that you need additional rules, such as IDE temporary
# files, please do so either via a global .gitignore file (registered
# with core.excludesFile), or by adding private repository-specific
# rules to .git/info/exclude.  See https://git-scm.com/docs/gitignore
# for more information.

# Build directories
build/
build-*/
docs/genrst/

# Test failure outputs
tests/results/*

# Python cache files
__pycache__/

# Customized Makefile/project overrides
GNUmakefile
user.props

# MacOS desktop metadata files
.DS_Store

#ctags
tags

sdkconfig.old
sdkconfig

.gitlab-ci.yml

0 → 100644
+37 −0
Original line number Diff line number Diff line
variables:
  GIT_SUBMODULE_STRATEGY: recursive
  GIT_SUBMODULE_PATHS: micropython/lib/berkeley-db-1.xx micropython/lib/micropython-lib


stages:
  - build

build-p1:
  stage: build
  tags:
    - nixos
  script:
    - nix-shell nix/shell.nix --command "idf.py -g p1 build"
  artifacts:
    expose_as: 'Proto 1 ELF'
    paths: ['build/badge23.elf']

build-p3:
  stage: build
  tags:
    - nixos
  script:
    - nix-shell nix/shell.nix --command "idf.py -g p3 build"
  artifacts:
    expose_as: 'Proto 3 ELF'
    paths: ['build/badge23.elf']

build-p4:
  stage: build
  tags:
    - nixos
  script:
    - nix-shell nix/shell.nix --command "idf.py -g p4 build"
  artifacts:
    expose_as: 'Proto 4 ELF'
    paths: ['build/badge23.elf']

.gitmodules

0 → 100644
+58 −0
Original line number Diff line number Diff line
[submodule "lib/axtls"]
	path = micropython/lib/axtls
	url = https://github.com/micropython/axtls.git
[submodule "lib/libffi"]
	path = micropython/lib/libffi
	url = https://github.com/atgreen/libffi
[submodule "lib/lwip"]
	path = micropython/lib/lwip
	url = https://github.com/lwip-tcpip/lwip.git
[submodule "lib/berkeley-db-1.xx"]
	path = micropython/lib/berkeley-db-1.xx
	url = https://github.com/pfalcon/berkeley-db-1.xx
[submodule "lib/stm32lib"]
	path = micropython/lib/stm32lib
	url = https://github.com/micropython/stm32lib
	branch = work-F0-1.9.0+F4-1.16.0+F7-1.7.0+G0-1.5.1+G4-1.3.0+H7-1.6.0+L0-1.11.2+L1-1.10.3+L4-1.17.0+WB-1.10.0+WL-1.1.0
[submodule "lib/nrfx"]
	path = micropython/lib/nrfx
	url = https://github.com/NordicSemiconductor/nrfx.git
[submodule "lib/mbedtls"]
	path = micropython/lib/mbedtls
	url = https://github.com/ARMmbed/mbedtls.git
[submodule "lib/asf4"]
	path = micropython/lib/asf4
	url = https://github.com/adafruit/asf4
	branch = circuitpython
[submodule "lib/tinyusb"]
	path = micropython/lib/tinyusb
	url = https://github.com/hathach/tinyusb
[submodule "lib/mynewt-nimble"]
	path = micropython/lib/mynewt-nimble
	url = https://github.com/micropython/mynewt-nimble.git
[submodule "lib/btstack"]
	path = micropython/lib/btstack
	url = https://github.com/bluekitchen/btstack.git
[submodule "lib/nxp_driver"]
	path = micropython/lib/nxp_driver
	url = https://github.com/hathach/nxp_driver.git
[submodule "lib/libhydrogen"]
	path = micropython/lib/libhydrogen
	url = https://github.com/jedisct1/libhydrogen.git
[submodule "lib/pico-sdk"]
	path = micropython/lib/pico-sdk
	url = https://github.com/raspberrypi/pico-sdk.git
[submodule "lib/fsp"]
	path = micropython/lib/fsp
	url = https://github.com/renesas/fsp.git
[submodule "lib/wiznet"]
	path = micropython/lib/wiznet5k
	url = https://github.com/andrewleech/wiznet_ioLibrary_Driver.git
	# Requires https://github.com/Wiznet/ioLibrary_Driver/pull/120
	# url = https://github.com/Wiznet/ioLibrary_Driver.git
[submodule "lib/cyw43-driver"]
	path = micropython/lib/cyw43-driver
	url = https://github.com/georgerobotics/cyw43-driver.git
[submodule "lib/micropython-lib"]
	path = micropython/lib/micropython-lib
	url = https://github.com/micropython/micropython-lib.git
+13 −0
Original line number Diff line number Diff line
repos:
  - repo: local
    hooks:
      - id: codeformat
        name: MicroPython codeformat.py for changed files
        entry: tools/codeformat.py -v -f
        language: python
      - id: verifygitlog
        name: MicroPython git commit message format checker
        entry: tools/verifygitlog.py --check-file --ignore-rebase
        language: python
        verbose: true
        stages: [commit-msg]

CMakeLists.txt

0 → 100644
+7 −0
Original line number Diff line number Diff line
cmake_minimum_required(VERSION 3.12)

set(IDF_TARGET esp32s3)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

project(badge23)

README.md

0 → 100644
+206 −0
Original line number Diff line number Diff line
## Demo Payload

See python_payload/README.md for a demo application.

Files can be transferred with mpremote, such as:

```
mpremote fs cp python_payload/boot.py :boot.py
```

Alternatively, adafruit-ampy may work more reliably sometimes:

```
ampy -p /dev/ttyACM0 -d3 put boot.py
```

Please transfer all .py files in python_payload/ for using the demo payload.

## How to install dependencies

### Generic

1. install esp-idf v4.4:
(copied from https://www.wemos.cc/en/latest/tutorials/others/build\_micropython\_esp32.html)
```
$ cd ~
$ git clone https://github.com/espressif/esp-idf.git
$ cd esp-idf
$ git checkout v4.4
$ git submodule update --init --recursive

$ cd esp-idf
$ ./install.sh
$ source export.sh
```
best put something like "alias espidf='source ~/esp-idf/export.sh'" in your .bashrc etc,
you need to run it in every new terminal and adding it to autostart did bother us

### Nix(OS)

```
$ nix-shell nix/shell.nix
```

## How to build and flash

Standard ESP-IDF project machinery present and working. You can run `idf.py` from the git checkout and things should just work.

### Building

Prepare submodules:

```
$ make -C micropython/ports/esp32 submodules
```

Build normally with idf.py:

```
$ idf.py build
```

By default, code for the fourth generation prototype will be built. To select a different generation, either set `-g`/`--generation` during an `idf.py build` (which will get cached for subsequent builds) or set the BADGE_GENERATION environment variable to one of the following values:

^ `-g` / `BADGE_GENERATION` value ^ Badge Generation                   ^ 
| `p1` or `proto1`                | Prototype 1                        |
| `p3` or `proto3`                | Prototype 3 (B3xx)                 |
| `p4` or `proto4`                | Prototype 4 (B4xx)                 |

**Important**: when switching generations, do a full clean by running `rm -rf sdkconfig build`. Otherwise you will get _weird_ errors and likely will end up building for the wrong architecture.

### Flashing

Put badge into bootloader mode by holding left should button down during boot.

```
$ idf.py -p /dev/ttyACM0 flash
```

You can skip `-p /dev/ttyACM0` if you set the environment variable `ESPPORT=/dev/ttyACM0`. This environment variable is also set by default when using Nix.

After flashing, remember to powercycle your badge to get it into the user application.


### Cleaning

For a full clean, do **not** trust `idf.py clean` or `idf.py fullclean`. Instead, do:

```
$ rm -rf build sdkconfig
```

### Accessing MicroPython REPL:

```
$ picocom -b 115200 /dev/ttyACM0
$ # or
$ screen /dev/ttyACM0
$ # or (will eat newlines in REPL, though)
$ idf.py -p /dev/ttyACM0 monitor
```

### Use CMake

`idf.py` calls cmake under the hood for most operations. If you dislike using wrappers you can do the same work yourself:

```
mkdir build
cd build
cmake .. -G Ninja
ninja
```

There's `flash/monitor` targets, too (but no openocd/gdb...). To pick what port to flash to/monitor, set the ESPPORT environment variable.

## How to modify

### Structure

```
main/               - main module, starts micropython on core1 and continues
                      executing components/badge23/.
usermodule/         - `hardware`, `synth`, ... C modules exposed to micropython.
components/badge23/ - main ESP-IDF `app_main`, runs on core 0 after micropython
                      gets started on core1.
components/gc9a01/  - low-level LCD driver.
```

### General info

Global + micropython entry point: `app_main()` in `micropython/ports/esp32/main.c`, compiled into `main/` component.

C entry point, called by^: `os_app_main()` in components/badge23/espan.c

Register new C files for compilation: add to components/badge23/CMakelists.txt

Change output volume in the `set_global_vol_dB(int8_t)` call; -90 for mute

### Debugging

The badge is currently configured to run in HW USB UART/JTAG mode (vs. using TinyUSB and 'software' CDC/whatever using the generic OTG peripheral).

What this means:

1. You can use the MicroPython REPL over a USB console,
2. The MicroPython REPL will also print ESP-IDF logs, including panics,
3. You can use OpenOCD/GDB.

#### printf() debugging and logging in C-land

Given the above, you can do the following to get a log. This is part of ESP-IDF's standard logging functionality.

```
static const char *TAG = "misery";
// ...
ESP_LOGI(TAG, "i love C");
```

However, this will **only work** if you first set `CONFIG_LOG_DEFAULT_LEVEL_INFO=y` (which will likely break programs interacting with micropython REPL as many components of the ESP-IDF will suddenly become very chatty). But that's fine for troubleshooting some C-land bugs.

If you want to only log errors or just add temporary logs, use `ESP_LOGE` instead, which will always print to the USB console.

`printf()` also just works. But it should only be used for development debugging, for long-term logging statements please use `ESP_LOG*` instead.

#### Running OpenOCD+GDB

First, make sure your badge is running in application mode (not bootloader mode! that will stay in bootloader mode).

Then, start OpenOCD:

```
$ OPENOCD_COMMANDS="-f board/esp32s3-builtin.cfg" idf.py openocd
```

(you can skip setting `OPENOCD_COMMANDS` if you're using Nix)

Then, in another terminal:

```
$ idf.py gdb
```

Good luck. The idf.py gdb/openocd scripts seem somewhat buggy.

### ESP-IDF functionality

#### sdkconfig / menuconfig

We have an sdkconfig.default file per badge generation. See the build
instructions above to see how to select the generation to build against.

The build system will generate an sdkconfig, but it should not be committed into
version control. Instead, treat it like an ephemeral artifact that you can also
modify for your own needs during development.

To run menuconfig, do the usual::

```
$ idf.py  menuconfig
```

(Specify -g or BADGE_GENERATION if you haven't built the firmware yet)

Then, either save into the temporary sdkconfig by using 'S', or save into a
defconfig by using 'D'. The resulting `build/defconfig` file can then be copied
into `sdkconfig.$generation` to change the defaults for a given generation.
+18 −0
Original line number Diff line number Diff line
idf_component_register(
    SRCS
        apa102LEDStrip.c
        audio.c
        captouch.c
        display.c
        espan.c
        leds.c
        scope.c
        synth.c
        spio.c
    INCLUDE_DIRS
        include
    REQUIRES
        badge23_hwconfig
        gc9a01
        espressif__led_strip
)
+32 −0
Original line number Diff line number Diff line
menu "Badge23 Config"
    choice BADGE23_HW_GEN
        prompt "Badge23 Hardware Generation"
        default BADGE23_HW_GEN_P4
        config BADGE23_HW_GEN_P1
            help
                Protoype version 1, a.k.a. proto1. Very early protoype.
                Visual identifiers:
                 - No line in/out jacks
                 - White bottom board
                 - USB-C jack points side of leaf
            bool "Prototype 1"
        config BADGE23_HW_GEN_P3
            help
                Prototype version 3, a.k.a. proto3
                Visual identifiers:
                  - Sticker with B3xx (xx being arbitrary digits) on the back
            bool "Prototype 3"
        config BADGE23_HW_GEN_P4
            help
                Prototype version 4, a.k.a. proto4
                Visual identifiers:
                  - Sticker with B4xx (xx being arbitrary digits) on the back
            bool "Prototype 4"
        config BADGE23_HW_GEN_ADILESS
            help
                Prototype version 5, a.k.a. adi-less
                Visual identifiers:
                  - Sticker with B5xx (xx being arbitrary digits) on the back
            bool "Prototype 5 / ADI-less"
    endchoice
endmenu
+6 −0
Original line number Diff line number Diff line
badge23/espan
===

Transitional component containing all custom C code for badge23, including drivers for peripherals and 'espan' application leftovers.

This will be likely split up into sub-components.
+50 −0
Original line number Diff line number Diff line
#include "badge23/apa102LEDStrip.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness)
{  
  ledObject->_numLEDs = numLEDs;
  ledObject->_bytesPerLED = bytesPerLED;
  ledObject->_endFrameLength = 1;//round( (numLEDs/2)/8 );
  ledObject->_frameLength = (1+numLEDs+ledObject->_endFrameLength)*bytesPerLED;
  ledObject->_globalBrightness = globalBrightness;
  ledObject->LEDs = (unsigned char *)malloc(ledObject->_frameLength*sizeof(unsigned char)); 
  
  //Start Frame
  ledObject->LEDs[0] = 0;
  ledObject->LEDs[1] = 0;
  ledObject->LEDs[2] = 0;
  ledObject->LEDs[3] = 0;
  //Driver frame+PIXEL frames
  for(ledObject->_counter=ledObject->_bytesPerLED; ledObject->_counter<ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter+=ledObject->_bytesPerLED)
  {
    ledObject->LEDs[ledObject->_counter] = ledObject->_globalBrightness;
    ledObject->LEDs[ledObject->_counter+1] = 0;
    ledObject->LEDs[ledObject->_counter+2] = 0;
    ledObject->LEDs[ledObject->_counter+3] = 0;
  }
  //END frames
  for(ledObject->_counter=ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter<ledObject->_frameLength; ledObject->_counter+=ledObject->_bytesPerLED)
  {
    ledObject->LEDs[ledObject->_counter] = 255;
    ledObject->LEDs[ledObject->_counter+1] = 255;
    ledObject->LEDs[ledObject->_counter+2] = 255;
    ledObject->LEDs[ledObject->_counter+3] = 255;
  }
}
void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour)
{
  ledObject->_counter = 4*(pixelIndex+1);
  ledObject->LEDs[ ledObject->_counter + 1 ] = pixelColour[2];
  ledObject->LEDs[ ledObject->_counter + 2 ] = pixelColour[1];
  ledObject->LEDs[ ledObject->_counter + 3 ] = pixelColour[0];
}
void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour)
{
  ledObject->_counter = 4*(pixelIndex+1);
  pixelColour[2] = ledObject->LEDs[ ledObject->_counter + 1 ];
  pixelColour[1] = ledObject->LEDs[ ledObject->_counter + 2 ];
  pixelColour[0] = ledObject->LEDs[ ledObject->_counter + 3 ];
}
+349 −0
Original line number Diff line number Diff line
#include "badge23/audio.h"
#include "badge23/synth.h" 
#include "badge23/scope.h"
#include "badge23_hwconfig.h"

#include "driver/i2s.h"
#include "driver/i2c.h"


#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#define TIMEOUT_MS                  1000

#define I2C_MASTER_NUM              0                          /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */

static void audio_player_task(void* arg);

#define DMA_BUFFER_SIZE     64
#define DMA_BUFFER_COUNT    2
#define I2S_PORT 0

#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
static uint8_t max98091_i2c_read(const uint8_t reg)
{
    const uint8_t tx[] = {reg};
    uint8_t rx[1];
    esp_err_t ret = i2c_master_write_read_device(I2C_MASTER_NUM, 0x10, tx, sizeof(tx), rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS);
    return rx[0];
}

static esp_err_t max98091_i2c_write(const uint8_t reg, const uint8_t data)
{
    const uint8_t tx[] = {reg, data};
    esp_err_t ret = i2c_master_write_to_device(I2C_MASTER_NUM, 0x10, tx, sizeof(tx), TIMEOUT_MS / portTICK_PERIOD_MS);

    if(max98091_i2c_read(reg) != data) printf("Write of %04X to %02X apparently failed\n", data, reg);

    return ret;
}



static void init_codec()
{
    // Enable CODEC

    vTaskDelay(10 / portTICK_PERIOD_MS);
    ESP_ERROR_CHECK(max98091_i2c_write(0x00, 0x80)); // shutdown
    vTaskDelay(10 / portTICK_PERIOD_MS);

    ESP_ERROR_CHECK(max98091_i2c_write(0x45, 0)); // shutdown

    ESP_ERROR_CHECK(max98091_i2c_write(0x1b, 1 << 4)); // pclk = mclk / 1

    ESP_ERROR_CHECK(max98091_i2c_write(0x26,  (1 << 7) | (1 << 6))); // music, dc filter in record

    ESP_ERROR_CHECK(max98091_i2c_write(0x06, 1 << 2)); // Sets up DAI for left-justified slave mode operation.
    ESP_ERROR_CHECK(max98091_i2c_write(0x07, 1 << 5)); // Sets up the DAC to speaker path

    // Somehow this was needed to get an input signal to the ADC, even though
    // all other registers should be taken care of later. Don't know why.
    ESP_ERROR_CHECK(max98091_i2c_write(0x09, 1 << 6)); // Sets up the line in to adc path

    ESP_ERROR_CHECK(max98091_i2c_write(0x25, (1 << 1) | (1 << 0))); // SDOUT, SDIN enabled
    ESP_ERROR_CHECK(max98091_i2c_write(0x42, 1 << 0)); // bandgap bias
    ESP_ERROR_CHECK(max98091_i2c_write(0x43, 1 << 0)); // high performane mode

    // Table 51. Digital Audio Interface (DAI) Format Configuration Register

    ESP_ERROR_CHECK(max98091_i2c_write(0x2E, 1)); // Left DAC -> Left Speaker
    ESP_ERROR_CHECK(max98091_i2c_write(0x2F, 2)); // Right DAC -> Right Speaker

    //max98091_i2c_write(0x2E, (1<<2) | (1<<1)); // Line A -> Left Speaker
    //max98091_i2c_write(0x2F, (1<<3) | (1<<0)); // LIne B -> Right Speaker

    ESP_ERROR_CHECK(max98091_i2c_write(0x29, 1)); // Left DAC -> Left HP
    ESP_ERROR_CHECK(max98091_i2c_write(0x2A, 2)); // Right DAC -> Right HP

    // Mic bias is off
    ESP_ERROR_CHECK(max98091_i2c_write(0x3E, (1<<4) |(1<<3) | (1<<2) | (1<<1) | (1<<0))); // enable micbias, line input amps, ADCs
    ESP_ERROR_CHECK(max98091_i2c_write(0x0D, (1<<3) | (1<<2))); // IN3 SE -> Line A, IN4 SE -> Line B
    ESP_ERROR_CHECK(max98091_i2c_write(0x15, (1<<4) )); // line B -> left ADC
    ESP_ERROR_CHECK(max98091_i2c_write(0x16, (1<<3) )); // line A -> right ADC
    ESP_ERROR_CHECK(max98091_i2c_write(0x44, (1<<2) | (1<<1) | (1<<0) )); // 128x oversampling, dithering, high performance ADC

    max98091_i2c_write(0x13, (1<<4) | (1<<5) | (1<<1) | (1<<0) ); // enable digital mic

    // Enable headset mic
#if 0
    max98091_i2c_write(0x13, 0);
    ESP_ERROR_CHECK(max98091_i2c_write(0x0F, (0<<1) | (1<<0) )); // IN5/IN6 to MIC1
    ESP_ERROR_CHECK(max98091_i2c_write(0x10, (1<<6) | (1<<4) | (1<<2) )); // 20 dB gain on MIC1
    ESP_ERROR_CHECK(max98091_i2c_write(0x15, (1<<5) )); // MIC1 -> left ADC
    ESP_ERROR_CHECK(max98091_i2c_write(0x16, (1<<5) )); // MIC1 -> right ADC
#endif

    ESP_ERROR_CHECK(max98091_i2c_write(0x3F, (1<<1) | (1<<0))); // output enable: enable dacs

    ESP_ERROR_CHECK(max98091_i2c_write(0x45, 1<<7)); // power up
    //max98091_i2c_write(0x31, 0x2c); // 0db, no mute
    //max98091_i2c_write(0x32, 0x2c); // 0db, no mute
    ESP_ERROR_CHECK(max98091_i2c_write(0x3F, (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<1) | (1<<0))); // enable outputs, dacs

    //max98091_i2c_write(0x27, (1<<4) | (1<<5)); // full playback gain

    //max98091_i2c_write(0x31, 0x3f); // +14 db speaker
    //max98091_i2c_write(0x32, 0x3f); // +14 db speaker
    ESP_ERROR_CHECK(max98091_i2c_write(0x41, 0x0));

    ESP_ERROR_CHECK(max98091_i2c_write(0x3D, 1<<7)); // jack detect enable
}

static void i2s_init(void){
    init_codec();
    vTaskDelay(100 / portTICK_PERIOD_MS); // dunno if necessary
    
    static const i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_TX,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = 16,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
        //.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
        .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB,
        //^...technically wrong but works...? in idf v5 it's msb but don't try that late at night
        .intr_alloc_flags = 0, // default interrupt priority
        .dma_buf_count = DMA_BUFFER_COUNT,
        .dma_buf_len = DMA_BUFFER_SIZE,
        .use_apll = false
    };
    static const i2s_pin_config_t pin_config = {
        .bck_io_num = 10,
        .mck_io_num = 18,
        .ws_io_num = 11,
        .data_out_num = 12,
        .data_in_num = I2S_PIN_NO_CHANGE
    };
    i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);

    i2s_set_pin(I2S_PORT, &pin_config);

}

#elif defined(CONFIG_BADGE23_HW_GEN_P1)

static void i2s_init(void){
    
    static const i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_TX,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = 16,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
        //.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,

        .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
        .intr_alloc_flags = 0, // default interrupt priority
        .dma_buf_count = DMA_BUFFER_COUNT,
        .dma_buf_len = DMA_BUFFER_SIZE,
        .use_apll = false
    };
    static const i2s_pin_config_t pin_config = {
        .bck_io_num = 13,
        .mck_io_num = 11,
        .ws_io_num = 12,
        .data_out_num = 14,
        .data_in_num = I2S_PIN_NO_CHANGE
    };
    i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);

    i2s_set_pin(I2S_PORT, &pin_config);
}
#else
#error "audio not implemented for this badge generation"
#endif

typedef struct _audio_source_t{
    void * render_data;
    float (* render_function)(void *);
    uint16_t index;
    struct _audio_source_t * next;
} audio_source_t;

static audio_source_t * _audio_sources = NULL;

uint16_t add_audio_source(void * render_data, void * render_function){
    //construct audio source struct
    audio_source_t * src = malloc(sizeof(audio_source_t));
    if(src == NULL) return;
    src->render_data = render_data;
    src->render_function = render_function;
    src->next = NULL;
    src->index = 0;

    //handle empty list special case
    if(_audio_sources == NULL){
        _audio_sources = src;
        return 0; //only nonempty lists from here on out!
    }

    //searching for lowest unused index
    audio_source_t * index_source = _audio_sources;
    while(1){
        if(src->index == (index_source->index)){
            src->index++; //someone else has index already, try next
            index_source = _audio_sources; //start whole list for new index
        } else {
            index_source = index_source->next;
        }
        if(index_source == NULL){ //traversed the entire list
            break;
        }
    }

    audio_source_t * audio_source = _audio_sources;
    //append new source to linked list
    while(audio_source != NULL){
        if(audio_source->next == NULL){
            audio_source->next = src;
            break;
        } else {
        audio_source = audio_source->next;
        }
    }
    return src->index;
}

void remove_audio_source(uint16_t index){
    audio_source_t * audio_source = _audio_sources;
    audio_source_t * start_gap = NULL;

    while(audio_source != NULL){
        if(index == audio_source->index){
            if(start_gap == NULL){
                _audio_sources = audio_source->next;
            } else {
                start_gap->next = audio_source->next;
            }
            vTaskDelay(20 / portTICK_PERIOD_MS); //give other tasks time to stop using
            free(audio_source); //terrible hack tbh
            break;
        }
        start_gap = audio_source;
        audio_source = audio_source->next;
    }
}

uint16_t count_audio_sources(){
    uint16_t ret = 0;
    audio_source_t * audio_source = _audio_sources;
    while(audio_source != NULL){
        audio_source = audio_source->next;
        ret++;
    }
    return ret;
}

static void _audio_init(void) {
    init_scope(241);
    i2s_init();
    //ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
    TaskHandle_t handle;
    xTaskCreate(&audio_player_task, "Audio player", 3000, NULL, configMAX_PRIORITIES - 1, &handle);
}

#define LR_PHASE 1
#define NAT_LOG_DB 0.1151292546497023

static uint16_t _global_vol = 3000;

void set_global_vol_dB(int8_t vol_dB){
    if(vol_dB < (BADGE_MIN_VOLUME_DB)){
        _global_vol = 0;
    } else {
        if(vol_dB > (BADGE_MAX_VOLUME_DB)) vol_dB = (BADGE_MAX_VOLUME_DB);
        uint16_t buf =  3000 * exp(vol_dB * NAT_LOG_DB);
        if(buf > (BADGE_VOLUME_LIMIT)) buf = (BADGE_VOLUME_LIMIT);
        _global_vol = buf;
    }
}

static void audio_player_task(void* arg) {
    int16_t buffer[DMA_BUFFER_SIZE * 2];
    memset(buffer, 0, sizeof(buffer));

    while(true) {

        for(int i = 0; i < (DMA_BUFFER_SIZE * 2); i += 2){
            float sample = 0;
            audio_source_t * audio_source = _audio_sources;
            while(audio_source != NULL){
                sample += (*(audio_source->render_function))(audio_source->render_data);
                audio_source = audio_source->next;
            }
            write_to_scope((int16_t) (1600. * sample));
            sample = _global_vol * sample;
            if(sample > 32767) sample = 32767;
            if(sample < -32767) sample = -32767;
            buffer[i] = (int16_t) sample;
            buffer[i+1] = LR_PHASE * buffer[i];
        }

        size_t count = 0;
        i2s_write(I2S_PORT, buffer, sizeof(buffer), &count, 1000);
        if (count != sizeof(buffer)) {
            printf("i2s_write_bytes: count (%d) != length (%d)\n", count, sizeof(buffer));
            abort();
        }
    }
}

void audio_init() { _audio_init(); }


/*
#define NAT_LOG_SEMITONE 0.05776226504666215

void synth_set_bend(int i, float bend){
    if(bend != bend) return;
    if((bend > -0.0001) && (bend < 0.0001)){
        synths[i].bend = 1;
    } else {
        synths[i].bend = exp(bend * NAT_LOG_SEMITONE);
    }
}
*/

/*
void synth_stop(int i){
    if(synths[i].env_phase){
        synths[i].env_phase = 3;
    }
}

void synth_fullstop(int i){
    synths[i].env_phase = 0;
}

void synth_start(int i){
    synths[i].env_phase = 1; //put into attack phase;
}

float synth_get_env(int i){
    return synths[i].env;
}
*/
+0 −0

File added.

Preview size limit exceeded, changes collapsed.

+89 −0
Original line number Diff line number Diff line
#include "badge23/display.h"
#include "gc9a01.h"

#include "esp_log.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "badge23/scope.h"
#include "esp_system.h"

uint16_t *pixels;

typedef struct leds_cfg {
    bool active_paddles[10];
} display_cfg_t;

static QueueHandle_t display_queue = NULL;
static void display_task(TimerHandle_t aaaaa);
//static void display_task(void* arg);

static void _display_init() {
    GC9A01_Init();
    //    GC9A01_Screen_Load(0,0,240,240,pixels);
    GC9A01_Update();

    /*
    display_queue = xQueueCreate(1, sizeof(display_cfg_t));
    TaskHandle_t handle;
    xTaskCreate(&display_task, "Display", 4096, NULL, configMAX_PRIORITIES - 3, &handle);
    */
    
    /* SCOPE TASK
    TimerHandle_t aa = xTimerCreate("Display", pdMS_TO_TICKS(100), pdTRUE, (void *) 0, *display_task);
    if( xTimerStart(aa, 0 ) != pdPASS )
    {
    }
    */
}

void display_update(){
    GC9A01_Update();
}

void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col){
    GC9A01_DrawPixel(x, y, col);
}

uint16_t display_get_pixel(uint8_t x, uint8_t y){
    return GC9A01_GetPixel(x,y);
}

void display_fill(uint16_t col){
    GC9A01_FillRect(0, 0, 240, 240, col);
}

void display_draw_scope(){
    //display_cfg_t  display_;
    uint16_t line[240];
    /*
    printf("waiting...\n");
    xQueueReceive(display_queue, &display_, portMAX_DELAY);
    printf("go...\n");
    */
    //uint32_t t0 = esp_log_timestamp();
    begin_scope_read();

    for(int y=0; y<240; y++){
        read_line_from_scope(&(line[0]), y);
        memcpy(&ScreenBuff[y * 240], line, sizeof(line));
    }
    end_scope_read();

    //uint32_t td = esp_log_timestamp() - t0;
    // printf("it took %lu\n", td);
    display_update();

}
//static void display_task(void* arg) {
static void display_task(TimerHandle_t aaaaa) {
    display_draw_scope();
}

void display_init() { _display_init(); }
+84 −0
Original line number Diff line number Diff line
#include "badge23/captouch.h"
#include "badge23/audio.h"
#include "badge23/leds.h"
#include "badge23/display.h"
#include "badge23/spio.h"
#include "badge23_hwconfig.h"

#include "esp_log.h"
#include "driver/i2c.h"
#include "driver/spi_master.h"

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdint.h>

static const char *TAG = "espan";

#define I2C_MASTER_NUM              0                          /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ          400000                     /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */

#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
#define CONFIG_I2C_MASTER_SDA 2
#define CONFIG_I2C_MASTER_SCL 1

#elif defined(CONFIG_BADGE23_HW_GEN_P1)
#define CONFIG_I2C_MASTER_SDA 10
#define CONFIG_I2C_MASTER_SCL 9

#else
#error "i2c not implemented for this badge generation"
#endif

static esp_err_t i2c_master_init(void)
{
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = CONFIG_I2C_MASTER_SDA,
        .scl_io_num = CONFIG_I2C_MASTER_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    i2c_param_config(i2c_master_port, &conf);

    return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}

#define CAPTOUCH_POLLING_PERIOD 10

void os_app_main(void)
{
    ESP_LOGI(TAG, "Starting on %s...", badge23_hw_name);
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");

    set_global_vol_dB(-90);
    audio_init();
    leds_init();
    init_buttons();
    captouch_init();

    vTaskDelay(2000 / portTICK_PERIOD_MS);
    set_global_vol_dB(0);

    display_init();
    while(1) {
        manual_captouch_readout(1);
        vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
        manual_captouch_readout(0);
        vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
        update_button_state();
        vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
        //display_draw_scope();
    }

    ESP_ERROR_CHECK(i2c_driver_delete(I2C_MASTER_NUM));
    ESP_LOGI(TAG, "I2C de-initialized successfully");
}
+17 −0
Original line number Diff line number Diff line
#ifndef DEF_apa102LEDStrip
#define DEF_apa102LEDStrip

struct apa102LEDStrip
{
    unsigned char *LEDs;
    short int _frameLength;
    short int _endFrameLength;
    short int _numLEDs;
    unsigned char _bytesPerLED;
    short int _counter;
    unsigned char _globalBrightness;
};
void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness);
void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour);
void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour);
#endif
+15 −0
Original line number Diff line number Diff line
#pragma once
#include <stdint.h>

#define SAMPLE_RATE 16000
#define BADGE_MAX_VOLUME_DB 20
#define BADGE_MIN_VOLUME_DB (-80)
#define BADGE_VOLUME_LIMIT 30000

void audio_init();

void set_global_vol_dB(int8_t vol_dB);
uint16_t count_audio_sources();

uint16_t add_audio_source(void * render_data, void * render_function);
void remove_audio_source(uint16_t index);
+10 −0
Original line number Diff line number Diff line
#pragma once
#include <stdint.h>

void captouch_init(void);
void captouch_print_debug_info(void);
void gpio_event_handler(void * arg);
void manual_captouch_readout(uint8_t top);
void captouch_get_cross(int paddle, int * x, int * y);
void captouch_force_calibration();
uint16_t read_captouch();
+33 −0
Original line number Diff line number Diff line
/*
   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#pragma once
#include <stdint.h>
#include "esp_err.h"

#define IMAGE_W 240
#define IMAGE_H 240

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data.
 *
 * @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels.
 *        Effectively, you can get the pixel data by doing ``decode_image(&myPixels); pixelval=myPixels[ypos][xpos];``
 * @return - ESP_ERR_NOT_SUPPORTED if image is malformed or a progressive jpeg file
 *         - ESP_ERR_NO_MEM if out of memory
 *         - ESP_OK on succesful decode
 */
esp_err_t decode_image(uint16_t **pixels);

#ifdef __cplusplus
}
#endif
+11 −0
Original line number Diff line number Diff line
#pragma once

#include <stdbool.h>
#include <stdint.h>

void display_init();
void display_draw_scope();
void display_update();
void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col);
uint16_t display_get_pixel(uint8_t x, uint8_t y);
void display_fill(uint16_t col);
+2 −0
Original line number Diff line number Diff line
#pragma once
void os_app_main(void);
+8 −0
Original line number Diff line number Diff line
#pragma once

#include <stdint.h>
void leds_init();
void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
void leds_set_single_hsv(uint8_t index, float hue, float sat, float value);
void leds_update();
+15 −0
Original line number Diff line number Diff line
#pragma once
#include <stdint.h>

typedef struct {
    int16_t * buffer;
    int16_t buffer_size;
    int16_t write_head_position; // last written value
    volatile uint8_t is_being_read;
} scope_t;

void init_scope(uint16_t size);
void write_to_scope(int16_t value);
void begin_scope_read();
void end_scope_read();
void read_line_from_scope(uint16_t * line, int16_t point);
+6 −0
Original line number Diff line number Diff line
#pragma once
#include <stdint.h>

int8_t get_button_state(bool leftbutton);
void update_button_state();
void init_buttons();
+57 −0
Original line number Diff line number Diff line
#pragma once
#include <stdint.h>
#include <stdio.h>

#define TRAD_OSC_DECAY_STEP          0.01
#define TRAD_OSC_ATTACK_STEP          0.01
#define TRAD_OSC_MIN_ATTACK_ENV          0.01
#define TRAD_OSC_ATTACK_POP_BLOCK          16
typedef struct {
    //user variables
    float       freq;           //in hertz, negative frequencies for linFM allowed
    float       bend;
    float       vol;            //output volume
    float       env;
    uint8_t     env_phase;      //0: off, 1: attack, 2: hold, 3: decay
    uint8_t     skip_hold;
    float       gate;           //below what volume the oscillator stops and returns 0
    uint16_t    decay_steps;    //after how many sample rate steps the volume reduces
                                //by factor TRAD_OSC_DECAY_STEP, set 0 for no decay
    uint16_t    attack_steps;
    uint8_t     waveform;       //0: sine, 1: fast sine, 2: tri, 3: saw,
                                //4: square, 5: 33% pulse, 6: 25% pulse

    //internal data storage, not for user access
    float       counter;        //state of central sawtooth oscillator, [-1..1] typ.
    uint16_t    env_counter;
    int8_t      overflow_event; //set to -1 when counter underflows (below -1),
                                //set to +1 when counter overflows (above 1)
                                //not reset or used by anything so far
    uint16_t    noise_reg;
} trad_osc_t;

//#define KS_BUFFER_SIZE (SAMPLE_RATE)/20
#define KS_BUFFER_SIZE 800

typedef struct {
    //user variables
    float freq;                 //frequency in hertz, negative frequencies are rectified,
                                //minimum freq determined by KS_BUFFER_SIZE
    float feedback;             //feedback value, will be compensated with frequency
                                //for equal decay across spectrum, [-1..1] without
    
    //internal data storage, not for user access
    float tape[KS_BUFFER_SIZE]; //the delay chain
    float real_feedback;        //compensated feedback value
} ks_osc_t; //karplus strong

float run_trad_osc(trad_osc_t * osc);

void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend);
void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq);
void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform);
void trad_osc_set_attack(trad_osc_t * osc, uint16_t attack);
void trad_osc_set_decay(trad_osc_t * osc, uint16_t decay);
void trad_env_stop(trad_osc_t * osc);
void trad_env_fullstop(trad_osc_t * osc);
void trad_env_start(trad_osc_t * osc);
+73 −0
Original line number Diff line number Diff line
void render_audio(
    instrument_descriptor_t instrument_descriptor,
    instrument_t instance,
    unsigned int sample_count,
    float * output_vector
){
    for(unsigned int i = 0; i < sample_count; i++){
        instrument_descriptor->render_audio_sample(instance, sample_count, output_vector[2*i]);
    }
}

void render_audio_adding(
    instrument_descriptor_t instrument_descriptor,
    instrument_t instance,
    unsigned int sample_count,
    float * output_vector,
    float gain
){
    if(gain <= 0.0000001) return;
    float temp[2];
    for(unsigned int i = 0; i < sample_count; i++){
        instrument_descriptor->render_audio_sample(instance, sample_count, temp);
        output_vector[2*i] += gain * buffer[0];
        output_vector[2*i+1] += gain * buffer[1];
    }
}

void append_instrument_descriptor(
    instrument_descriptor_list_t * list,
    void * construct_instrument_descriptor
){
    lle_t * element = list;
    while(element->next != NULL){
        element = element->next;
    }
    element->next = malloc(sizeof(lle_t);
    if(element->next == NULL) return;
    element = element->next;
    element->next = NULL;

    element->content = construct_instrument_descriptor();
}

instrument_descriptor_list_t * list_builtin_instrument_descriptors(){
    //really hope we can make this more elegant some day
    instrument_descriptor_list_t * list = NULL;

    //add your instrument here!
    append_instrument_descriptor(list, &minimal_example_descriptor);

    return list;
}

void instantiate_instrument(active_instrument_list_t instruments,
                            instrument_descriptor_t descriptor
){
    descriptor->new_instrument
}

void mix_instruments_audio(active_instrument_list_t instruments,
                           unsigned int sample_count,
                           float * output_vector
){
    active_instrument_t instrument = instruments;
    while(instrument->next != NULL){
        render_audio_adding(instrument->descriptor,
                            instrument->instrument,
                            sample_count,
                            output_vector,
                            instrument->gain)
        instrument = instrument->next;
    }
}
+130 −0
Original line number Diff line number Diff line
/* wip instrument api for badge23 (in large parts inspired by ladspa)

current status: none of this is hooked up or functional or compiles, just drafting things rn

some core concepts:

- several instruments can run at the same time (e.g., drum computer running in background),
with only one of them being in foreground and using buttons and display

- instruments are as "self contained" as possible, i.e. they access buttons and display with
minimal host involvement and pretty much just produce audio "on their own". aside from
scheduling the host mostly does some cap touch preprocessing and the audio output mixdown

- different timing requirements -> different "threads" for audio, buttons, display each
(leds: special case, see below)

open questions:

- led animations: instruments should be able to output led patterns. maybe keeping a dummy
led array in ram for each running instrument and allowing users to create and run "shaders"
would be a desirable functional mode; do we want this/does this need any extra api?

- for performance reasons: instruments are expected to behave themselves, i.e. not access hw
without permission or write to read-only locations, can we do better than that without
excessive overhead? and if we can, do we _want_ to? (devices that make electronic musical
instruments malfunction on purpose are not uncommon in general)

- badge link/cv data input/output: can probably be added to the descriptor easily? shouldn't
freeze api before tho
*/

//===========================================================================================
//some hardware dummy definitions, move somewhere else someday maybe
typedef struct {
    int intensity;  //touch strength, considered as no touch if below 0
    int rad;        //radial position
    int az;         //cw azimuthal position (only meaningful for top petals);
} petal_t;

typedef int button_t; //0: no press, -1: left, 1: right, 2: down

typedef struct {    //read-only (shared between all instruments, unprotected)
    petal_t petals[10];  //even: top, odd: bottom, 0 at usb-c jack, count ccw
    button_t button;    //can be either left or right, depending on host
                        //handedness settings. the other button is reserved for
                        //host use and is not exposed here.
} hardware_inputs_t;
//===========================================================================================

typedef void * instrument_t; //contains instrument instance data, not to be interpreted by host

typedef struct _instrument_descriptor_t {
    unsigned int unique_id;
    //null terminated instrument name
    const char * name;

    //allocates memory for new instance data and returns pointer to it (mandatory)
    instrument_t (* new_instrument)(const struct _instrument_descriptor * descriptor,
                                    unsigned int sample_rate,
                                    hardware_inputs_t * hw);

    //frees instance data memory (mandatory)
    void (* delete_instrument) (instrument_t instance);

    //renders a single stereo audio sample (optional, NULL if not supported)
    void (* render_audio_sample) (instrument_t instance);

    //handles petal/button/sensor input, ideally runs every 3-8ms (optional, NULL if not supported)
    void (* process_user_input) (instrument_t instance);

    //only runs when instrument is in foreground (optional, NULL if not supported)
    void (* update_display) (instrument_t instance);

    //(optional, NULL if not supported)
    void (* update_leds) (instrument_t instance);
} instrument_descriptor_t;

// this function is called once per instrument type before use (i.e. around boot) and returns a
// filled out instrument descriptor struct to be used by the host for creating instrument instances
// returns null if allocation fails
const instrument_descriptor_t * contruct_instrument_descriptor();

//===========================================================================================
//host-side helper functions

void render_audio(
    instrument_descriptor_t instrument_descriptor,
    instrument_t instance,
    unsigned int sample_count,
    float * output_vector
);

void render_audio_adding(
    instrument_descriptor_t instrument_descriptor,
    instrument_t instance,
    unsigned int sample_count,
    float * output_vector,
    float gain
);

typedef struct {
    void * content;
    lle_t * next;
} lle_t; //linked list element

typedef lle_t instrument_descriptor_list_t;

typedef struct {
    instrument_t * instrument;
    instrument_descriptor_t descriptor;
    char is_foreground;
    char is_rendering_leds;
    float gain;
} active_instrument_t;

void append_instrument_descriptor(
    instrument_descriptor_list_t * list,
    void * construct_instrument_descriptor
);

instrument_descriptor_list_t * list_builtin_instrument_descriptors();

typedef lle_t active_instrument_list_t;
void mix_instruments_audio(active_instrument_list_t instruments,
                           unsigned int sample_count,
                           float * output_vector
);


//===========================================================================================
+89 −0
Original line number Diff line number Diff line
//simple instrument example implementation

//trad_osc is made up rn, didn't check how the existing implementation works

typedef struct{
    unsigned int * sample_rate;
    hardware_inputs_t * hw;
    trad_osc_t[30] osc;
    unsigned int sample_rate;
    hardware_inputs_t * hw;
    float last_freq; //frequency of last note played to write to display
} minimal_example_t;

void minimal_example_render_sample(instrument_handle inst, float * stereo_output){
    float acc = 0;
    for(int i = 0; i < 30; i++){
        acc += trad_osc_run(&inst.osc[i], inst.sample_rate);
    }
    stereo_output[0] = acc; // both channels the same -> mono
    stereo_output[1] = acc;
}

void minimal_example_process_user_input(instrument_handle inst){
    static int petal_prev[10];
    for(int i = 0; i < 10; i++){
        if(inst->hw.petals[i].intensity > 0){    //if the pad is touched...
            if(!petal_prev[i]){                 //and it's a new touch...
                if(button != 2){ //if button isn't pressed: play single note in different octaves
                    int j = i + (inst->hw.button + 1) * 10; //choose osc
                    trad_osc_start(&inst.osc[j]);   //play a tone
                    inst->last_freq = inst.osc[j].freq;
                } else { //for button center: all the octaves at once
                    trad_osc_start(&inst.osc[i]);   //play a tone
                    trad_osc_start(&inst.osc[i+10]);   //play a tone
                    trad_osc_start(&inst.osc[i+20]);   //play a tone
                    inst->last_freq = inst.osc[i+10].freq;
                }
            }
            petal_prev[i] = 1;
        } else {
            petal_prev[i] = 0;
        }
    }
}

void minimal_example_update_display(instrument_handle inst){
    display_print("%f", inst->last_freq);
}

static float pad_to_freq(int pad){
    int j = pad % 10;
    if(j) j++;      //skip min 2nd
    if(j>8) j++;    //skip maj 6th
    j += (pad/10) * 12; //add octaves
    float freq = 440 * pow(2., j/12.);
}

instrument_t new_minimal_example(
    const struct _instrument_descriptor * descriptor, 
    unsigned int sample_rate,
    hardware_inputs_t * hw)
{
    instrument_t inst = malloc(sizeof(minimal_example_t));
    if(inst == NULL) return NULL;
    inst->sample_rate = sample_rate;
    inst->hw = hw;
    for(int i = 0; i < 30; i++){
        inst->osc[i] = trad_osc_new(pad_to_freq(i), sample_rate);
        //other osc parameters (wave, envelope, etc.) omitted for clarity
    }
    return inst;
}

void delete_minimal_example(instrument_t inst){
    free(inst);
}

const instrument_descriptor_t * minimal_example_descriptor(){
    instrument_descriptor_t * inst = malloc(sizeof(instrument_descriptor_t));
    if(inst == NULL) return NULL;
    inst->unique_id = 0;
    inst->name = "simple instrument";
    inst->render_audio_sample = &minimal_example_render_sample;
    inst->new_instrument = &new_minimal_example;
    inst->delete_instrument = &delete_minimal_example;
    inst->update_display = NULL;
    inst->process_user_input = minimal_example_user_input;
    inst->update_leds = NULL;
}
+245 −0
Original line number Diff line number Diff line
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "esp_system.h"
#include "badge23/leds.h"
#include "badge23_hwconfig.h"

#if defined(CONFIG_BADGE23_HW_GEN_P1)
#define LED_SPI_PORT

#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
#define LED_ASYNC_PORT

#else
#error "leds not implemented for this badge generation"
#endif

typedef struct leds_cfg {
    int             leaf;
    size_t          size;
    size_t          position;
    size_t          slot;
    int             timer;
} leds_cfg_t;

static leds_cfg_t active_leds[11];

struct RGB
{
    unsigned char R;
    unsigned char G;
    unsigned char B;
};

struct HSV
{
    double H;
    double S;
    double V;
};

struct RGB HSVToRGB(struct HSV hsv) {
    double r = 0, g = 0, b = 0;

    if (hsv.S == 0)
    {
        r = hsv.V;
        g = hsv.V;
        b = hsv.V;
    }
    else
    {
        int i;
        double f, p, q, t;

        if (hsv.H == 360)
            hsv.H = 0;
        else
            hsv.H = hsv.H / 60;

        i = (int)trunc(hsv.H);
        f = hsv.H - i;

        p = hsv.V * (1.0 - hsv.S);
        q = hsv.V * (1.0 - (hsv.S * f));
        t = hsv.V * (1.0 - (hsv.S * (1.0 - f)));

        switch (i)
        {
            case 0:
                r = hsv.V;
                g = t;
                b = p;
                break;

            case 1:
                r = q;
                g = hsv.V;
                b = p;
                break;

            case 2:
                r = p;
                g = hsv.V;
                b = t;
                break;

            case 3:
                r = p;
                g = q;
                b = hsv.V;
                break;

            case 4:
                r = t;
                g = p;
                b = hsv.V;
                break;

            default:
                r = hsv.V;
                g = p;
                b = q;
                break;
        }

    }

    struct RGB rgb;
    rgb.R = r * 255;
    rgb.G = g * 255;
    rgb.B = b * 255;

    return rgb;
}

#ifdef LED_SPI_PORT
#include "driver/spi_master.h"
#include "badge23/apa102LEDStrip.h"

#define totalPixels 40
#define bytesPerPixel 4

static struct apa102LEDStrip leds;
static spi_device_handle_t spi_led;
static spi_transaction_t spiTransObject;
static esp_err_t ret;
static spi_bus_config_t buscfg;
static spi_device_interface_config_t devcfg;

#define maxSPIFrameInBytes 8000
#define maxSPIFrequency 10000000

void renderLEDs()
{
    spi_device_queue_trans(spi_led, &spiTransObject, portMAX_DELAY);
}

static int setupSPI()
{
    //Set up the Bus Config struct
    buscfg.miso_io_num=-1;
    buscfg.mosi_io_num=18;
    buscfg.sclk_io_num=8;
    buscfg.quadwp_io_num=-1;
    buscfg.quadhd_io_num=-1;
    buscfg.max_transfer_sz=maxSPIFrameInBytes;

    //Set up the SPI Device Configuration Struct
    devcfg.clock_speed_hz=maxSPIFrequency;
    devcfg.mode=0;
    devcfg.spics_io_num=-1;
    devcfg.queue_size=1;

    //Initialize the SPI driver
    ret=spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    //Add SPI port to bus
    ret=spi_bus_add_device(SPI2_HOST, &devcfg, &spi_led);
    ESP_ERROR_CHECK(ret);
    return ret;
}

void set_single_led(uint8_t index, uint8_t c[3]){
    setPixel(&leds, index, c);
}

static void _leds_init() {
    memset(active_leds, 0 , sizeof(active_leds));

    setupSPI();
    initLEDs(&leds, totalPixels, bytesPerPixel, 255);

    //Set up SPI tx/rx storage Object
    memset(&spiTransObject, 0, sizeof(spiTransObject));
    spiTransObject.length = leds._frameLength*8;
    spiTransObject.tx_buffer = leds.LEDs;


    TaskHandle_t handle;
    //xTaskCreate(&leds_task, "LEDs player", 4096, NULL, configMAX_PRIORITIES - 2, &handle);
}
#endif

#ifdef LED_ASYNC_PORT
#include "../../espressif__led_strip/include/led_strip.h"
led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num);

#define LED_GPIO_NUM 14
#define LED_RMT_CHAN 0

led_strip_t * led_strip;

static void _leds_init(){
    memset(active_leds, 0 , sizeof(active_leds));
    led_strip = led_strip_init(LED_RMT_CHAN, LED_GPIO_NUM, 40);
}

void set_single_led(uint8_t index, uint8_t c[3]){
    index = ((39-index) + 1 + 32)%40;
    led_strip->set_pixel(led_strip, index, c[0], c[1], c[2]);
}

static void renderLEDs(){
    led_strip->refresh(led_strip, 1000);
}

#endif

void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue){
    index = (index + 3) % 40;
    uint8_t c[3];
    c[0] = red;
    c[1] = green;
    c[2] = blue;
    set_single_led(index, c);
}
 
void leds_set_single_hsv(uint8_t index, float hue, float sat, float val){
    index = (index + 3) % 40;
    struct RGB rgb;
    struct HSV hsv;
    hsv.H = hue;
    hsv.S = sat;
    hsv.V = val;
    
    rgb = HSVToRGB(hsv);

    uint8_t c[3];
    c[0] = rgb.R;
    c[1] = rgb.G;
    c[2] = rgb.B;
    set_single_led(index, c);
}

void leds_update(){
    vTaskDelay(10 / portTICK_PERIOD_MS); //do we...
    renderLEDs();
    vTaskDelay(10 / portTICK_PERIOD_MS); //...need these?
}

void leds_init() { _leds_init(); }
+63 −0
Original line number Diff line number Diff line
#include "badge23/scope.h"
#include <string.h>

scope_t * scope;

void init_scope(uint16_t size){
    scope_t * scp = malloc(sizeof(scope_t));
    if(scp == NULL) scope = NULL;
    scp->buffer_size = size;
    scp->buffer = malloc(sizeof(int16_t) * scp->buffer_size);
    if(scp->buffer == NULL){
        free(scp);
        scope = NULL;
    } else {
        memset(scp->buffer, 0, sizeof(int16_t) * scp->buffer_size);
        scope = scp;
    }
}

void write_to_scope(int16_t value){
    if(scope->is_being_read) return;
    if(scope == NULL) return;
    scope->write_head_position++;
    if(scope->write_head_position >= scope->buffer_size) scope->write_head_position = 0;
    scope->buffer[scope->write_head_position] = value;
}

void begin_scope_read(){
    if(scope == NULL) return;
    scope->is_being_read = 1; //best mutex
}

void read_line_from_scope(uint16_t * line, int16_t point){
    memset(line, 0, 480);
    int16_t startpoint = scope->write_head_position - point;
    while(startpoint < 0){
        startpoint += scope->buffer_size;
    }
    int16_t stoppoint = startpoint - 1;
    if(stoppoint < 0){
        stoppoint += scope->buffer_size;
    }
    int16_t start = (scope->buffer[point]/32 + 120);
    int16_t stop = (scope->buffer[point+1]/32 + 120);
    if(start>240)   start = 240;
    if(start<0)     start = 0;
    if(stop>240)    stop = 240;
    if(stop<0)     stop = 0;

    if(start > stop){
        int16_t inter = start;
        start = stop;
        stop = inter;
    }
    for(int16_t i = start; i <= stop; i++){
        line[i] = 255;
    }
}

void end_scope_read(){
    if(scope == NULL) return;
    scope->is_being_read = 0; //best mutex
}
+140 −0
Original line number Diff line number Diff line
//special purpose input outputs
#include "driver/gpio.h"
#include "badge23_hwconfig.h"
#include "stdint.h"

static int8_t leftbutton = 0;
static int8_t rightbutton = 0;

#if defined(CONFIG_BADGE23_HW_GEN_P1)

#define RIGHT_BUTTON_LEFT 37
#define RIGHT_BUTTON_MID 0
#define RIGHT_BUTTON_RIGHT 35

#define LEFT_BUTTON_LEFT 7
#define LEFT_BUTTON_MID 6
#define LEFT_BUTTON_RIGHT 5

static void _init_buttons(){
    //configure all buttons as pullup
    uint64_t mask = 0;
    mask |= (1ULL << RIGHT_BUTTON_LEFT);
    mask |= (1ULL << RIGHT_BUTTON_RIGHT);
    mask |= (1ULL << LEFT_BUTTON_LEFT);
    mask |= (1ULL << LEFT_BUTTON_MID);
    mask |= (1ULL << LEFT_BUTTON_RIGHT);
    gpio_config_t cfg = {
        .pin_bit_mask = mask,
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    ESP_ERROR_CHECK(gpio_config(&cfg));
    cfg.pin_bit_mask = 1;
    cfg.pull_up_en = GPIO_PULLUP_DISABLE;
    ESP_ERROR_CHECK(gpio_config(&cfg));
}

void update_button_state(){
    if(!gpio_get_level(RIGHT_BUTTON_LEFT)){
        rightbutton = -1;
    } else if(!gpio_get_level(RIGHT_BUTTON_MID)){
        rightbutton = 2;
    } else if(!gpio_get_level(RIGHT_BUTTON_RIGHT)){
        rightbutton = 1;
    } else {
        rightbutton = 0;
    }

    if(!gpio_get_level(LEFT_BUTTON_LEFT)){
        leftbutton = -1;
    } else if(!gpio_get_level(LEFT_BUTTON_MID)){
        leftbutton = 2;
    } else if(!gpio_get_level(LEFT_BUTTON_RIGHT)){
        leftbutton = 1;
    } else {
        leftbutton = 0;
    }
}

#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)

#include "driver/i2c.h"
#define I2C_MASTER_NUM 0
#define TIMEOUT_MS 1000

//on ESP32
#define LEFT_BUTTON_LEFT 3
#define LEFT_BUTTON_MID 0

//on PORTEXPANDER
#define LEFT_BUTTON_RIGHT 0
#define RIGHT_BUTTON_LEFT 6
#define RIGHT_BUTTON_MID 5
#define RIGHT_BUTTON_RIGHT 7

static void _init_buttons(){
    //configure all buttons as pullup
    gpio_config_t cfg = {
        .pin_bit_mask = 1 << LEFT_BUTTON_LEFT,
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    ESP_ERROR_CHECK(gpio_config(&cfg));
    cfg.pin_bit_mask = 1;
    cfg.pull_up_en = GPIO_PULLUP_DISABLE;
    ESP_ERROR_CHECK(gpio_config(&cfg));
    printf("nya\n");
}

void update_button_state(){
    uint8_t port;
    esp_err_t ret = i2c_master_read_from_device(I2C_MASTER_NUM, 0b1101101, &port, sizeof(port), TIMEOUT_MS / portTICK_PERIOD_MS);
    uint8_t rr = port & (1ULL << RIGHT_BUTTON_RIGHT);
    uint8_t rm = port & (1ULL << RIGHT_BUTTON_MID);
    uint8_t rl = port & (1ULL << RIGHT_BUTTON_LEFT);
    uint8_t lr = port & (1ULL << LEFT_BUTTON_RIGHT);
    uint8_t ll = gpio_get_level(LEFT_BUTTON_LEFT);
    uint8_t lm = gpio_get_level(LEFT_BUTTON_MID);

    if(!rl){
        rightbutton = -1;
    } else if(!rm){
        rightbutton = 2;
    } else if(!rr){
        rightbutton = 1;
    } else {
        rightbutton = 0;
    }

    if(!ll){
        leftbutton = -1;
    } else if(!lm){
        leftbutton = 2;
    } else if(!lr){
        leftbutton = 1;
    } else {
        leftbutton = 0;
    }
}

#else
#error "spio not implemented for this badge generation"
#endif

void init_buttons(){
    _init_buttons();
}

//#define ALWAYS_UPDATE_BUTTON
int8_t get_button_state(bool left){
#ifdef ALWAYS_UPDATE_BUTTON
    update_button_state();
#endif
    if(left) return leftbutton;
    return rightbutton;
}
+201 −0
Original line number Diff line number Diff line
#include "badge23/synth.h"
#include "badge23/audio.h"
#include <math.h>

float ks_osc(ks_osc_t * ks, float input){
    //TODO: FIX THIS
    ks->real_feedback = ks->feedback;

    float delay_time = ((float) (SAMPLE_RATE))/ks->freq;
    if(delay_time >= (KS_BUFFER_SIZE)) delay_time = (KS_BUFFER_SIZE) - 1;


    //ks->tape[0] = input + real_feedback * ks->tape[delay_time];    
    return ks->tape[0];
}

float waveshaper(uint8_t shape, float in);
float nes_noise(uint16_t * reg, uint8_t mode, uint8_t run);

void run_trad_env(trad_osc_t * osc){
    switch(osc->env_phase){
        case 0:
            osc->env = 0; osc->counter = 0; osc->env_counter = 0;
            break;
        case 1:
            if(osc->attack_steps){
                if(osc->env == 0){
                    osc->env = (TRAD_OSC_MIN_ATTACK_ENV);
                } else {
                    osc->env_counter++;
                    if(osc->env_counter > osc->attack_steps){
                        osc->env *= (1. + (TRAD_OSC_ATTACK_STEP));
                        osc->env_counter = 0;
                    }
                }
            } else {
                osc->env += osc->vol/TRAD_OSC_ATTACK_POP_BLOCK;
            }
            if(osc->env > osc->vol){
                osc->env_phase = 2;
                osc->env = osc->vol;
            }
            break;
        case 2:
            osc->env = osc->vol;
            osc->env_counter = 0;
            if(osc->skip_hold) osc->env_phase = 3;
            break;
        case 3:
            if(osc->decay_steps){
                osc->env_counter++;
                if(osc->env_counter > osc->decay_steps){
                    osc->env *= (1. - (TRAD_OSC_DECAY_STEP));
                    osc->env_counter = 0;
                }
                if(osc->env < osc->gate){
                    osc->env_phase = 0; osc->env = 0; osc->counter = 0;
                }
            } else {
                osc->env_phase = 0; osc->env = 0; osc->counter = 0;
            }
            break;
    }
}

float run_trad_osc(trad_osc_t * osc){
    run_trad_env(osc);
    if(!osc->env_phase) return 0;
    float ret = 0;

    //run core sawtooth
    float freq = osc->freq * osc->bend;
    if(freq > 10000) freq = 10000;
    if(freq < -10000) freq = -10000;
    if(freq != freq) freq = 0;
    osc->counter += 2. * freq / ((float)(SAMPLE_RATE));
    if(osc->counter != osc->counter){
        printf("trad_osc counter is NaN");
        abort();
    }
    while(osc->counter > 1.){
        osc->counter -= 2.;
        osc->overflow_event = 1;
    }
    while(osc->counter < -1.){
        osc->counter += 2.;
        osc->overflow_event = -1;
    }

    if(osc->waveform >= 7){
        ret = nes_noise(&(osc->noise_reg), osc->waveform == 7, osc->overflow_event);
        osc->overflow_event = 0;
    } else {
        //apply waveshaper
        ret = waveshaper(osc->waveform, osc->counter);
    }

    //apply volume
    ret *= osc->env;
    return ret;
}

float nes_noise(uint16_t * reg, uint8_t mode, uint8_t run){
    if(run) {
        uint8_t fb = *reg;
        if(mode){
            fb = fb>>6;
        } else {
            fb = fb>>1;
        }
        fb = (fb ^ (*reg)) & 1;
        *reg = (*reg >> 1);
        *reg = (*reg) | (((uint16_t) fb) << 14);
    }
    return ((float) ((*reg) & 1)) * 2 - 1;
}

float waveshaper(uint8_t shape, float in){
    //expects sawtooth input in [-1..1] range
    switch(shape){
        case 0: // TODO: implement proper sine
            in = sin(in * 3.1415);
            break;
        case 1: //fast sine
            in = waveshaper(2, in);
            if(in > 0.){
                in = 1. - in;
                in *= in;
                in = 1. - in;
            } else {
                in = 1. + in;
                in *= in;
                in = in - 1.;
            }
            break;
        case 2: //triangle
            in += 0.5;
            if(in > 1.0) in -= 2;
            if(in > 0.) in = -in;
            in = (2. * in) + 1.;
            break;
        case 3: //sawtooth
            break;
        case 4: //square
            if(in > 0){
                in = 1.;
            } else {
                in = -1.;
            }
            break;
        case 5: //33% pulse
            if(in > 0.33){
                in = 1.;
            } else {
                in = -1.;
            }
            break;
        case 6: //25% pulse
            if(in > 0.5){
                in = 1.;
            } else {
                in = -1.;
            }
            break;
    }
    return in;
}

#define NAT_LOG_SEMITONE 0.05776226504666215

void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend){
    osc->freq = 440. * exp(bend * NAT_LOG_SEMITONE);
}

void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq){
    osc->freq = freq;
}

void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform){
    osc->waveform = waveform;
}

void trad_osc_set_attack(trad_osc_t * osc, uint16_t attack){
    osc->attack_steps = attack;
}

void trad_osc_set_decay(trad_osc_t * osc, uint16_t decay){
    osc->decay_steps = decay;
}

void trad_env_stop(trad_osc_t * osc){
    if(osc->env_phase) osc->env_phase = 3; 
}

void trad_env_fullstop(trad_osc_t * osc){
    osc->env_phase = 0; //stop and skip decay phase
}

void trad_env_start(trad_osc_t * osc){
    osc->env_phase = 1; //put into attack phase;
}
+162 −0
Original line number Diff line number Diff line
!_TAG_FILE_FORMAT	2	/extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED	1	/0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_EXCMD	mixed	/number, pattern, mixed, or combineV2/
!_TAG_OUTPUT_FILESEP	slash	/slash or backslash/
!_TAG_OUTPUT_MODE	u-ctags	/u-ctags or e-ctags/
!_TAG_PATTERN_LENGTH_LIMIT	96	/0 for no limit/
!_TAG_PROC_CWD	/home/zjfms/fluff/badge2023/bootstrap/software/espan/main/	//
!_TAG_PROGRAM_AUTHOR	Universal Ctags Team	//
!_TAG_PROGRAM_NAME	Universal Ctags	/Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL	https://ctags.io/	/official site/
!_TAG_PROGRAM_VERSION	5.9.0	/p5.9.20220828.0/
AD7147_BASE_ADDR	captouch.c	/^#define AD7147_BASE_ADDR /;"	d	file:
AD7147_REG_DEVICE_ID	captouch.c	/^#define AD7147_REG_DEVICE_ID /;"	d	file:
AD7147_REG_PWR_CONTROL	captouch.c	/^#define AD7147_REG_PWR_CONTROL /;"	d	file:
AD7147_REG_STAGE_CAL_EN	captouch.c	/^#define AD7147_REG_STAGE_CAL_EN /;"	d	file:
AD7147_REG_STAGE_HIGH_INT_ENABLE	captouch.c	/^#define AD7147_REG_STAGE_HIGH_INT_ENABLE /;"	d	file:
CIN	captouch.c	/^#define CIN /;"	d	file:
CIN_BIAS	captouch.c	/^#define CIN_BIAS /;"	d	file:
CIN_CDC_NEG	captouch.c	/^#define CIN_CDC_NEG /;"	d	file:
CIN_CDC_POS	captouch.c	/^#define CIN_CDC_POS /;"	d	file:
CONFIG_I2C_MASTER_SCL	Kconfig.projbuild	/^    config I2C_MASTER_SCL$/;"	c	menu:Example Configuration
CONFIG_I2C_MASTER_SCL_MODULE	Kconfig.projbuild	/^    config I2C_MASTER_SCL$/;"	c	menu:Example Configuration
CONFIG_I2C_MASTER_SDA	Kconfig.projbuild	/^    config I2C_MASTER_SDA$/;"	c	menu:Example Configuration
CONFIG_I2C_MASTER_SDA_MODULE	Kconfig.projbuild	/^    config I2C_MASTER_SDA$/;"	c	menu:Example Configuration
DEF_apa102LEDStrip	apa102LEDStrip.h	/^#define DEF_apa102LEDStrip$/;"	d
DMA_BUFFER_COUNT	audio.c	/^#define DMA_BUFFER_COUNT /;"	d	file:
DMA_BUFFER_SIZE	audio.c	/^#define DMA_BUFFER_SIZE /;"	d	file:
ESP_INTR_FLAG_DEFAULT	captouch.c	/^#define ESP_INTR_FLAG_DEFAULT /;"	d	file:
Example Configuration	Kconfig.projbuild	/^menu "Example Configuration"$/;"	m
I2C_MASTER_FREQ_HZ	espan.c	/^#define I2C_MASTER_FREQ_HZ /;"	d	file:
I2C_MASTER_NUM	captouch.c	/^#define I2C_MASTER_NUM /;"	d	file:
I2C_MASTER_NUM	espan.c	/^#define I2C_MASTER_NUM /;"	d	file:
I2C_MASTER_RX_BUF_DISABLE	espan.c	/^#define I2C_MASTER_RX_BUF_DISABLE /;"	d	file:
I2C_MASTER_SCL	Kconfig.projbuild	/^    config I2C_MASTER_SCL$/;"	c	menu:Example Configuration
I2C_MASTER_SCL_IO	espan.c	/^#define I2C_MASTER_SCL_IO /;"	d	file:
I2C_MASTER_SDA	Kconfig.projbuild	/^    config I2C_MASTER_SDA$/;"	c	menu:Example Configuration
I2C_MASTER_SDA_IO	espan.c	/^#define I2C_MASTER_SDA_IO /;"	d	file:
I2C_MASTER_TX_BUF_DISABLE	espan.c	/^#define I2C_MASTER_TX_BUF_DISABLE /;"	d	file:
LEDs	apa102LEDStrip.h	/^    unsigned char *LEDs;$/;"	m	struct:apa102LEDStrip	typeref:typename:unsigned char *
MIN	audio.c	/^#define MIN(/;"	d	file:
SAMPLE_RATE	audio.c	/^#define SAMPLE_RATE /;"	d	file:
TAG	captouch.c	/^static const char *TAG = "captouch";$/;"	v	typeref:typename:const char *	file:
TAG	espan.c	/^static const char *TAG = "espan";$/;"	v	typeref:typename:const char *	file:
TIMEOUT_MS	captouch.c	/^#define TIMEOUT_MS /;"	d	file:
_audio_init	audio.c	/^static void _audio_init(int i2s_num) {$/;"	f	typeref:typename:void	file:
_bytesPerLED	apa102LEDStrip.h	/^    unsigned char _bytesPerLED;$/;"	m	struct:apa102LEDStrip	typeref:typename:unsigned char
_counter	apa102LEDStrip.h	/^    short int _counter;$/;"	m	struct:apa102LEDStrip	typeref:typename:short int
_endFrameLength	apa102LEDStrip.h	/^    short int _endFrameLength;$/;"	m	struct:apa102LEDStrip	typeref:typename:short int
_frameLength	apa102LEDStrip.h	/^    short int _frameLength;$/;"	m	struct:apa102LEDStrip	typeref:typename:short int
_globalBrightness	apa102LEDStrip.h	/^    unsigned char _globalBrightness;$/;"	m	struct:apa102LEDStrip	typeref:typename:unsigned char
_numLEDs	apa102LEDStrip.h	/^    short int _numLEDs;$/;"	m	struct:apa102LEDStrip	typeref:typename:short int
active_paddles	espan.c	/^static bool active_paddles[10];$/;"	v	typeref:typename:bool[10]	file:
active_sounds	audio.c	/^static sound_cfg_t active_sounds[11];$/;"	v	typeref:typename:sound_cfg_t[11]	file:
ad7147_device_config	captouch.c	/^struct ad7147_device_config {$/;"	s	file:
ad7147_stage_config	captouch.c	/^struct ad7147_stage_config {$/;"	s	file:
ad714x_chip	captouch.c	/^struct ad714x_chip {$/;"	s	file:
ad714x_default_config	captouch.c	/^static struct ad7147_stage_config ad714x_default_config(void)$/;"	f	typeref:struct:ad7147_stage_config	file:
ad714x_i2c_read	captouch.c	/^static esp_err_t ad714x_i2c_read(const struct ad714x_chip *chip, const uint16_t reg, uint16_t *d/;"	f	typeref:typename:esp_err_t	file:
ad714x_i2c_write	captouch.c	/^static esp_err_t ad714x_i2c_write(const struct ad714x_chip *chip, const uint16_t reg, const uint/;"	f	typeref:typename:esp_err_t	file:
ad714x_set_device_config	captouch.c	/^static void ad714x_set_device_config(const struct ad714x_chip *chip, const struct ad7147_device_/;"	f	typeref:typename:void	file:
ad714x_set_stage_config	captouch.c	/^static void ad714x_set_stage_config(const struct ad714x_chip *chip, const uint8_t stage, const s/;"	f	typeref:typename:void	file:
addr	captouch.c	/^    uint8_t addr;$/;"	m	struct:ad714x_chip	typeref:typename:uint8_t	file:
afe_offsets	captouch.c	/^    int afe_offsets[13];$/;"	m	struct:ad714x_chip	typeref:typename:int[13]	file:
apa102LEDStrip	apa102LEDStrip.h	/^struct apa102LEDStrip$/;"	s
app_main	espan.c	/^void app_main(void)$/;"	f	typeref:typename:void
audio_init	audio.c	/^void audio_init() { _audio_init(0); }$/;"	f	typeref:typename:void
audio_player_task	audio.c	/^static void audio_player_task(void* arg) {$/;"	f	typeref:typename:void	file:
avg_fp_skip	captouch.c	/^    unsigned int avg_fp_skip:2;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:2	file:
avg_lp_skip	captouch.c	/^    unsigned int avg_lp_skip:2;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:2	file:
bank2	captouch.c	/^static const uint16_t bank2 = 0x80;$/;"	v	typeref:typename:const uint16_t	file:
black	espan.c	/^uint8_t black[] = {0,0,0};$/;"	v	typeref:typename:uint8_t[]
blue	espan.c	/^uint8_t blue[] = {0,0,32};$/;"	v	typeref:typename:uint8_t[]
bot_map	espan.c	/^uint8_t bot_map[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4};$/;"	v	typeref:typename:uint8_t[]
buffer	audio.c	/^    const int16_t*  buffer;$/;"	m	struct:sound_cfg	typeref:typename:const int16_t *	file:
buscfg	espan.c	/^spi_bus_config_t buscfg;$/;"	v	typeref:typename:spi_bus_config_t
bytesPerPixel	espan.c	/^#define bytesPerPixel /;"	d	file:
captouch_init	captouch.c	/^void captouch_init(void)$/;"	f	typeref:typename:void
captouch_init_chip	captouch.c	/^static void captouch_init_chip(const struct ad714x_chip* chip)$/;"	f	typeref:typename:void	file:
captouch_print_debug_info	captouch.c	/^void captouch_print_debug_info(void)$/;"	f	typeref:typename:void
captouch_print_debug_info_chip	captouch.c	/^static void captouch_print_debug_info_chip(const struct ad714x_chip* chip)$/;"	f	typeref:typename:void	file:
cdc_bias	captouch.c	/^    unsigned int cdc_bias:2;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:2	file:
chip_bot	captouch.c	/^static const struct ad714x_chip chip_bot = {.addr = AD7147_BASE_ADDR, .gpio = 3, .afe_offsets = /;"	v	typeref:typename:const struct ad714x_chip	file:
chip_top	captouch.c	/^static const struct ad714x_chip chip_top = {.addr = AD7147_BASE_ADDR + 1, .gpio = 48, .afe_offse/;"	v	typeref:typename:const struct ad714x_chip	file:
cinX_connection_setup	captouch.c	/^    unsigned int cinX_connection_setup[13];$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int[13]	file:
decimation	captouch.c	/^    unsigned int decimation:2;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:2	file:
devcfg	espan.c	/^spi_device_interface_config_t devcfg;$/;"	v	typeref:typename:spi_device_interface_config_t
espan_handle_captouch	espan.c	/^void espan_handle_captouch(uint16_t pressed_top, uint16_t pressed_bot)$/;"	f	typeref:typename:void
ext_source	captouch.c	/^    unsigned int ext_source:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
free_buffer	audio.c	/^    bool            free_buffer;$/;"	m	struct:sound_cfg	typeref:typename:bool	file:
getPixel	apa102LEDStrip.c	/^void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour/;"	f	typeref:typename:void
gpio	captouch.c	/^    uint8_t gpio;$/;"	m	struct:ad714x_chip	typeref:typename:uint8_t	file:
gpio_event_handler	captouch.c	/^static void gpio_event_handler(void* arg)$/;"	f	typeref:typename:void	file:
gpio_evt_queue	captouch.c	/^static QueueHandle_t gpio_evt_queue = NULL;$/;"	v	typeref:typename:QueueHandle_t	file:
gpio_isr_handler	captouch.c	/^static void IRAM_ATTR gpio_isr_handler(void* arg)$/;"	f	typeref:typename:void IRAM_ATTR	file:
i2c_master_init	espan.c	/^static esp_err_t i2c_master_init(void)$/;"	f	typeref:typename:esp_err_t	file:
initLEDs	apa102LEDStrip.c	/^void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, un/;"	f	typeref:typename:void
int_pol	captouch.c	/^    unsigned int int_pol:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
leds	espan.c	/^struct apa102LEDStrip leds;$/;"	v	typeref:struct:apa102LEDStrip
lp_conv_delay	captouch.c	/^    unsigned int lp_conv_delay:2;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:2	file:
maxSPIFrameInBytes	espan.c	/^#define maxSPIFrameInBytes /;"	d	file:
maxSPIFrequency	espan.c	/^#define maxSPIFrequency /;"	d	file:
maxValuePerColour	espan.c	/^#define maxValuePerColour /;"	d	file:
neg_afe_offset	captouch.c	/^    unsigned int neg_afe_offset:6;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:6	file:
neg_afe_offset_disable	captouch.c	/^    unsigned int neg_afe_offset_disable:1;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:1	file:
neg_afe_offset_swap	captouch.c	/^    unsigned int neg_afe_offset_swap:1;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:1	file:
neg_peak_detect	captouch.c	/^    unsigned int neg_peak_detect:3;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:3	file:
neg_threshold_sensitivity	captouch.c	/^    unsigned int neg_threshold_sensitivity:4;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:4	file:
paddle_leds	espan.c	/^static const uint8_t paddle_leds[][9] = {$/;"	v	typeref:typename:const uint8_t[][9]	file:
play_bootsound	audio.c	/^void play_bootsound() {$/;"	f	typeref:typename:void
play_pan	audio.c	/^void play_pan(int pan) {$/;"	f	typeref:typename:void
pos_afe_offset	captouch.c	/^    unsigned int pos_afe_offset:6;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:6	file:
pos_afe_offset_disable	captouch.c	/^    unsigned int pos_afe_offset_disable:1;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:1	file:
pos_afe_offset_swap	captouch.c	/^    unsigned int pos_afe_offset_swap:1;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:1	file:
pos_peak_detect	captouch.c	/^    unsigned int pos_peak_detect:3;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:3	file:
pos_threshold_sensitivity	captouch.c	/^    unsigned int pos_threshold_sensitivity:4;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:4	file:
position	audio.c	/^    size_t          position;$/;"	m	struct:sound_cfg	typeref:typename:size_t	file:
power_mode	captouch.c	/^    unsigned int power_mode:2;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:2	file:
pressed_bot	captouch.c	/^static uint16_t pressed_top, pressed_bot;$/;"	v	typeref:typename:uint16_t	file:
pressed_top	captouch.c	/^static uint16_t pressed_top, pressed_bot;$/;"	v	typeref:typename:uint16_t	file:
red	espan.c	/^uint8_t red[] = {32,0,0};$/;"	v	typeref:typename:uint8_t[]
renderLEDs	espan.c	/^void renderLEDs()$/;"	f	typeref:typename:void
ret	espan.c	/^esp_err_t ret;$/;"	v	typeref:typename:esp_err_t
se_connection_setup	captouch.c	/^    unsigned int se_connection_setup:2;$/;"	m	struct:ad7147_stage_config	typeref:typename:unsigned int:2	file:
sequence_stage_num	captouch.c	/^    unsigned int sequence_stage_num:4;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:4	file:
setPixel	apa102LEDStrip.c	/^void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour/;"	f	typeref:typename:void
setupSPI	espan.c	/^int setupSPI()$/;"	f	typeref:typename:int
size	audio.c	/^    size_t          size;$/;"	m	struct:sound_cfg	typeref:typename:size_t	file:
slot	audio.c	/^    size_t          slot;$/;"	m	struct:sound_cfg	typeref:typename:size_t	file:
sound_active	audio.c	/^static bool sound_active(void)$/;"	f	typeref:typename:bool	file:
sound_cfg	audio.c	/^typedef struct sound_cfg {$/;"	s	file:
sound_cfg_t	audio.c	/^} sound_cfg_t;$/;"	t	typeref:struct:sound_cfg	file:
sound_queue	audio.c	/^static QueueHandle_t sound_queue = NULL;$/;"	v	typeref:typename:QueueHandle_t	file:
spiTransObject	espan.c	/^spi_transaction_t spiTransObject;$/;"	v	typeref:typename:spi_transaction_t
spi_led	espan.c	/^spi_device_handle_t spi_led;$/;"	v	typeref:typename:spi_device_handle_t
stage0_cal_en	captouch.c	/^    unsigned int stage0_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage0_high_int_enable	captouch.c	/^    unsigned int stage0_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage10_cal_en	captouch.c	/^    unsigned int stage10_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage10_high_int_enable	captouch.c	/^    unsigned int stage10_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage11_cal_en	captouch.c	/^    unsigned int stage11_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage11_high_int_enable	captouch.c	/^    unsigned int stage11_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage1_cal_en	captouch.c	/^    unsigned int stage1_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage1_high_int_enable	captouch.c	/^    unsigned int stage1_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage2_cal_en	captouch.c	/^    unsigned int stage2_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage2_high_int_enable	captouch.c	/^    unsigned int stage2_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage3_cal_en	captouch.c	/^    unsigned int stage3_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage3_high_int_enable	captouch.c	/^    unsigned int stage3_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage4_cal_en	captouch.c	/^    unsigned int stage4_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage4_high_int_enable	captouch.c	/^    unsigned int stage4_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage5_cal_en	captouch.c	/^    unsigned int stage5_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage5_high_int_enable	captouch.c	/^    unsigned int stage5_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage6_cal_en	captouch.c	/^    unsigned int stage6_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage6_high_int_enable	captouch.c	/^    unsigned int stage6_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage7_cal_en	captouch.c	/^    unsigned int stage7_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage7_high_int_enable	captouch.c	/^    unsigned int stage7_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage8_cal_en	captouch.c	/^    unsigned int stage8_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage8_high_int_enable	captouch.c	/^    unsigned int stage8_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage9_cal_en	captouch.c	/^    unsigned int stage9_cal_en:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stage9_high_int_enable	captouch.c	/^    unsigned int stage9_high_int_enable:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
stages	captouch.c	/^    int stages;$/;"	m	struct:ad714x_chip	typeref:typename:int	file:
sw_reset	captouch.c	/^    unsigned int sw_reset:1;$/;"	m	struct:ad7147_device_config	typeref:typename:unsigned int:1	file:
top_map	espan.c	/^uint8_t top_map[] = {1, 1, 1, 0, 0, 4, 4, 4, 3, 3, 2, 2};$/;"	v	typeref:typename:uint8_t[]
totalPixels	espan.c	/^#define totalPixels /;"	d	file:
+6 −0
Original line number Diff line number Diff line
idf_component_register(
    SRCS
        badge23_hwconfig.c
    INCLUDE_DIRS
        include
)
+13 −0
Original line number Diff line number Diff line
#include "badge23_hwconfig.h"

#if defined(CONFIG_BADGE23_HW_GEN_P1)
const char *badge23_hw_name = "proto1";
#elif defined(CONFIG_BADGE23_HW_GEN_P3)
const char *badge23_hw_name = "proto3";
#elif defined(CONFIG_BADGE23_HW_GEN_P4)
const char *badge23_hw_name = "proto4";
#elif defined(CONFIG_BADGE23_HW_GEN_ADILESS)
const char *badge23_hw_name = "adiless";
#else
#error "Badge23 Hardware Generation must be set!"
#endif
+6 −0
Original line number Diff line number Diff line
#pragma once

#include "sdkconfig.h"

// internal name of the badge hardware version (proto1, proto3, etc).
const char *badge23_hw_name;
+4 −0
Original line number Diff line number Diff line
idf_component_register(SRCS "led_strip_rmt_ws2812.c"
                    INCLUDE_DIRS "include"
                    PRIV_REQUIRES "driver"
                    )
+16 −0
Original line number Diff line number Diff line
# LED Strip Component

This directory contains an implementation for addressable LEDs using the RMT peripheral.

It's compatible with:

* [WS2812](http://www.world-semi.com/Certifications/WS2812B.html)
* SK68XX

This component is used as part of the following ESP-IDF examples:
- [Blink Example](../../get-started/blink).
- [LED Strip Example](../../peripherals/rmt/led_strip).

To learn more about how to use this component, please check API Documentation from header file [led_strip.h](./include/led_strip.h).

Please note that this component is not considered to be a part of ESP-IDF stable API. It may change and it may be removed in the future releases.
+7 −0
Original line number Diff line number Diff line
version: "1.1.0-alpha"
description: C driver, based on RMT peripheral, for WS2812 and SK6812 smart RGB diodes

dependencies:
  # Required IDF version
  idf:
    version: ">=4.0"
+147 −0
Original line number Diff line number Diff line
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include "esp_err.h"

/**
* @brief LED Strip Type
*
*/
typedef struct led_strip_s led_strip_t;

/**
* @brief LED Strip Device Type
*
*/
typedef void *led_strip_dev_t;

/**
* @brief Declare of LED Strip Type
*
*/
struct led_strip_s {
    /**
    * @brief Set RGB for a specific pixel
    *
    * @param strip: LED strip
    * @param index: index of pixel to set
    * @param red: red part of color
    * @param green: green part of color
    * @param blue: blue part of color
    *
    * @return
    *      - ESP_OK: Set RGB for a specific pixel successfully
    *      - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
    *      - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
    */
    esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);

    /**
    * @brief Refresh memory colors to LEDs
    *
    * @param strip: LED strip
    * @param timeout_ms: timeout value for refreshing task
    *
    * @return
    *      - ESP_OK: Refresh successfully
    *      - ESP_ERR_TIMEOUT: Refresh failed because of timeout
    *      - ESP_FAIL: Refresh failed because some other error occurred
    *
    * @note:
    *      After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
    */
    esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);

    /**
    * @brief Clear LED strip (turn off all LEDs)
    *
    * @param strip: LED strip
    * @param timeout_ms: timeout value for clearing task
    *
    * @return
    *      - ESP_OK: Clear LEDs successfully
    *      - ESP_ERR_TIMEOUT: Clear LEDs failed because of timeout
    *      - ESP_FAIL: Clear LEDs failed because some other error occurred
    */
    esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms);

    /**
    * @brief Free LED strip resources
    *
    * @param strip: LED strip
    *
    * @return
    *      - ESP_OK: Free resources successfully
    *      - ESP_FAIL: Free resources failed because error occurred
    */
    esp_err_t (*del)(led_strip_t *strip);
};

/**
* @brief LED Strip Configuration Type
*
*/
typedef struct {
    uint32_t max_leds;   /*!< Maximum LEDs in a single strip */
    led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */
} led_strip_config_t;

/**
 * @brief Default configuration for LED strip
 *
 */
#define LED_STRIP_DEFAULT_CONFIG(number, dev_hdl) \
    {                                             \
        .max_leds = number,                       \
        .dev = dev_hdl,                           \
    }

/**
* @brief Install a new ws2812 driver (based on RMT peripheral)
*
* @param config: LED strip configuration
* @return
*      LED strip instance or NULL
*/
led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config);

/**
 * @brief Init the RMT peripheral and LED strip configuration.
 *
 * @param[in] channel: RMT peripheral channel number.
 * @param[in] gpio: GPIO number for the RMT data output.
 * @param[in] led_num: number of addressable LEDs.
 * @return
 *      LED strip instance or NULL
 */
led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num);

/**
 * @brief Denit the RMT peripheral.
 *
 * @param[in] strip: LED strip
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t led_strip_denit(led_strip_t *strip);

#ifdef __cplusplus
}
#endif
+208 −0
Original line number Diff line number Diff line
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_attr.h"
#include "led_strip.h"
#include "driver/rmt.h"

#define RMT_TX_CHANNEL RMT_CHANNEL_0

static const char *TAG = "ws2812";
#define STRIP_CHECK(a, str, goto_tag, ret_value, ...)                             \
    do                                                                            \
    {                                                                             \
        if (!(a))                                                                 \
        {                                                                         \
            ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
            ret = ret_value;                                                      \
            goto goto_tag;                                                        \
        }                                                                         \
    } while (0)

#define WS2812_T0H_NS (350)
#define WS2812_T0L_NS (1000)
#define WS2812_T1H_NS (1000)
#define WS2812_T1L_NS (350)
#define WS2812_RESET_US (280)

static uint32_t ws2812_t0h_ticks = 0;
static uint32_t ws2812_t1h_ticks = 0;
static uint32_t ws2812_t0l_ticks = 0;
static uint32_t ws2812_t1l_ticks = 0;

typedef struct {
    led_strip_t parent;
    rmt_channel_t rmt_channel;
    uint32_t strip_len;
    uint8_t buffer[0];
} ws2812_t;

/**
 * @brief Conver RGB data to RMT format.
 *
 * @note For WS2812, R,G,B each contains 256 different choices (i.e. uint8_t)
 *
 * @param[in] src: source data, to converted to RMT format
 * @param[in] dest: place where to store the convert result
 * @param[in] src_size: size of source data
 * @param[in] wanted_num: number of RMT items that want to get
 * @param[out] translated_size: number of source data that got converted
 * @param[out] item_num: number of RMT items which are converted from source data
 */
static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
        size_t wanted_num, size_t *translated_size, size_t *item_num)
{
    if (src == NULL || dest == NULL) {
        *translated_size = 0;
        *item_num = 0;
        return;
    }
    const rmt_item32_t bit0 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0
    const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_t1l_ticks, 0 }}}; //Logical 1
    size_t size = 0;
    size_t num = 0;
    uint8_t *psrc = (uint8_t *)src;
    rmt_item32_t *pdest = dest;
    while (size < src_size && num < wanted_num) {
        for (int i = 0; i < 8; i++) {
            // MSB first
            if (*psrc & (1 << (7 - i))) {
                pdest->val =  bit1.val;
            } else {
                pdest->val =  bit0.val;
            }
            num++;
            pdest++;
        }
        size++;
        psrc++;
    }
    *translated_size = size;
    *item_num = num;
}

static esp_err_t ws2812_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
{
    esp_err_t ret = ESP_OK;
    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
    STRIP_CHECK(index < ws2812->strip_len, "index out of the maximum number of leds", err, ESP_ERR_INVALID_ARG);
    uint32_t start = index * 3;
    // In thr order of GRB
    ws2812->buffer[start + 0] = green & 0xFF;
    ws2812->buffer[start + 1] = red & 0xFF;
    ws2812->buffer[start + 2] = blue & 0xFF;
    return ESP_OK;
err:
    return ret;
}

static esp_err_t ws2812_refresh(led_strip_t *strip, uint32_t timeout_ms)
{
    esp_err_t ret = ESP_OK;
    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
    STRIP_CHECK(rmt_write_sample(ws2812->rmt_channel, ws2812->buffer, ws2812->strip_len * 3, true) == ESP_OK,
                "transmit RMT samples failed", err, ESP_FAIL);
    return rmt_wait_tx_done(ws2812->rmt_channel, pdMS_TO_TICKS(timeout_ms));
err:
    return ret;
}

static esp_err_t ws2812_clear(led_strip_t *strip, uint32_t timeout_ms)
{
    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
    // Write zero to turn off all leds
    memset(ws2812->buffer, 0, ws2812->strip_len * 3);
    return ws2812_refresh(strip, timeout_ms);
}

static esp_err_t ws2812_del(led_strip_t *strip)
{
    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
    free(ws2812);
    return ESP_OK;
}

led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config)
{
    led_strip_t *ret = NULL;
    STRIP_CHECK(config, "configuration can't be null", err, NULL);

    // 24 bits per led
    uint32_t ws2812_size = sizeof(ws2812_t) + config->max_leds * 3;
    ws2812_t *ws2812 = calloc(1, ws2812_size);
    STRIP_CHECK(ws2812, "request memory for ws2812 failed", err, NULL);

    uint32_t counter_clk_hz = 0;
    STRIP_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev, &counter_clk_hz) == ESP_OK,
                "get rmt counter clock failed", err, NULL);
    // ns -> ticks
    float ratio = (float)counter_clk_hz / 1e9;
    ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
    ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
    ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
    ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);

    // set ws2812 to rmt adapter
    rmt_translator_init((rmt_channel_t)config->dev, ws2812_rmt_adapter);

    ws2812->rmt_channel = (rmt_channel_t)config->dev;
    ws2812->strip_len = config->max_leds;

    ws2812->parent.set_pixel = ws2812_set_pixel;
    ws2812->parent.refresh = ws2812_refresh;
    ws2812->parent.clear = ws2812_clear;
    ws2812->parent.del = ws2812_del;

    return &ws2812->parent;
err:
    return ret;
}

led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num)
{
    static led_strip_t *pStrip;

    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, channel);
    // set counter clock to 40MHz
    config.clk_div = 2;

    ESP_ERROR_CHECK(rmt_config(&config));
    ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

    // install ws2812 driver
    led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_num, (led_strip_dev_t)config.channel);

    pStrip = led_strip_new_rmt_ws2812(&strip_config);

    if ( !pStrip ) {
        ESP_LOGE(TAG, "install WS2812 driver failed");
        return NULL;
    }

    // Clear LED strip (turn off all LEDs)
    // This will fail for inverted output
    //ESP_ERROR_CHECK(pStrip->clear(pStrip, 100));

    return pStrip;
}

esp_err_t led_strip_denit(led_strip_t *strip)
{
    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
    ESP_ERROR_CHECK(rmt_driver_uninstall(ws2812->rmt_channel));
    return strip->del(strip);
}
+202 −0
Original line number Diff line number Diff line

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.