From f43b411ec5f0301cee2bfe0127533ce4ad7129b2 Mon Sep 17 00:00:00 2001 From: AshrafIbrahim03 Date: Thu, 24 Aug 2023 15:12:27 -0400 Subject: [PATCH 1/2] Merge branch 'master' of github.com:lancaster-university/microbit-v2-samples into merger --- .github/workflows/build.yml | 62 ++ .github/workflows/cppcheck.yml | 40 ++ .github/workflows/docker-image.yml | 25 + .github/workflows/onRelease.yml | 36 ++ .vscode/extensions.json | 5 + .vscode/launch.json | 40 ++ .vscode/tasks.json | 33 ++ CMakeLists.txt | 20 +- Dockerfile | 13 +- README.md | 50 +- build.py | 15 +- codal.ble.json | 18 + codal.dev.json | 17 + codal.json | 6 +- source/samples/AccelerometerTest.cpp | 8 +- source/samples/AudioTest.cpp | 4 +- source/samples/BLETest.cpp | 120 ++++ source/samples/BlinkyTest.cpp | 4 +- source/samples/ButtonTest.cpp | 8 +- source/samples/CapTouchTest.cpp | 12 +- source/samples/DeepSleepTest.cpp | 302 ++++++++++ source/samples/DisplayTest.cpp | 17 +- source/samples/MicrophoneTest.cpp | 25 +- source/samples/NeopixelsTest.cpp | 66 +++ source/samples/OOB.cpp | 529 ++++++++++++++---- source/samples/OOB_v3.cpp | 321 +++++++++++ source/samples/PowerManagementTest.cpp | 26 +- source/samples/RadioTestRx.cpp | 4 +- source/samples/SerialStreamer.cpp | 22 +- source/samples/SerialStreamer.h | 2 +- source/samples/StreamAPITest.cpp | 50 ++ source/samples/Tests.h | 18 +- .../cmake/toolchains/ARM_GCC/toolchain.cmake | 3 + utils/python/codal_utils.py | 68 ++- 34 files changed, 1756 insertions(+), 233 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/cppcheck.yml create mode 100644 .github/workflows/docker-image.yml create mode 100644 .github/workflows/onRelease.yml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 codal.ble.json create mode 100644 codal.dev.json create mode 100644 source/samples/BLETest.cpp create mode 100644 source/samples/DeepSleepTest.cpp create mode 100644 source/samples/NeopixelsTest.cpp create mode 100644 source/samples/OOB_v3.cpp create mode 100644 source/samples/StreamAPITest.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..53b94f1e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,62 @@ +name: Build Natively + +on: + push: + branches: '*' + pull_request: + branches: '*' + +jobs: + build-py-script: + strategy: + matrix: + os: [ubuntu-20.04, macos-11, windows-2019] + gcc: ['7-2017-q4', 'latest'] + cmake: ['3.6.0', ''] # Empty string installs the latest CMake release + fail-fast: false + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }}, gcc ${{ matrix.gcc }}, cmake ${{ matrix.cmake || 'latest'}} + steps: + - uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.8' + - name: Setup arm-none-eabi-gcc ${{ matrix.gcc }} + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: ${{ matrix.gcc }} + - name: Setup CMake ${{ matrix.cmake }} + uses: jwlawson/actions-setup-cmake@v1 + with: + cmake-version: ${{ matrix.cmake }} + - name: Install Ninja via PyPI + run: python -m pip install ninja + - name: Check Versions + run: | + arm-none-eabi-gcc --version + cmake --version + ninja --version + python --version + - name: Build default project using build.py + run: python build.py + - name: Upload hex file + uses: actions/upload-artifact@v1 + with: + name: build-py-${{ matrix.os }} + path: MICROBIT.hex + - name: Prepare BLE example + run: | + rm codal.json + mv codal.ble.json codal.json + python -c "import pathlib; \ + f=pathlib.Path('source/main.cpp'); \ + f.write_text(f.read_text().replace('out_of_box_experience()', 'ble_test()'))" + cat codal.json + - name: Build BLE project using build.py + run: python build.py --clean + - name: Upload BLE hex file + uses: actions/upload-artifact@v1 + with: + name: build-py-BLE-${{ matrix.os }} + path: MICROBIT.hex diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml new file mode 100644 index 00000000..07085f98 --- /dev/null +++ b/.github/workflows/cppcheck.yml @@ -0,0 +1,40 @@ +name: Static Analysis Report + +on: + workflow_dispatch: + push: + branches: '*' + pull_request: + branches: '*' + +jobs: + cppcheck: + runs-on: ubuntu-20.04 + name: Run CppCheck against the codebase + libraries + steps: + - uses: actions/checkout@v3 + - name: Install CppCheck + run: | + sudo apt-get update + sudo apt-get install -y cppcheck + - name: Setup arm-none-eabi-gcc + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: latest + - name: Setup CMake + uses: jwlawson/actions-setup-cmake@v1 + - name: Build default project using build.py + run: python build.py + - name: Run CppCheck + run: | + cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON . + cppcheck --project=compile_commands.json --std=c++11 --template='### {id} - {file}:{line}\n**{severity}:** {message}\n```\n{code}\n```\n' 2> cppcheck.md + - name: Add CppCheck result to job summary + run: | + echo "## Cppcheck output" >> $GITHUB_STEP_SUMMARY + echo "$(cat cppcheck.md)" >> $GITHUB_STEP_SUMMARY + - name: Upload log file + uses: actions/upload-artifact@v1 + with: + name: cppcheck.md + path: cppcheck.md diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 00000000..95bf3d4f --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,25 @@ +name: Build via Docker + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Build using the Docker image + env: + DOCKER_BUILDKIT: 1 + run: docker build -t microbit-tools --output type=local,dest=out . + - name: Directory Listing + run: ls -al + - name: Upload hex file + uses: actions/upload-artifact@v1 + with: + name: Export from Docker + path: out/MICROBIT.hex diff --git a/.github/workflows/onRelease.yml b/.github/workflows/onRelease.yml new file mode 100644 index 00000000..3d7e249c --- /dev/null +++ b/.github/workflows/onRelease.yml @@ -0,0 +1,36 @@ +name: Release Library Builds + +on: + workflow_dispatch: + release: + types: [created] + +jobs: + cppcheck: + runs-on: ubuntu-20.04 + name: Build against Ubuntu-20.04 for release assets + steps: + - uses: actions/checkout@v3 + - name: Install CppCheck + run: | + sudo apt-get update + sudo apt-get install -y cppcheck + + - name: Setup arm-none-eabi-gcc + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: latest + + - name: Setup CMake + uses: jwlawson/actions-setup-cmake@v1 + + - name: Build default project using build.py + run: python build.py + + - uses: xresloader/upload-to-github-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + file: "build/*.a" + update_latest_release: true + \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..41b822fc --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "marus25.cortex-debug" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..c62a7ed6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,40 @@ +{ + "configurations": [ + { + "name": "micro:bit PyOCD Cortex Debug", + "cwd": "${workspaceFolder}", + "executable": "build/MICROBIT", + "request": "launch", + "type": "cortex-debug", + "servertype": "pyocd", + "interface": "swd", + "device": "nrf52", + "targetId": "nrf52", + "svdFile": "libraries/codal-nrf52/nrfx/mdk/nrf52833.svd", + "preLaunchCommands": [ + "load build/MICROBIT", + "enable breakpoint", + "monitor reset" + ] + }, + + { + "name": "micro:bit OpenOCD Cortex Debug", + "cwd": "${workspaceFolder}", + "executable": "build/MICROBIT", + "request": "launch", + "type": "cortex-debug", + "servertype": "openocd", + "configFiles": [ + "interface/cmsis-dap.cfg", + "target/nrf52.cfg" + ], + "interface": "swd", + "preLaunchCommands": [ + "load build/MICROBIT", + "enable breakpoint", + "monitor reset" + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..ffbac11e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + "version": "2.0.0", + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "tasks": [ + { + "type": "shell", + "label": "CODAL build", + "command": "python build.py", + "windows": { + "command": "py build.py" + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "CODAL clean build", + "command": "python build.py --clean", + "windows": { + "command": "py build.py --clean" + }, + "group": { + "kind": "build", + "isDefault": false + } + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index ee85ffd4..1532c352 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.6) # include additional cmake include(utils/cmake/JSONParser.cmake) @@ -132,7 +132,7 @@ foreach(var ${device}) string(REGEX MATCH "[^device\.cmake_definitions\.]([A-Z,a-z,0-9,_,]+)" CODAL_CMAKE_DEFINITION "${var}") set(${CODAL_CMAKE_DEFINITION} ${${var}}) - endforeach() +endforeach() #define any additional symbols specified by the target. if("${device.definitions}" STRGREATER "") @@ -182,12 +182,12 @@ if("${CODAL_DEFINITIONS}" STRGREATER "") file(WRITE "${EXTRA_INCLUDES_NEW_PATH}" ${CODAL_DEFINITIONS}) configure_file(${EXTRA_INCLUDES_NEW_PATH} ${EXTRA_INCLUDES_PATH} COPYONLY) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -include ${EXTRA_INCLUDES_PATH}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include ${EXTRA_INCLUDES_PATH}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -include \"${EXTRA_INCLUDES_PATH}\"") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include \"${EXTRA_INCLUDES_PATH}\"") endif() -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${PLATFORM_INCLUDES_PATH}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${PLATFORM_INCLUDES_PATH}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I\"${PLATFORM_INCLUDES_PATH}\"") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I\"${PLATFORM_INCLUDES_PATH}\"") # a define for cmake if statements to detect if within the CODAL build environment set(CODAL_BUILD_SYSTEM TRUE) @@ -232,13 +232,17 @@ endif() #finally, find sources and includes of the application, and create a target. RECURSIVE_FIND_DIR(INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.h") +RECURSIVE_FIND_DIR(HPP_DIRS "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.hpp") +list(APPEND INCLUDE_DIRS ${HPP_DIRS}) + # *.c?? only catches .cpp, not .c, so let's be precise RECURSIVE_FIND_FILE(SOURCE_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.cpp") - RECURSIVE_FIND_FILE(S_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.s") RECURSIVE_FIND_FILE(C_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.c") +RECURSIVE_FIND_FILE(CC_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.cc") list(APPEND SOURCE_FILES ${S_FILES}) list(APPEND SOURCE_FILES ${C_FILES}) +list(APPEND SOURCE_FILES ${CC_FILES}) if("${SOURCE_FILES}" STREQUAL "") message(FATAL_ERROR "${BoldRed}No user application to build, please add a main.cpp at: ${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}${ColourReset}") @@ -262,4 +266,4 @@ endif() set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set(CMAKE_EXE_EXPORTS_C_FLAG "") -set(CMAKE_EXE_EXPORTS_CXX_FLAG "") \ No newline at end of file +set(CMAKE_EXE_EXPORTS_CXX_FLAG "") diff --git a/Dockerfile b/Dockerfile index 7af0490b..46377eb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:18.04 as builder RUN apt-get update -qq && \ apt-get install -y --no-install-recommends \ @@ -13,6 +13,13 @@ RUN apt-get update -qq && \ rm -rf /var/lib/apt/lists/* # Project sources volume should be mounted at /app -WORKDIR /app +COPY . /opt/microbit-samples +WORKDIR /opt/microbit-samples -ENTRYPOINT ["python3", "build.py"] +RUN python3 build.py + +FROM scratch AS export-stage +COPY --from=builder /opt/microbit-samples/MICROBIT.bin . +COPY --from=builder /opt/microbit-samples/MICROBIT.hex . + +ENTRYPOINT ["/bin/bash"] diff --git a/README.md b/README.md index 9c616a25..43a77a4f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,19 @@ # microbit-v2-BirdBrain-BLE +[![Native Build Status](https://github.com/lancaster-university/microbit-v2-samples/actions/workflows/build.yml/badge.svg)](https://github.com/lancaster-university/microbit-v2-samples/actions/workflows/build.yml) [![Docker Build Status](https://github.com/lancaster-university/microbit-v2-samples/actions/workflows/docker-image.yml/badge.svg)](https://github.com/lancaster-university/microbit-v2-samples/actions/workflows/docker-image.yml) + This repository contains the code to generate the BirdBrain BLE firmware for micro:bit V2. It is based on the micro:bit-v2-samples firmware created at lancaster-university. +This repository provides the necessary tooling to compile a C/C++ CODAL program for the micro:bit V2 and generate a HEX file that can be downloaded to the device. + +## Raising Issues +Any issues regarding the micro:bit are gathered on the [lancaster-university/codal-microbit-v2](https://github.com/lancaster-university/codal-microbit-v2) repository. Please raise yours there too. + # Installation You need some open source pre-requisites to build this repo. You can either install these tools yourself, or use the docker image provided below. - [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) -- [Github desktop](https://desktop.github.com/) +- [Git](https://git-scm.com) - [CMake](https://cmake.org/download/) - [Python 3](https://www.python.org/downloads/) @@ -25,7 +32,13 @@ For backwards compatibility with [microbit-samples](https://github.com/lancaster ## Docker You can use the [Dockerfile](https://github.com/lancaster-university/microbit-v2-samples/blob/master/Dockerfile) provided to build the samples, or your own project sources, without installing additional dependencies. -Run the following command to build the image locally: +Run the following command to build the image locally; the .bin and .hex files from a successful compile will be placed in a new `out/` directory: + +``` + docker build -t microbit-tools --output out . +``` + +To omit the final output stage (for CI, for example) run without the `--output` arguments: ``` docker build -t microbit-tools . @@ -34,28 +47,31 @@ Run the following command to build the image locally: # Building - Clone this repository - In the root of this repository type `python build.py` -- The hex file will be built `MICROBIT.HEX` and placed in the root folder. +- The hex file will be built `MICROBIT.hex` and placed in the root folder. -## Docker -You can use the image you built previously to build the project sources in the current working directory (equivalent to executing `build.py`). +# Developing +You will find a simple main.cpp in the `source` folder which you can edit. CODAL will also compile any other C/C++ header files our source files with the extension `.h .c .cpp` it finds in the source folder. -``` - docker run -v $(pwd):/app --rm microbit-tools -``` +The `samples` folder contains a number of simple sample programs that utilise you may find useful. -You can also provide additional arguments like `--clean`. +## Developer codal.json -``` - docker run -v $(pwd):/app --rm microbit-tools --clean -``` +There is an example `coda.dev.json` file which enables "developer builds" (clones dependencies from the latest commits, instead of the commits locked in the `codal-microbit-v2` tag), and adds extra CODAL flags that enable debug data to be printed to serial. +To use it, simply copy the additional json entries into your `codal.json` file, or you can replace the file completely (`mv coda.dev.json codal.json`). -# Developing -You will find a simple main.cpp in the `source` folder which you can edit. CODAL will also compile any other C/C++ header files our source files with the extension `.h .c .cpp` it finds in the source folder. +# Debugging +If you are using Visual Studio Code, there is a working debugging environment already set up for you, allowing you to set breakpoints and observe the micro:bit's memory. To get it working, follow these steps: -The `samples` folder contains a number of simple sample programs that utilise you may find useful. +1. Install either [OpenOCD](http://openocd.org) or [PyOCD](https://github.com/pyocd/pyOCD). +2. Install the [`marus25.cortex-debug` VS Code extension](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug). +3. Build your program. +4. Click the Run and Debug option in the toolbar. +5. Two debugging options are provided: one for OpenOCD, and one for PyOCD. Select the correct one depending on the debugger you installed. + +This should launch the debugging environment for you. To set breakpoints, you can click to the left of the line number of where you want to stop. # Compatibility -This repository is designed to follow the principles and APIs developed for the first version of the micro:bit. We have also included a compatilibty layer so that the vast majority of C/C++ programs built using [microbit-dal](https://www.github.com/lancaster-university/microbit-dal) will operate with few changes. +This repository is designed to follow the principles and APIs developed for the first version of the micro:bit. We have also included a compatibility layer so that the vast majority of C/C++ programs built using [microbit-dal](https://www.github.com/lancaster-university/microbit-dal) will operate with few changes. # Documentation -API documentation is embedded in the code using doxygen. We will produce integrated web-based documetation soon. +API documentation is embedded in the code using doxygen. We will produce integrated web-based documentation soon. diff --git a/build.py b/build.py index 594c5d75..9b1019d5 100755 --- a/build.py +++ b/build.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # The MIT License (MIT) @@ -39,11 +39,14 @@ parser.add_option('-m', '--minor', dest='update_minor', action="store_true", help='With -l, update minor version', default=False) parser.add_option('-M', '--major', dest='update_major', action="store_true", help='With -l, update major version', default=False) parser.add_option('-V', '--version', dest='version', metavar="VERSION", help='With -l, set the version; use "-V v0.0.1" to bootstrap', default=False) -parser.add_option('-u', '--update', dest='update', action="store_true", help='git pull target and libraries', default=False) +parser.add_option('-v', '--verbose', dest='verbose', action="store_true", help='Increases verbosity)', default=False) +parser.add_option('-u', '--update', dest='update', action="store_true", help='git pull target and libraries, use with "-d/--dev" to update all libraries to their latest master' , default=False) parser.add_option('-s', '--status', dest='status', action="store_true", help='git status target and libraries', default=False) parser.add_option('-r', '--revision', dest='revision', action="store", help='Checkout a specific revision of the target', default=False) parser.add_option('-d', '--dev', dest='dev', action="store_true", help='enable developer mode (does not use target-locked.json)', default=False) parser.add_option('-g', '--generate-docs', dest='generate_docs', action="store_true", help='generate documentation for the current target', default=False) +parser.add_option('-j', '--parallelism', dest='parallelism', action="store", help='Set the number of parallel threads to build with, if supported', default=10) +parser.add_option('-n', '--lines', dest='detail_lines', action="store", help="Sets the number of detail lines to output (only relevant to --status)", default=3 ) (options, args) = parser.parse_args() @@ -55,11 +58,11 @@ exit(0) if options.update: - update() + update(sync_dev = options.dev) exit(0) if options.status: - status() + status(logLines=options.detail_lines, detail=options.verbose, libs=args) exit(0) if options.revision: @@ -138,7 +141,7 @@ generate_docs() exit(0) - build(options.clean) + build(options.clean, verbose=options.verbose, parallelism=options.parallelism) exit(0) for json_obj in test_json: @@ -165,4 +168,4 @@ with open("../codal.json", 'w') as codal_json: json.dump(config, codal_json, indent=4) - build(True, True) + build(True, True, options.parallelism) diff --git a/codal.ble.json b/codal.ble.json new file mode 100644 index 00000000..c8e5da61 --- /dev/null +++ b/codal.ble.json @@ -0,0 +1,18 @@ +{ + "target": { + "name": "codal-microbit-v2", + "url": "https://github.com/lancaster-university/codal-microbit-v2", + "branch": "master", + "type": "git" + } , + "config":{ + "DEVICE_BLE": 1, + "MICROBIT_BLE_ENABLED" : 1, + "MICROBIT_BLE_PAIRING_MODE": 1, + "MICROBIT_BLE_DFU_SERVICE": 1, + "MICROBIT_BLE_DEVICE_INFORMATION_SERVICE": 1, + "MICROBIT_BLE_EVENT_SERVICE" : 1, + "MICROBIT_BLE_PARTIAL_FLASHING" : 1, + "MICROBIT_BLE_SECURITY_LEVEL": "SECURITY_MODE_ENCRYPTION_NO_MITM" + } +} diff --git a/codal.dev.json b/codal.dev.json new file mode 100644 index 00000000..0c8c6789 --- /dev/null +++ b/codal.dev.json @@ -0,0 +1,17 @@ +{ + "target": { + "name": "codal-microbit-v2", + "url": "https://github.com/lancaster-university/codal-microbit-v2", + "branch": "master", + "type": "git", + "dev": true + }, + "config":{ + "DMESG_ENABLE": 1, + "DEVICE_DMESG_BUFFER_SIZE": 1024, + "DMESG_SERIAL_DEBUG": 1, + "CODAL_DEBUG": 1, + "MICROBIT_BLE_ENABLED" : 0, + "MICROBIT_BLE_PAIRING_MODE": 0 + } +} diff --git a/codal.json b/codal.json index dec1a7ad..5302b588 100644 --- a/codal.json +++ b/codal.json @@ -3,10 +3,8 @@ "name": "codal-microbit-v2", "url": "https://github.com/lancaster-university/codal-microbit-v2", "branch": "master", - "type": "git", - "test_ignore": true, - "dev": true - } , + "type": "git" + }, "config":{ "NO_BLE": 0, "MICROBIT_BLE_ENABLED" : 1, diff --git a/source/samples/AccelerometerTest.cpp b/source/samples/AccelerometerTest.cpp index f2420940..43af3733 100644 --- a/source/samples/AccelerometerTest.cpp +++ b/source/samples/AccelerometerTest.cpp @@ -1,19 +1,19 @@ #include "MicroBit.h" #include "Tests.h" -void +static void onCompassData(MicroBitEvent) { DMESGN("C"); } -void +static void onAccelerometerData(MicroBitEvent) { DMESGN("A"); } -void +static void onShake(MicroBitEvent) { DMESG(" *** SHAKE ***"); @@ -34,7 +34,7 @@ accelerometer_test1() } } -int g_to_pix(int g) +static int g_to_pix(int g) { int v = 2; if ( g < -200) v--; diff --git a/source/samples/AudioTest.cpp b/source/samples/AudioTest.cpp index d0cde884..36f54208 100644 --- a/source/samples/AudioTest.cpp +++ b/source/samples/AudioTest.cpp @@ -56,7 +56,7 @@ static Pin *pin = NULL; static uint8_t pitchVolume = 0xff; // Pin control as per MakeCode. -void analogPitch(int frequency, int ms) { +static void analogPitch(int frequency, int ms) { if (frequency <= 0 || pitchVolume == 0) { pin->setAnalogValue(0); } else { @@ -74,7 +74,7 @@ void analogPitch(int frequency, int ms) { } } -void playScale() { +static void playScale() { const int beat = 500; analogPitch(Note::C5, beat); analogPitch(Note::B, beat); diff --git a/source/samples/BLETest.cpp b/source/samples/BLETest.cpp new file mode 100644 index 00000000..9fb22a1d --- /dev/null +++ b/source/samples/BLETest.cpp @@ -0,0 +1,120 @@ +/* +The MIT License (MIT) + +Copyright (c) 2021 Lancaster University. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include "MicroBit.h" +#include "Tests.h" + +#if CONFIG_ENABLED(DEVICE_BLE) + +extern MicroBit uBit; +MicroBitUARTService *uart; + +// we use events abd the 'connected' variable to keep track of the status of the Bluetooth connection +static void onConnected(MicroBitEvent) +{ + uBit.display.print("C"); +} + +static void onDisconnected(MicroBitEvent) +{ + uBit.display.print("D"); +} + +static void onDelim(MicroBitEvent) +{ + ManagedString r = uart->readUntil("\r\n"); + uart->send(r); +} + +void ble_test() +{ + // Configuration Tips + // + // An example codal.json is provided in the root directory: codal.ble.json + // Rename codal.ble.json to codal.json to use this BLE sample + // + // codal.json contains various Bluetooth related properties some of which are explained here: + // + // "DEVICE_BLE": 1 Determines whether BLE is enabled + // "MICROBIT_BLE_ENABLED" : 1 Determines whether BLE is enabled + // "MICROBIT_BLE_PAIRING_MODE": 1 Determines whether Pairing Mode is enabled + // "MICROBIT_BLE_DFU_SERVICE": 1 Determines whether the Nordic DFU Service is enabled + // "MICROBIT_BLE_DEVICE_INFORMATION_SERVICE": 1 Determines whether the DIS is enabled + // "MICROBIT_BLE_EVENT_SERVICE" : 1, Determines whether the Event Service is enabled + // "MICROBIT_BLE_PARTIAL_FLASHING" : 0 Determines whether Partial Flashing is enabled (Needs MakeCode/Python) + // "MICROBIT_BLE_SECURITY_LEVEL": "SECURITY_MODE_ENCRYPTION_WITH_MITM" Determines security mode + // + // Options for MICROBIT_BLE_SECURITY_LEVEL are: + // SECURITY_MODE_ENCRYPTION_WITH_MITM, enables pairing with a passcode + // SECURITY_MODE_ENCRYPTION_NO_MITM, enables pairing without a passcode + // SECURITY_MODE_ENCRYPTION_OPEN_LINK, pairing is no required + // + + uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED, onConnected); + uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, onDisconnected); + + uBit.messageBus.listen(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH, onDelim); + + new MicroBitAccelerometerService(*uBit.ble, uBit.accelerometer); + new MicroBitButtonService(*uBit.ble); + new MicroBitIOPinService(*uBit.ble, uBit.io); + new MicroBitLEDService(*uBit.ble, uBit.display); + new MicroBitMagnetometerService(*uBit.ble, uBit.compass); + new MicroBitTemperatureService(*uBit.ble, uBit.thermometer); + + uart = new MicroBitUARTService(*uBit.ble, 32, 32); + uart->eventOn("\r\n"); + + // A cunning code to indicate during start-up the particular Bluetooth configuration in the build + // + // SERVICE CODES + // A: Accelerometer Service + // B: Button Service + // D: Device Information Service + // E: Event Service + // F: DFU Service + // I: IO Pin Service + // L: LED Service + // M: Magnetometer Service + // T: Temperature Service + // U: UART Service + // + + // P: PASSKEY + // J: Just Works + // N: No Pairing Required + + // Services/Pairing Config/Power Level + uBit.display.scroll("BLE ABDILMTU/P"); + + if ( !uBit.compass.isCalibrated()) + uBit.compass.calibrate(); + + // If main exits, there may still be other fibers running or registered event handlers etc. + // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then + // sit in the idle task forever, in a power efficient sleep. + release_fiber(); +} + +#endif \ No newline at end of file diff --git a/source/samples/BlinkyTest.cpp b/source/samples/BlinkyTest.cpp index 05e9b94d..eb287fde 100644 --- a/source/samples/BlinkyTest.cpp +++ b/source/samples/BlinkyTest.cpp @@ -53,7 +53,7 @@ void off_power_test() } -void setDisplay(int mode) +static void setDisplay(int mode) { DMESG(mode ? "RED\n" : "GREEN\n"); @@ -70,7 +70,7 @@ void setDisplay(int mode) uBit.io.col5.setDigitalValue(!mode); } -void setCol(int col, int mode) +static void setCol(int col, int mode) { int c = 0; diff --git a/source/samples/ButtonTest.cpp b/source/samples/ButtonTest.cpp index 5b9f21b5..f3486e24 100644 --- a/source/samples/ButtonTest.cpp +++ b/source/samples/ButtonTest.cpp @@ -39,25 +39,25 @@ button_test2() } } -void +static void onButtonA(MicroBitEvent) { uBit.display.print("Aa"); } -void +static void onButtonB(MicroBitEvent) { uBit.display.print("Bb"); } -void +static void onButtonAB(MicroBitEvent) { uBit.display.print("Cc"); } -void listenerRemoved(MicroBitListener *) +static void listenerRemoved(MicroBitListener *) { DMESG("Listener deleted"); } diff --git a/source/samples/CapTouchTest.cpp b/source/samples/CapTouchTest.cpp index e27c3244..a4c1228e 100644 --- a/source/samples/CapTouchTest.cpp +++ b/source/samples/CapTouchTest.cpp @@ -99,7 +99,7 @@ calibrateTest(float sample) //DMESG("[SAMPLE: %d]", (int)sample); } -void +static void onCalibrate(MicroBitEvent) { @@ -109,26 +109,26 @@ onCalibrate(MicroBitEvent) c2 = last_t2; } -void +static void onPrint(MicroBitEvent) { while(1) uBit.display.scroll(last_t2); } -void onTouchP0(MicroBitEvent e) +static void onTouchP0(MicroBitEvent e) { DMESG("TOUCH: P0"); } -void onTouchP1(MicroBitEvent e) +static void onTouchP1(MicroBitEvent e) { DMESG("TOUCH: P1"); } -void onTouchP2(MicroBitEvent e) +static void onTouchP2(MicroBitEvent e) { DMESG("TOUCH: P2"); } -void onTouchFace(MicroBitEvent e) +static void onTouchFace(MicroBitEvent e) { DMESG("TOUCH: FACE"); } diff --git a/source/samples/DeepSleepTest.cpp b/source/samples/DeepSleepTest.cpp new file mode 100644 index 00000000..5afd9513 --- /dev/null +++ b/source/samples/DeepSleepTest.cpp @@ -0,0 +1,302 @@ + +#include "MicroBit.h" +#include "Tests.h" + +//////////////////////////////////////////////////////////////// +// TESTS + +// A fiber that sleeps for a few seconds +static void deepsleep_test1(); + + // A fiber that sleeps until woken by button A or B +static void deepsleep_test2(); + +// A timer event handler that sleeps between events +static void deepsleep_test3(); + +// Wake to run button A or B handlers +static void deepsleep_test4(); + +// Two timer event handlers with different periods that sleep between events +static void deepsleep_test5(); + +//////////////////////////////////////////////////////////////// +// TEST + +void deepsleep_test( int test) +{ + switch ( test) + { + case 1: deepsleep_test1(); break; + case 2: deepsleep_test2(); break; + case 3: deepsleep_test3(); break; + case 4: deepsleep_test4(); break; + case 5: deepsleep_test5(); break; + } + + release_fiber(); +} + +//////////////////////////////////////////////////////////////// +// HELPERS + +static void deepsleep_test_zeroone(); +static void deepsleep_test_threefour(); +static void deepsleep_test_send_time( const char *suffix); + +//////////////////////////////////////////////////////////////// +// TEST 1 + +// A fiber that sleeps for a few seconds + +static void deepsleep_test1_fiber() +{ + while (true) + { + deepsleep_test_send_time( "deepsleep_test1_fiber\n"); + deepsleep_test_zeroone(); + + uBit.power.deepSleep(3000); + } +} + +static void deepsleep_test1() +{ + deepsleep_test_send_time( "deepsleep_test2\n"); + + // Show that display is off during sleep + uBit.display.image.setPixelValue( 2, 0, 128); + + create_fiber( deepsleep_test1_fiber); +} + +//////////////////////////////////////////////////////////////// +// TEST 2 + +// A fiber that sleeps until woken by button A or B + +static void deepsleep_test2_fiber() +{ + while (true) + { + deepsleep_test_send_time( "deepsleep_test2_fiber\n"); + + uBit.power.deepSleep(); + + if ( uBit.buttonA.isPressed()) + uBit.display.print('A'); + else if ( uBit.buttonB.isPressed()) + uBit.display.print('B'); + else + uBit.display.print('C'); + } +} + + +static void deepsleep_test2() +{ + deepsleep_test_send_time( "deepsleep_test2\n"); + + // Show that display is off during sleep + uBit.display.image.setPixelValue( 2, 0, 128); + + uBit.io.buttonA.wakeOnActive(1); + uBit.io.buttonB.wakeOnActive(1); + + create_fiber( deepsleep_test2_fiber); +} + +//////////////////////////////////////////////////////////////// +// TEST 3 + +// A timer event handler that sleeps between events + +static void deepsleep_test3_onTimer(MicroBitEvent e) +{ + deepsleep_test_send_time( "deepsleep_test3_onTimer\n"); + deepsleep_test_zeroone(); + + // Request deep sleep and exit the handler + uBit.power.deepSleepAsync(); +} + + +static void deepsleep_test3() +{ + deepsleep_test_send_time( "deepsleep_test3\n"); + + // Show that display is off during sleep + uBit.display.image.setPixelValue( 2, 0, 128); + + uint16_t timer_id = 60000; + uint16_t timer_value = 1; + CODAL_TIMESTAMP timer_period = 5000; //ms + + uBit.messageBus.listen( timer_id, timer_value, deepsleep_test3_onTimer); + + // CODAL_TIMER_EVENT_FLAGS_WAKEUP makes the timer event trigger power up + system_timer_event_every( timer_period, timer_id, timer_value, CODAL_TIMER_EVENT_FLAGS_WAKEUP); +} + +//////////////////////////////////////////////////////////////// +// TEST 4 + +// Wake to run button A or B handlers + +static void deepsleep_test4_onButtonA(MicroBitEvent e) +{ + // Disable deep sleep power down until we have finished + uBit.power.powerDownDisable(); + + deepsleep_test_zeroone(); + uBit.sleep(500); + deepsleep_test_zeroone(); + + uBit.power.powerDownEnable(); + uBit.power.deepSleepAsync(); +} + + +static void deepsleep_test4_onButtonB(MicroBitEvent e) +{ + uBit.power.powerDownDisable(); + + deepsleep_test_threefour(); + uBit.sleep(500); + deepsleep_test_threefour(); + + uBit.power.powerDownEnable(); + uBit.power.deepSleepAsync(); +} + + +static void deepsleep_test4() +{ + deepsleep_test_send_time( "deepsleep_test4\n"); + + // Show that display is off during sleep + uBit.display.image.setPixelValue( 2, 0, 128); + + uBit.messageBus.listen( MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_DOWN, deepsleep_test4_onButtonA); + uBit.messageBus.listen( MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_DOWN, deepsleep_test4_onButtonB); + + uBit.io.buttonA.wakeOnActive(1); + uBit.io.buttonB.wakeOnActive(1); + + uBit.power.deepSleepAsync(); +} + +//////////////////////////////////////////////////////////////// +// TEST 5 + +// Two timer event handlers with different periods that sleep between events + +static void deepsleep_test5_onTimer1(MicroBitEvent e) +{ + uBit.power.powerDownDisable(); + + deepsleep_test_send_time( "deepsleep_test5_onTimer1\n"); + + deepsleep_test_zeroone(); + uBit.sleep(500); + deepsleep_test_zeroone(); + + uBit.power.powerDownEnable(); + + // Request deep sleep and exit the handler + uBit.power.deepSleepAsync(); +} + + +static void deepsleep_test5_onTimer2(MicroBitEvent e) +{ + uBit.power.powerDownDisable(); + + deepsleep_test_send_time( "deepsleep_test5_onTimer2\n"); + + deepsleep_test_threefour(); + uBit.sleep(500); + deepsleep_test_threefour(); + + uBit.power.powerDownEnable(); + + // Request deep sleep and exit the handler + uBit.power.deepSleepAsync(); +} + + +static void deepsleep_test5() +{ + deepsleep_test_send_time( "deepsleep_test5\n"); + + // Show that display is off during sleep + uBit.display.image.setPixelValue( 2, 0, 128); + + uint16_t timer_id = 60000; + uint16_t timer_value = 1; + + uBit.messageBus.listen( timer_id, timer_value, deepsleep_test5_onTimer1); + uBit.messageBus.listen( timer_id, timer_value + 1, deepsleep_test5_onTimer2); + + // CODAL_TIMER_EVENT_FLAGS_WAKEUP makes the timer event trigger power up + system_timer_event_every( 6000, timer_id, timer_value, CODAL_TIMER_EVENT_FLAGS_WAKEUP); + system_timer_event_every( 20000, timer_id, timer_value + 1, CODAL_TIMER_EVENT_FLAGS_WAKEUP); + + uBit.power.deepSleepAsync(); +} + +//////////////////////////////////////////////////////////////// +// HELPERS + +static void deepsleep_test_togglePixel( int x, int y) +{ + uBit.display.image.setPixelValue( x, y, uBit.display.image.getPixelValue( x, y) ? 0 : 255); +} + + +static void deepsleep_test_sirenPixels( int x0, int y0, int x1, int y1, int ms) +{ + deepsleep_test_togglePixel( x0, y0); + uBit.sleep(ms); + deepsleep_test_togglePixel( x0, y0); + deepsleep_test_togglePixel( x1, y1); + uBit.sleep(ms); + deepsleep_test_togglePixel( x1, y1); +} + + +static void deepsleep_test_zeroone() +{ + deepsleep_test_send_time( "deepsleep_test_zeroone\n"); + deepsleep_test_sirenPixels( 0, 0, 1, 0, 150); +} + + +static void deepsleep_test_threefour() +{ + deepsleep_test_send_time( "deepsleep_test_threefour\n"); + deepsleep_test_sirenPixels( 3, 0, 4, 0, 500); +} + + +static void deepsleep_test_send_time( const char *suffix) +{ + uint64_t second = 1000000; + + uint64_t now = system_timer_current_time_us(); + + int u = (int) (now % second); + int s = (int) (now / second); + int m = s / 60; + s = s % 60; + int h = m / 60; + m = m % 60; + + ManagedString sh( h); + ManagedString sm( m); sm = "00" + sm; sm = sm.substring( sm.length() - 2, 2); + ManagedString ss( s); ss = "00" + ss; ss = ss.substring( ss.length() - 2, 2); + ManagedString su( u); su = "000000" + su; su = su.substring( su.length() - 6, 6); + ManagedString msg = sh + ":" + sm + ":" + ss + "." + su + " " + ManagedString(suffix); + uBit.serial.send( msg); +} + diff --git a/source/samples/DisplayTest.cpp b/source/samples/DisplayTest.cpp index beb6a56d..6bdea56d 100644 --- a/source/samples/DisplayTest.cpp +++ b/source/samples/DisplayTest.cpp @@ -50,10 +50,7 @@ const char * const sad_emoji ="\ 000,255,255,255,000\n\ 255,000,000,000,255\n"; -Image happy(happy_emoji); -Image sad(sad_emoji); - -void +static void concurrent_display_test_t1() { while(1) @@ -63,7 +60,7 @@ concurrent_display_test_t1() } } -void +static void concurrent_display_test_t2() { uBit.sleep(500); @@ -245,7 +242,7 @@ raw_blinky_test() } -void +static void onButtonAPressed(MicroBitEvent) { const char * const a_emoji ="\ @@ -259,7 +256,7 @@ onButtonAPressed(MicroBitEvent) uBit.display.print(img_a); } -void +static void onButtonBPressed(MicroBitEvent) { const char * const b_emoji ="\ @@ -272,7 +269,7 @@ onButtonBPressed(MicroBitEvent) uBit.display.print(img_b); } -void +static void onButtonABPressed(MicroBitEvent) { const char * const c_emoji ="\ @@ -285,7 +282,7 @@ onButtonABPressed(MicroBitEvent) uBit.display.print(img_c); } -void +static void onShakePressed(MicroBitEvent) { const char * const d_emoji ="\ @@ -298,7 +295,7 @@ onShakePressed(MicroBitEvent) uBit.display.print(img_d); } -void +static void do_something_forever() { uBit.sleep(10); diff --git a/source/samples/MicrophoneTest.cpp b/source/samples/MicrophoneTest.cpp index ff575839..e97e32a9 100644 --- a/source/samples/MicrophoneTest.cpp +++ b/source/samples/MicrophoneTest.cpp @@ -1,3 +1,4 @@ +#include #include "MicroBit.h" #include "SerialStreamer.h" #include "StreamNormalizer.h" @@ -13,7 +14,7 @@ static LevelDetectorSPL *levelSPL = NULL; static int claps = 0; static volatile int sample; -void +static void onLoud(MicroBitEvent) { DMESG("LOUD"); @@ -24,7 +25,7 @@ onLoud(MicroBitEvent) uBit.display.print(claps); } -void +static void onQuiet(MicroBitEvent) { DMESG("QUIET"); @@ -69,6 +70,26 @@ mems_mic_test() uBit.sleep(1000); } +// WARNING! For this test to run correctly floats for printf/sprintf/snprintf +// have to be enabled by adding this flag to the linker (target.json): +// -u _printf_float +void +mems_mic_zero_offset_test() +{ + LevelDetectorSPL* levelSPL = new LevelDetectorSPL(uBit.audio.processor->output, 85.0, 65.0, 16.0, 0, DEVICE_ID_SYSTEM_LEVEL_DETECTOR, false); + uBit.audio.activateMic(); + + char float_str[20]; + volatile auto value = 0; + + while (true) { + value = levelSPL->getValue(); + snprintf(float_str, 80, "%.4f", uBit.audio.processor->zeroOffset); + uBit.serial.printf("%s\n", float_str); + uBit.sleep(1); + } +} + void mems_clap_test(int wait_for_clap) { diff --git a/source/samples/NeopixelsTest.cpp b/source/samples/NeopixelsTest.cpp new file mode 100644 index 00000000..5d697ada --- /dev/null +++ b/source/samples/NeopixelsTest.cpp @@ -0,0 +1,66 @@ +/* +The MIT License (MIT) + +Copyright (c) 2021 Lancaster University. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include "MicroBit.h" +#include "Tests.h" +#include "neopixel.h" + +extern MicroBit uBit; + +void +neopixel_test() +{ + // Length of neopixel strip + int length = 8; + + // Brightness of pixels + int brightness = 32; + + // Colour counter variable (just used to remember what colour we last displayed) + int c = 0; + + // Create a buffer to hold pixel data of the appropriate size + ManagedBuffer b(length*3); + + while(1) + { + // Clear the buffer to zeroes. You don't need to do this, but it's often convenient. + b.fill(0); + + // Fill the buffer with some data. + // Neopixel typically has 3 bytes per pixel, for each primary colour + // in GRB format (Green, then Red, then Blue). + for (int i=0; i +#include "Synthesizer.h" #define OOB_SHAKE_OVERSAMPLING 5 #define OOB_SHAKE_OVERSAMPLING_THRESHOLD 4 -#define OOB_SHAKE_THRESHOLD 4000 - - /* - * This is the program that will be shipped with the 550 micro:bits - * for the journalists in August. It is the first prototype of the - * first experience. - */ +#define OOB_SHAKE_THRESHOLD 1200 enum modes { WAKE = 0, INTRO, BUTTON_A, BUTTON_B, + LOGO_BUTTON, TURN, DOTCHASER, + CLAP, NEXT, SECRET }; @@ -27,9 +29,12 @@ int accelX, accelY; int targetX, targetY; bool flag = false; MicroBitImage currentFrame; - +bool mute = false; + +int basenote = 52; //shake game + int shake_detected = 0; int shakeCount; int xMin; int xMax; @@ -41,83 +46,136 @@ MicroBitImage currentFrame; // Images and animations ----------------- -const MicroBitImage dot("0,1,0,1,0\n1,1,1,1,1\n1,1,1,1,1\n0,1,1,1,0\n0,0,1,0,0\n"); +const MicroBitImage dot("0,255,0,255,0\n255,255,255,255,255\n255,255,255,255,255\n0,255,255,255,0\n0,0,255,0,0\n"); const char *shake[] = { "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n", - "0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n0,0,0,0,0\n0,0,0,0,0\n", - "0,0,0,0,0\n0,1,0,1,0\n0,0,1,0,0\n0,1,0,1,0\n0,0,0,0,0\n", - "0,0,1,0,0\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n0,0,1,0,0\n", - "1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n", - "1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n" + "0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,0,0,0\n0,0,0,0,0\n", + "0,0,0,0,0\n0,255,0,255,0\n0,0,255,0,0\n0,255,0,255,0\n0,0,0,0,0\n", + "0,0,255,0,0\n0,255,0,255,0\n255,0,255,0,255\n0,255,0,255,0\n0,0,255,0,0\n", + "255,0,255,0,255\n0,255,0,255,0\n255,0,255,0,255\n0,255,0,255,0\n255,0,255,0,255\n", + "255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n" }; const char *wakeAnim[] = { - "0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n0,0,0,0,0\n0,0,0,0,0\n", - "0,0,0,0,0\n0,1,1,1,0\n0,1,1,1,0\n0,1,1,1,0\n0,0,0,0,0\n", - "1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n" + "0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,0,0,0\n0,0,0,0,0\n", + "0,0,0,0,0\n0,255,255,255,0\n0,255,255,255,0\n0,255,255,255,0\n0,0,0,0,0\n", + "255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n" }; const char *explosionTime[] = { - "1,1,1,1,1\n1,0,0,0,1\n1,0,0,0,1\n1,0,0,0,1\n1,1,1,1,1\n", - "1,1,1,1,1\n1,1,1,1,1\n1,1,0,1,1\n1,1,1,1,1\n1,1,1,1,1\n", - "1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n1,1,1,1,1\n", - "0,0,0,0,0\n0,1,1,1,0\n0,1,1,1,0\n0,1,1,1,0\n0,0,0,0,0\n", - "0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n0,0,0,0,0\n0,0,0,0,0\n", - "0,0,0,0,0\n0,1,0,1,0\n0,0,0,0,0\n0,1,0,1,0\n0,0,0,0,0\n", - "1,0,0,0,1\n0,0,1,0,0\n0,1,1,1,0\n0,0,1,0,0\n1,0,0,0,1\n", - "0,0,1,0,0\n0,1,0,1,0\n1,0,0,0,1\n0,1,0,1,0\n0,0,1,0,0\n", - "1,0,0,0,1\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n1,0,0,0,1\n", + "255,255,255,255,255\n255,0,0,0,255\n255,0,0,0,255\n255,0,0,0,255\n255,255,255,255,255\n", + "255,255,255,255,255\n255,255,255,255,255\n255,255,0,255,255\n255,255,255,255,255\n255,255,255,255,255\n", + "255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n", + "0,0,0,0,0\n0,255,255,255,0\n0,255,255,255,0\n0,255,255,255,0\n0,0,0,0,0\n", + "0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,0,0,0\n0,0,0,0,0\n", + "0,0,0,0,0\n0,255,0,255,0\n0,0,0,0,0\n0,255,0,255,0\n0,0,0,0,0\n", + "255,0,0,0,255\n0,0,255,0,0\n0,255,255,255,0\n0,0,255,0,0\n255,0,0,0,255\n", + "0,0,255,0,0\n0,255,0,255,0\n255,0,0,0,255\n0,255,0,255,0\n0,0,255,0,0\n", + "255,0,0,0,255\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n255,0,0,0,255\n", "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n" }; const char *twistyTime[] = { - "0,0,0,0,0\n0,0,0,0,0\n1,0,0,0,1\n0,0,0,0,0\n0,0,0,0,0\n", - "0,0,0,0,0\n1,0,0,0,1\n1,1,0,1,1\n1,0,0,0,1\n0,0,0,0,0\n", - "1,0,0,0,1\n1,1,0,1,1\n1,1,1,1,1\n1,1,0,1,1\n1,0,0,0,1\n", - "0,0,0,1,1\n1,0,0,1,1\n1,1,1,1,1\n1,1,0,0,1\n1,1,0,0,0\n", - "0,1,1,1,1\n0,0,1,1,1\n1,0,1,0,1\n1,1,1,0,0\n1,1,1,1,0\n", - "1,1,1,1,1\n0,0,1,1,1\n0,0,1,0,0\n1,1,1,0,0\n1,1,1,1,1\n", - "1,1,1,1,1\n0,1,1,1,0\n0,0,1,0,0\n0,1,1,1,0\n1,1,1,1,1\n", - "0,1,1,1,0\n0,0,1,0,0\n0,0,0,0,0\n0,0,1,0,0\n0,1,1,1,0\n", - "0,0,1,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n", + "0,0,0,0,0\n0,0,0,0,0\n255,0,0,0,255\n0,0,0,0,0\n0,0,0,0,0\n", + "0,0,0,0,0\n255,0,0,0,255\n255,255,0,255,255\n255,0,0,0,255\n0,0,0,0,0\n", + "255,0,0,0,255\n255,255,0,255,255\n255,255,255,255,255\n255,255,0,255,255\n255,0,0,0,255\n", + "0,0,0,255,255\n255,0,0,255,255\n255,255,255,255,255\n255,255,0,0,255\n255,255,0,0,0\n", + "0,255,255,255,255\n0,0,255,255,255\n255,0,255,0,255\n255,255,255,0,0\n255,255,255,255,0\n", + "255,255,255,255,255\n0,0,255,255,255\n0,0,255,0,0\n255,255,255,0,0\n255,255,255,255,255\n", + "255,255,255,255,255\n0,255,255,255,0\n0,0,255,0,0\n0,255,255,255,0\n255,255,255,255,255\n", + "0,255,255,255,0\n0,0,255,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,255,255,255,0\n", + "0,0,255,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n", "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n" }; const char *heart[] = { - "0,1,0,1,0\n1,1,1,1,1\n1,1,1,1,1\n0,1,1,1,0\n0,0,1,0,0\n" + "0,255,0,255,0\n255,255,255,255,255\n255,255,255,255,255\n0,255,255,255,0\n0,0,255,0,0\n" }; // Arrow images and animations. -const MicroBitImage arrowUpTime("0,0,1,0,0\n0,1,1,1,0\n1,0,1,0,1\n0,0,1,0,0\n0,0,1,0,0\n"); +const MicroBitImage arrowUpTime("0,0,255,0,0\n0,255,255,255,0\n255,0,255,0,255\n0,0,255,0,0\n0,0,255,0,0\n"); const char *arrowDisintegrationTime[] = { - "0,0,0,0,0\n0,0,1,0,0\n0,0,1,0,0\n1,0,1,0,1\n0,1,1,1,0\n", - "0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n0,0,1,0,0\n1,0,1,0,1\n", - "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n0,0,1,0,0\n", - "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,1,0,0\n", + "0,0,0,0,0\n0,0,255,0,0\n0,0,255,0,0\n255,0,255,0,255\n0,255,255,255,0\n", + "0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,255,0,0\n255,0,255,0,255\n", + "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,255,0,0\n", + "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n", "0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n0,0,0,0,0\n" }; // Bottom arrow from left to right const char *bottomArrow[] = { - "0,0,1,0,0\n0,1,0,0,0\n1,1,1,1,1\n0,1,0,0,0\n0,0,1,0,0\n", - "0,0,0,0,1\n1,0,0,1,0\n1,0,1,0,0\n1,1,0,0,0\n1,1,1,1,0\n", - "0,0,1,0,0\n0,0,1,0,0\n1,0,1,0,1\n0,1,1,1,0\n0,0,1,0,0\n", - "1,0,0,0,0\n0,1,0,0,1\n0,0,1,0,1\n0,0,0,1,1\n0,1,1,1,1\n", - "0,0,1,0,0\n0,0,0,1,0\n1,1,1,1,1\n0,0,0,1,0\n0,0,1,0,0\n" + "0,0,255,0,0\n0,255,0,0,0\n255,255,255,255,255\n0,255,0,0,0\n0,0,255,0,0\n", + "0,0,0,0,255\n255,0,0,255,0\n255,0,255,0,0\n255,255,0,0,0\n255,255,255,255,0\n", + "0,0,255,0,0\n0,0,255,0,0\n255,0,255,0,255\n0,255,255,255,0\n0,0,255,0,0\n", + "255,0,0,0,0\n0,255,0,0,255\n0,0,255,0,255\n0,0,0,255,255\n0,255,255,255,255\n", + "0,0,255,0,0\n0,0,0,255,0\n255,255,255,255,255\n0,0,0,255,0\n0,0,255,0,0\n" }; const char *topArrow[] = { - "0,0,1,0,0\n0,1,0,0,0\n1,1,1,1,1\n0,1,0,0,0\n0,0,1,0,0\n", - "1,1,1,1,0\n1,1,0,0,0\n1,0,1,0,0\n1,0,0,1,0\n0,0,0,0,1\n", - "0,0,1,0,0\n0,1,1,1,0\n1,0,1,0,1\n0,0,1,0,0\n0,0,1,0,0\n", - "0,1,1,1,1\n0,0,0,1,1\n0,0,1,0,1\n0,1,0,0,1\n1,0,0,0,0\n", - "0,0,1,0,0\n0,0,0,1,0\n1,1,1,1,1\n0,0,0,1,0\n0,0,1,0,0\n" + "0,0,255,0,0\n0,255,0,0,0\n255,255,255,255,255\n0,255,0,0,0\n0,0,255,0,0\n", + "255,255,255,255,0\n255,255,0,0,0\n255,0,255,0,0\n255,0,0,255,0\n0,0,0,0,255\n", + "0,0,255,0,0\n0,255,255,255,0\n255,0,255,0,255\n0,0,255,0,0\n0,0,255,0,0\n", + "0,255,255,255,255\n0,0,0,255,255\n0,0,255,0,255\n0,255,0,0,255\n255,0,0,0,0\n", + "0,0,255,0,0\n0,0,0,255,0\n255,255,255,255,255\n0,0,0,255,0\n0,0,255,0,0\n" }; - + +int target_freq; +int current_freq; +int playback_sleep = 5; +int slide = 1; +int chatter = false; +int chatter_toggle = false; + // --------------------------- +void playfreq(int freq) +{ + if (mute || freq == 0) { + uBit.io.speaker.setAnalogValue(0); + uBit.io.P0.setAnalogValue(0); + return; + } + uBit.io.speaker.setHighDrive(true); + uBit.io.speaker.setAnalogValue(512); + uBit.io.P0.setHighDrive(true); + uBit.io.P0.setAnalogValue(512); + int period = 1000000.0/(float)freq; + + uBit.io.speaker.setAnalogPeriodUs(period); + uBit.io.P0.setAnalogPeriodUs(period); + return; +} + +void play_note(uint8_t note) { + if(note == 0) { + target_freq = 0; + return; + } + + // A 440hz + int f = 440.0 * pow(2, ((float)(note - 58)/12.0)); + target_freq = f; + + uBit.serial.printf("%d \r\n", note); +} + +void playback_ticker() { + // Thread forever + while(1) { + + if(target_freq == 0) { + current_freq = 0; + playfreq(0); + } else { + current_freq += (target_freq - current_freq) / slide; + playfreq(current_freq); + } + fiber_sleep(playback_sleep); + } +} + // Wake up the device void wake() { @@ -125,45 +183,63 @@ void wake() // Turn on all pixels. for(int y=0; y<5; y++) { for(int x=0; x<5; x++) { - uBit.display.image.setPixelValue(x, y, 1); + uBit.display.image.setPixelValue(x, y, 255); } } // Fade in all LEDs. for(int i=0; i<255; i++) { uBit.display.setBrightness(i); - uBit.sleep(5); + uBit.sleep(10); + target_freq = i; } + // Fade out all LEDs. for(int i=255; i>0; i--) { uBit.display.setBrightness(i); - uBit.sleep(5); + uBit.sleep(10); + target_freq = i; } + play_note(0); // Set brightness back to full and clear screen. uBit.display.image.clear(); uBit.display.setBrightness(255); + slide = 1; // Pulsing animation. - int animDelay = 50; - for(int j=0; j<15; j++) { + int animDelay = 100; + for(int j=0; j<20; j++) { + int k = 0; for(int i=0; i<3; i++) { currentFrame = MicroBitImage(wakeAnim[i]); + play_note((3*j) + k*5); + k = k + 2; uBit.display.print(currentFrame,0,0,0,animDelay); } for(int i=2; i>-1; i--) { currentFrame = MicroBitImage(wakeAnim[i]); + play_note((3 * j) + k*5); + k++; uBit.display.print(currentFrame,0,0,0,animDelay); } - animDelay -= 3; + animDelay -= 5; } + + play_note(basenote); + uBit.sleep(300); // Fade out last dot. + //freq = 512; + // Our frequency goes negative in this loop but it sounds cool! for(int i=255; i>=0; i--) { uBit.display.setBrightness(i); uBit.sleep(1); + //freq = freq-10; + //playfreq(freq); } + play_note(0); // Clear display and set brightnes back to full. uBit.display.image.clear(); uBit.display.setBrightness(255); @@ -178,79 +254,155 @@ void intro() { // Introduce the micro:bit. uBit.display.image.clear(); - uBit.display.scroll("HELLO."); - + chatter = true; + uBit.display.scroll("HELLO", 150); + chatter = false; + + slide = 5; + MicroBitImage smiley("0,0,0,0, 0\n0,255,0,255,0\n0,0,0,0,0\n255,0,0,0,255\n0,255,255,255,0\n"); + uBit.display.print(smiley); + uBit.display.setBrightness(0); + for(int b = 0; b < 255; b++) { + uBit.sleep(2000 / 255); + uBit.display.setBrightness(b); + } + + play_note(basenote + 12); + uBit.sleep(100); + play_note(0); + uBit.sleep(20); + play_note(basenote + 5); + uBit.sleep(300); + play_note(0); + uBit.sleep(1000); + // Proceed to the next mode. mode++; } - + +int button_a_pressed = false; +void OOB_onButtonA(MicroBitEvent) +{ + button_a_pressed = true; +} + void pressButtonA() { // Give instruction // uBit.display.print("A"); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, OOB_onButtonA); // Wait for a button press. - while(!uBit.buttonA.isPressed()) { - uBit.display.print("A ",100); - uBit.sleep(1); - uBit.display.print("A ",100); - uBit.sleep(1); - if(uBit.buttonA.isPressed()) break; + while(!button_a_pressed) { + uBit.display.print("A"); + uBit.sleep(500); + if(button_a_pressed) break; currentFrame = MicroBitImage(topArrow[0]); uBit.display.print(currentFrame,0,0,0,100); uBit.sleep(100); - if(uBit.buttonA.isPressed()) break; + if(button_a_pressed) break; currentFrame = MicroBitImage(topArrow[0]); uBit.display.print(currentFrame,0,0,0,100); uBit.sleep(100); - if(uBit.buttonA.isPressed()) break; + if(button_a_pressed) break; } // SADHBH'S animation goes here. for(int i=0; i<10; i++) { currentFrame = MicroBitImage(explosionTime[i]); uBit.display.print(currentFrame,0,0,0,100); + play_note(basenote + (i * 5)) ; } + play_note(0); uBit.display.stopAnimation(); uBit.sleep(1000); // Proceed to the next mode. - mode++; } +int button_b_pressed = false; +void OOB_onButtonB(MicroBitEvent) +{ + button_b_pressed = true; +} + void pressButtonB() { // Give instruction + uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, OOB_onButtonB); // Wait for a button press. - while(!uBit.buttonB.isPressed()) { - uBit.display.print("B ",100); - uBit.sleep(1); - uBit.display.print("B ",100); - uBit.sleep(1); - if(uBit.buttonB.isPressed()) break; + while(!button_b_pressed) { + uBit.display.print("B"); + uBit.sleep(500); + if(button_b_pressed) break; currentFrame = MicroBitImage(topArrow[4]); uBit.display.print(currentFrame,0,0,0,100); uBit.sleep(100); - if(uBit.buttonB.isPressed())break; + if(button_b_pressed)break; currentFrame = MicroBitImage(topArrow[4]); uBit.display.print(currentFrame,0,0,0,100); uBit.sleep(100); - if(uBit.buttonB.isPressed())break; + if(button_b_pressed)break; + } + + // SADHBH'S animation goes here. + for(int i=0; i<10; i++) { + currentFrame = MicroBitImage(twistyTime[i]); + uBit.display.print(currentFrame,0,0,0,100); + play_note(basenote + (9*5) - (i * 5)) ; + } + play_note(0); + + uBit.sleep(2000); + + // Proceed to the next mode. + mode++; +} + +int button_logo_pressed = false; +void OOB_onButtonLogo(MicroBitEvent) +{ + button_logo_pressed = true; +} + +void pressLogoButton() +{ + // Give instruction + + uBit.messageBus.listen(MICROBIT_ID_LOGO, MICROBIT_BUTTON_EVT_CLICK, OOB_onButtonLogo); + + // Wait for a button press. + while(!button_b_pressed) { + uBit.display.print("Logo"); + uBit.sleep(500); + if(button_logo_pressed) break; + + currentFrame = MicroBitImage(topArrow[2]); + uBit.display.print(currentFrame,0,0,0,100); + uBit.sleep(100); + if(button_logo_pressed)break; + + currentFrame = MicroBitImage(topArrow[2]); + uBit.display.print(currentFrame,0,0,0,100); + uBit.sleep(100); + if(button_logo_pressed)break; } // SADHBH'S animation goes here. for(int i=0; i<10; i++) { currentFrame = MicroBitImage(twistyTime[i]); uBit.display.print(currentFrame,0,0,0,100); + play_note(basenote + (9*5) - (i * 5)) ; } + play_note(0); uBit.sleep(2000); @@ -287,15 +439,21 @@ void turn() int timeout = 0; int samples_high; int x, y, z, magnitude; + + playback_sleep = 100; - uBit.display.scroll("SHAKE!"); + uBit.display.scroll("SHAKE!", 200); uBit.accelerometer.setRange(8); xMax = uBit.accelerometer.getX(); yMax = uBit.accelerometer.getY(); - while(timeout < 10000) { + shake_detected = 0; + slide = 1; + + while(timeout < 20000 || shake_detected == 0) { + samples_high = 0; for (int samples = 0; samples < OOB_SHAKE_OVERSAMPLING; samples++) { @@ -316,15 +474,29 @@ void turn() // Clamp shakeCount within range 0..4 shakeCount = min(shakeCount, 4); shakeCount = max(shakeCount, 0); - + // Display an image matching the shake intensity measured currentFrame = MicroBitImage(shake[shakeCount]); uBit.display.print(currentFrame); + if(shakeCount > 0) { + play_note(basenote + 7*shakeCount); + } else { + play_note(0); + } + + if(shakeCount == 4) shake_detected = 1; // Exit on large shake + + // Wait a while. + uBit.sleep(150); + timeout += 150; + + if(((timeout % 3000) == 0) && !shake_detected) { + uBit.display.scroll("SHAKE!", 200); + } - // Wait a while. - uBit.sleep(150); - timeout += 150; } + playback_sleep = 5; + play_note(0); uBit.accelerometer.setRange(2); uBit.display.image.clear(); @@ -345,13 +517,23 @@ void insertNewTarget() void dotChaser() { - uBit.display.scroll("CHASE THE DOT"); + uBit.display.scroll("TILT", 200); + slide = 1; int score = 0; int toggle = 0; int toggleCount = 0; - - while(score < 6) { + + // Get initial positions + updateAccelPosition(); + int last_x = accelX; + int last_y = accelY; + + // Timeout + int timeout = 0; + + slide = 3; + while(score < 3) { if(toggleCount % 5 == 0) toggle = 255-toggle; updateAccelPosition(); @@ -361,16 +543,47 @@ void dotChaser() uBit.display.image.setPixelValue(targetX, targetY, toggle); if(targetX == accelX && targetY == accelY) { + play_note(0); + uBit.sleep(100); + for(int z = 0; z < 4; z++) { + current_freq = 2000; + play_note(basenote + 12*z); + uBit.sleep(100); + } insertNewTarget(); score++; + play_note(0); + uBit.sleep(300); + } + + if(last_x != accelX || last_y != accelY) { + play_note(basenote - 12 + (12 * accelX) + (3 * accelY)); + last_x = accelX; + last_y = accelY; + timeout = 0; + } else { + play_note(0); + } + + if(timeout > 5000) { + uBit.display.scroll("TILT", 200); + timeout = 0; } uBit.sleep(100); + timeout += 100; toggleCount++; } - + + play_note(0); // Fade out last dot. + for(int z = 0; z < 10; z++) { + current_freq = 2000; + play_note(basenote + 12*(z%5)); + uBit.sleep(100); + } + play_note(0); for(int i=255; i>=0; i--) { uBit.display.setBrightness(i); uBit.sleep(1); @@ -547,51 +760,119 @@ void snake() uBit.sleep(SNAKE_FRAME_DELAY); } } + +void OOB_onButtonAExtra() { + uBit.display.stopAnimation(); + for(int i=0; i<10; i++) { + currentFrame = MicroBitImage(explosionTime[i]); + uBit.display.print(currentFrame,0,0,0,100); + play_note(basenote + (i * 5)) ; + } + currentFrame = MicroBitImage(heart[0]); + play_note(0); + uBit.display.image.clear(); + uBit.display.print(currentFrame,0,0,0,400); + mode++; +} + +void OOB_onButtonBExtra() { + uBit.display.stopAnimation(); + for(int i=0; i<10; i++) { + currentFrame = MicroBitImage(twistyTime[i]); + uBit.display.print(currentFrame,0,0,0,100); + play_note(basenote + (9*5) - (i * 5)) ; + } + play_note(0); + currentFrame = MicroBitImage(heart[0]); + uBit.display.image.clear(); + uBit.display.print(currentFrame,0,0,0,400); + mode++; +} void next() { if(flag == false){ - flag = true; - uBit.display.scroll("GREAT! NOW GET CODING!"); + flag = true; + for(int i = 0; i < 5; i++) { + play_note(basenote + i * 5); + uBit.sleep(100); + } + play_note(0); + uBit.display.scroll("WOW!", 200); } - while(!uBit.buttonA.isPressed() && !uBit.buttonB.isPressed()){ - for(int i=0; i<10; i++) { - currentFrame = MicroBitImage(twistyTime[i]); - uBit.display.print(currentFrame,0,0,0,100); - if(uBit.buttonA.isPressed() && uBit.buttonB.isPressed()){ - uBit.display.stopAnimation(); - break; - } - } - for(int i=0; i<10; i++) { - currentFrame = MicroBitImage(explosionTime[i]); - uBit.display.print(currentFrame,0,0,0,100); - if(uBit.buttonA.isPressed() && uBit.buttonB.isPressed()){ - uBit.display.stopAnimation(); - break; - } - } - currentFrame = MicroBitImage(heart[0]); + + int nRuns = 0; + while(!uBit.buttonA.isPressed() && !uBit.buttonB.isPressed() && mode == NEXT){ + for(int i=0; i<10; i++) { + if(nRuns<3) play_note(basenote + (3 * (i % 4))); + currentFrame = MicroBitImage(twistyTime[i]); + uBit.display.print(currentFrame,0,0,0,100); + if(uBit.buttonA.isPressed() && uBit.buttonB.isPressed()){ + uBit.display.stopAnimation(); + break; + } + if(uBit.buttonA.isPressed()) OOB_onButtonAExtra(); + if(uBit.buttonB.isPressed()) OOB_onButtonBExtra(); + } + for(int i=0; i<10; i++) { + if(nRuns<3) play_note(basenote + (5 * (i % 4))); + currentFrame = MicroBitImage(explosionTime[i]); + uBit.display.print(currentFrame,0,0,0,100); + if(uBit.buttonA.isPressed() && uBit.buttonB.isPressed()){ + uBit.display.stopAnimation(); + break; + } + if(uBit.buttonA.isPressed()) OOB_onButtonAExtra(); + if(uBit.buttonB.isPressed()) OOB_onButtonBExtra(); + } + play_note(0); + currentFrame = MicroBitImage(heart[0]); uBit.display.print(currentFrame,0,0,0,400); uBit.sleep(100); if(uBit.buttonA.isPressed() && uBit.buttonB.isPressed()){ uBit.display.stopAnimation(); break; - } } - mode++; - - - - + if(uBit.buttonA.isPressed()) OOB_onButtonAExtra(); + if(uBit.buttonB.isPressed()) OOB_onButtonBExtra(); + nRuns++; + } + mode++; +} + +void make_noise() { + uBit.display.scroll("MAKE NOISE!", 200); + level_meter(); + mode++; +} + +void clap() { + uBit.display.scroll("CLAP!", 200); + mems_clap_test(1); + mode++; } -int -out_of_box_experience() +void onFacePalm(MicroBitEvent e) { + uBit.serial.printf("face palm \r\n"); + mute = !mute; +} + +void +out_of_box_experience_v2() { + target_freq = 0; + current_freq = 0; + + create_fiber(playback_ticker); + + /* Disable face touch to mute + uBit.io.face.isTouched(); + uBit.messageBus.listen(uBit.io.face.id, MICROBIT_BUTTON_EVT_CLICK, onFacePalm); + */ + + mode = WAKE; + if(uBit.buttonA.isPressed()) mode = SECRET; - uBit.sleep(2000); - mode=2; while(1) { switch(mode) { @@ -612,6 +893,10 @@ out_of_box_experience() pressButtonB(); break; + case LOGO_BUTTON: + pressLogoButton(); + break; + case TURN: turn(); break; @@ -619,15 +904,21 @@ out_of_box_experience() case DOTCHASER: dotChaser(); break; - + + case CLAP: + clap(); + break; + case NEXT: next(); break; case SECRET: + default: snake(); break; } } } + diff --git a/source/samples/OOB_v3.cpp b/source/samples/OOB_v3.cpp new file mode 100644 index 00000000..7e2a750e --- /dev/null +++ b/source/samples/OOB_v3.cpp @@ -0,0 +1,321 @@ +#include "MicroBit.h" +#include "Synthesizer.h" +#include "StreamRecording.h" +#include "LowPassFilter.h" +#include "Tests.h" + +const char * const heart = + "000,255,000,255,000\n" + "255,255,255,255,255\n" + "255,255,255,255,255\n" + "000,255,255,255,000\n" + "000,000,255,000,000\n"; +static const MicroBitImage HEART(heart); + +const char * const happy = + "000,000,000,000,000\n" + "000,255,000,255,000\n" + "000,000,000,000,000\n" + "255,000,000,000,255\n" + "000,255,255,255,000\n"; +static const MicroBitImage HAPPY(happy); + +const char * const sad = + "000,000,000,000,000\n" + "000,255,000,255,000\n" + "000,000,000,000,000\n" + "000,255,255,255,000\n" + "255,000,000,000,255\n"; +static const MicroBitImage SAD(sad); + +const char * const silent = + "000,255,000,255,000\n" + "000,000,000,000,000\n" + "000,000,000,000,000\n" + "255,255,255,255,255\n" + "000,000,000,000,000\n"; +static const MicroBitImage SILENT(silent); + +const char * const singing = + "000,255,000,255,000\n" + "000,000,000,000,000\n" + "000,255,255,255,000\n" + "255,000,000,000,255\n" + "000,255,255,255,000\n"; +static const MicroBitImage SINGING(singing); + +const char * const asleep = + "000,000,000,000,000\n" + "255,255,000,255,255\n" + "000,000,000,000,000\n" + "000,255,255,255,000\n" + "000,000,000,000,000\n"; +static const MicroBitImage ASLEEP(asleep); + +const char * const sun = + "255,000,255,000,255\n" + "000,255,255,255,000\n" + "255,255,255,255,255\n" + "000,255,255,255,000\n" + "255,000,255,000,255\n"; +static const MicroBitImage SUN(sun); + +const char * const moon = + "000,000,255,255,000\n" + "000,000,000,255,255\n" + "000,000,000,255,255\n" + "000,000,000,255,255\n" + "000,000,255,255,000\n"; +static const MicroBitImage MOON(moon); + +// MakeCode melodies in the format NOTE[octave][:duration] +static const int DEFAULT_TEMPO_BPM = 120; +static const int MS_PER_BPM = (60000 / DEFAULT_TEMPO_BPM) / 4; +static const int NOTE_LEN = 6; +#define TUNE_LEN(tune) (sizeof(tune) / sizeof(tune[0])) + +static const char MELODY_POWER_UP[][NOTE_LEN] = {"G4:1", "C5", "E", "G:2", "E:1", "G:3"}; +static const char MELODY_POWER_DOWN[][NOTE_LEN] = {"G5:1", "D#", "C", "G4:2", "B5:1", "C:3"}; + + +/** + * Displays a vertical bar graph based on the `value` and `high` arguments. + * + * Function adapted from the MakeCode project, Copyright Microsoft Corporation + * MIT Licensed (MIT): + * https://github.com/microsoft/pxt-microbit/blob/v5.1.25/libs/core/led.ts#L42-L83 + * https://github.com/microsoft/pxt-microbit/blob/v5.1.25/LICENSE.txt + * + * @param value - Current value to plot. + * @param high - Maximum value. + */ +static void plotBarGraph(uint32_t value, int high) { + float v = (float)value / (float)high; + float dv = 1.0 / 16.0; + float k = 0; + for (int y = 4; y >= 0; --y) { + for (int x = 0; x < 3; ++x) { + if (k > v) { + uBit.display.image.setPixelValue(2 - x, y, 0); + uBit.display.image.setPixelValue(2 + x, y, 0); + } else { + uBit.display.image.setPixelValue(2 - x, y, 255); + uBit.display.image.setPixelValue(2 + x, y, 255); + } + k += dv; + } + } +} + +static void playMelody(const char melody[][NOTE_LEN], size_t len) { + DMESG("Tune len: %d", len); + + // Starting from default values, optional octave & duration values are remembered + int octave = 4; + int durationMs = 4 * MS_PER_BPM; + + for (size_t i = 0; i < len; i++) { + const char *note = melody[i]; + const char *note_char = &melody[i][0]; + int distanceFromA = 0; + int frequency = 0; + bool rest = false; + + // First process the note, as its distance from A + switch (*note_char) { + case 'A': distanceFromA = 0; break; + case 'B': distanceFromA = 2; break; + case 'C': distanceFromA = -9; break; + case 'D': distanceFromA = -7; break; + case 'E': distanceFromA = -5; break; + case 'F': distanceFromA = -4; break; + case 'G': distanceFromA = -2; break; + case 'R': rest = true; break; + default: target_panic(123); break; + } + + // Then process the optional #/b modifiers and/or scale + note_char++; + while (*note_char != ':' && *note_char != '\0') { + if (*note_char == '#') { + distanceFromA++; + } else if (*note_char == 'b') { + distanceFromA--; + } else if ((*note_char >= '0') && (*note_char <= '9')) { + octave = (*note_char - '0'); + } else { + target_panic(124); + } + note_char++; + } + + // If an optional duration is present, calculate the delay in ms + // Note, only a single digit implemented right now + if (*note_char == ':') { + note_char++; + if ((*note_char < '0') || (*note_char > '9')) target_panic(125); + durationMs = atoi((const char*)note_char) * MS_PER_BPM; + } + + // Calculate note frequency, or keep it as zero for a rest + if (!rest) { + float distanceFromA4 = (octave - 4) * 12 + distanceFromA; + frequency = 440.0 * pow(2, distanceFromA4 / 12.0); + } + + // Play the tone/rest for the calculated duration + DMESG("%s -> f:%u, ms:%d", note, frequency, durationMs); + if (frequency) { + uBit.audio.virtualOutputPin.setAnalogPeriodUs(1000000 / frequency); + uBit.audio.virtualOutputPin.setAnalogValue(127); + } + uBit.sleep(durationMs); + uBit.audio.virtualOutputPin.setAnalogValue(0); + + // Short break between notes + uBit.sleep(10); + } +} + +static void onButtonA(MicroBitEvent) { + DMESG("Button A"); + uBit.audio.soundExpressions.playAsync("spring"); + uBit.display.print(HAPPY); +} + +static void onButtonB(MicroBitEvent) { + DMESG("Button B"); + uBit.audio.soundExpressions.playAsync("sad"); + uBit.display.print(SAD); +} + +static void onButtonAB(MicroBitEvent) { + DMESG("Button A+B"); + + int lightLevel = uBit.display.readLightLevel(); + DMESG("Light level: %d", lightLevel); + // Reset display mode to disable light level reading & avoid LED flicker + uBit.display.setDisplayMode(DisplayMode::DISPLAY_MODE_BLACK_AND_WHITE); + + if (lightLevel > 50) { + uBit.display.print(SUN); + playMelody(MELODY_POWER_UP, TUNE_LEN(MELODY_POWER_UP)); + } else { + uBit.display.print(MOON); + playMelody(MELODY_POWER_DOWN, TUNE_LEN(MELODY_POWER_DOWN)); + } +} + +static void onButtonLogo(MicroBitEvent) { + DMESG("Button Logo"); + + int sampleRate = 11000; + static SplitterChannel *splitterChannel = uBit.audio.splitter->createChannel(); + splitterChannel->requestSampleRate( sampleRate ); + + // Uncomment these two lines and comment out the *recording declaration after them to insert a low-pass-filter. + // static LowPassFilter *lowPassFilter = new LowPassFilter(*splitterChannel, 0.812313f, false); + // static StreamRecording *recording = new StreamRecording(*lowPassFilter); + static StreamRecording *recording = new StreamRecording(*splitterChannel); + + static MixerChannel *channel = uBit.audio.mixer.addChannel(*recording, sampleRate); + + // uBit.audio.processor->setGain(0.08f); // Default gain + // uBit.audio.processor->setGain(0.16f); // Double + + MicroBitAudio::requestActivation(); + channel->setVolume(75.0); + uBit.audio.mixer.setVolume(1023); + + uBit.display.clear(); + uBit.audio.levelSPL->setUnit(LEVEL_DETECTOR_SPL_8BIT); + + recording->recordAsync(); + while (uBit.logo.isPressed() && recording->isRecording()) { + int audioLevel = (int)uBit.audio.levelSPL->getValue(); + DMESG("Audio level: %d", audioLevel); + plotBarGraph(audioLevel, 255); + uBit.sleep(5); + } + // At this point either the logo has been released or the recording is done + recording->stop(); + // Note: The CODAL_STREAM_IDLE_TIMEOUT_MS config has been set in the + // codal.json file to reduce the time it takes for the microphone LED + // to turn off after the recording is done. + // This area is still being tweaked in CODAL and the codal.json config + // should be removed in the future to use the CODAL default. + uBit.display.clear(); + + // If the recording is done but the logo is still pressed we want to + // hold back the playback until the logo has been released + while (uBit.logo.isPressed()); + + recording->play(); + while (recording->isPlaying()) { + uBit.sleep(20); + } + recording->erase(); +} + +static void onShake(MicroBitEvent) { + DMESG("Shake"); + uBit.display.print(SILENT); + uBit.sleep(400); + + // Sound Effect: + // music.createSoundEffect(WaveShape.Sine, 3041, 3923, 59, 255, 500, SoundExpressionEffect.Warble, InterpolationCurve.Linear) + // audio.SoundEffect( + // freq_start=3041, freq_end=3923, + // vol_start=59, vol_end=255, + // duration=500, + // waveform=audio.SoundEffect.WAVEFORM_SINE, + // fx=audio.SoundEffect.FX_WARBLE, + // shape=audio.SoundEffect.SHAPE_LINEAR, + // ) + uBit.audio.soundExpressions.playAsync("002373041050001000392300001023010802050005000000000000000000000000000000"); + + uBit.display.print(SINGING); + uBit.sleep(400); + uBit.display.print(SILENT); +} + +static void onScreenDown(MicroBitEvent) { + DMESG("Display Down"); + + // Sound Effect: + // music.createSoundEffect(WaveShape.Sine, 849, 1, 255, 0, 1000, SoundExpressionEffect.None, InterpolationCurve.Linear) + // audio.SoundEffect( + // freq_start=849, freq_end=1, + // vol_start=255, vol_end=0, + // duration=1000, + // waveform=audio.SoundEffect.WAVEFORM_SINE, + // fx=audio.SoundEffect.FX_NONE, + // shape=audio.SoundEffect.SHAPE_LINEAR, + // ) + uBit.audio.soundExpressions.play("010230849100001000000100000000012800000100240000000000000000000000000000"); + + uBit.display.print(ASLEEP); +} + +static void onStart() { + uBit.audio.soundExpressions.playAsync("hello"); + uBit.display.print(HEART); +} + +void out_of_box_experience() { + uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_AB, MICROBIT_BUTTON_EVT_CLICK, onButtonAB); + uBit.messageBus.listen(MICROBIT_ID_LOGO, MICROBIT_BUTTON_EVT_DOWN, onButtonLogo); + uBit.messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_SHAKE, onShake); + uBit.messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_FACE_DOWN, onScreenDown); + + onStart(); + + //uBit.audio.rawSplitter->status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; + //uBit.audio.splitter->status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; + + while (true) { + uBit.sleep(1000); + } +} diff --git a/source/samples/PowerManagementTest.cpp b/source/samples/PowerManagementTest.cpp index e5c4dd20..cbc3f09b 100644 --- a/source/samples/PowerManagementTest.cpp +++ b/source/samples/PowerManagementTest.cpp @@ -24,10 +24,6 @@ 000,255,255,255,000\n\ 000,255,255,255,000\n"; - static MicroBitImage dc(dc_emoji); - static MicroBitImage usb(usb_emoji); - static MicroBitImage battery(battery_emoji); - void version_test() { @@ -59,7 +55,8 @@ static void power_management_deep_sleep_until_button_b(MicroBitEvent) { DMESG("Entering Deep Sleep, wake on button B."); uBit.io.buttonB.setActiveLo(); - uBit.power.deepSleep(uBit.io.buttonB); + uBit.io.buttonB.wakeOnActive(1); + uBit.power.deepSleep(); DMESG("Leaving Deep Sleep..."); } @@ -68,7 +65,8 @@ static void power_management_deep_sleep_until_P0_high(MicroBitEvent) DMESG("Entering Deep Sleep, on P0 LO->HI"); uBit.io.P0.setPull(PullMode::Down); uBit.io.P0.setActiveHi(); - uBit.power.deepSleep(uBit.io.P0); + uBit.io.P0.wakeOnActive(1); + uBit.power.deepSleep(); } void @@ -118,20 +116,24 @@ usb_connection_test() while(1) { uBit.display.print(" "); - uBit.sleep(100); - DMESG("POWER_CONSUMPTION: %d", uBit.power.getPowerConsumption()); - uBit.sleep(2000); + uBit.sleep(100); + DMESG("POWER_CONSUMPTION: %d", uBit.power.getPowerData().estimatedPowerConsumption); + uBit.sleep(2000); uBit.display.print("*"); - uBit.sleep(100); - DMESG("POWER_CONSUMPTION: %d", uBit.power.getPowerConsumption()); - uBit.sleep(2000); + uBit.sleep(100); + DMESG("POWER_CONSUMPTION: %d", uBit.power.getPowerData().estimatedPowerConsumption); + uBit.sleep(2000); } } void power_source_test() { + MicroBitImage dc(dc_emoji); + MicroBitImage usb(usb_emoji); + MicroBitImage battery(battery_emoji); + while(1) { MicroBitPowerSource p = uBit.power.getPowerSource(); diff --git a/source/samples/RadioTestRx.cpp b/source/samples/RadioTestRx.cpp index b82ff271..15b6ed58 100644 --- a/source/samples/RadioTestRx.cpp +++ b/source/samples/RadioTestRx.cpp @@ -3,7 +3,7 @@ int data_received; -void onData(MicroBitEvent) +static void onData(MicroBitEvent) { PacketBuffer b = uBit.radio.datagram.recv(); @@ -14,7 +14,7 @@ void onData(MicroBitEvent) uBit.display.print("B"); } -void onData2(MicroBitEvent) +static void onData2(MicroBitEvent) { PacketBuffer b = uBit.radio.datagram.recv(); DMESG("RECV"); diff --git a/source/samples/SerialStreamer.cpp b/source/samples/SerialStreamer.cpp index b84a8034..4c3c521b 100644 --- a/source/samples/SerialStreamer.cpp +++ b/source/samples/SerialStreamer.cpp @@ -80,7 +80,7 @@ void SerialStreamer::streamBuffer(ManagedBuffer buffer) int bps = upstream.getFormat(); // If a BINARY mode is requested, simply output all the bytes to the serial port. - if (mode == SERIAL_STREAM_MODE_BINARY) + if( mode == SERIAL_STREAM_MODE_BINARY ) { uint8_t *p = &buffer[0]; uint8_t *end = p + buffer.length(); @@ -90,12 +90,14 @@ void SerialStreamer::streamBuffer(ManagedBuffer buffer) } // if a HEX mode is requested, format using printf, framed by sample size.. - if (mode == SERIAL_STREAM_MODE_HEX || mode == SERIAL_STREAM_MODE_DECIMAL) + if( mode == SERIAL_STREAM_MODE_HEX || mode == SERIAL_STREAM_MODE_DECIMAL ) { uint8_t *d = &buffer[0]; uint8_t *end = d+buffer.length(); uint32_t data; + uint32_t sum = 0; + while(d < end) { data = *d++; @@ -113,19 +115,23 @@ void SerialStreamer::streamBuffer(ManagedBuffer buffer) uBit.serial.printf("%d ", data); CRLF++; + sum += data; - if (CRLF == 16){ - uBit.serial.printf("\n"); + if (CRLF >= 16){ + uBit.serial.putc('\r'); + uBit.serial.putc('\n'); + sum = 0; CRLF = 0; } } - if (CRLF > 0) - uBit.serial.printf("\n"); + if (CRLF > 0) { + uBit.serial.putc( '\r' ); + uBit.serial.putc( '\n' ); + } } - // We're alway hungry, so deschedule ourselves after processing each buffer. - schedule(); + } diff --git a/source/samples/SerialStreamer.h b/source/samples/SerialStreamer.h index 47200748..4426e25d 100644 --- a/source/samples/SerialStreamer.h +++ b/source/samples/SerialStreamer.h @@ -31,7 +31,7 @@ DEALINGS IN THE SOFTWARE. #define SERIAL_STREAM_MODE_BINARY 1 #define SERIAL_STREAM_MODE_DECIMAL 2 -#define SERIAL_STREAM_MODE_HEX 3 +#define SERIAL_STREAM_MODE_HEX 4 class SerialStreamer : public DataSink { diff --git a/source/samples/StreamAPITest.cpp b/source/samples/StreamAPITest.cpp new file mode 100644 index 00000000..8466667e --- /dev/null +++ b/source/samples/StreamAPITest.cpp @@ -0,0 +1,50 @@ +#include "MicroBit.h" +#include "CodalAssert.h" +#include "LevelDetector.h" +#include "LevelDetectorSPL.h" +#include "Tests.h" + +/** + * Note - These tests use CodalAssert.h - so require the following codal.json options + * be enabled: + * CODAL_ENABLE_ASSERT: 1 + * + * To cause the first assertion failure to halt the processor, also include: + * CODAL_ASSERT_PANIC: 1 + */ + +extern MicroBit uBit; + +/** + * Tests if the mic auto activation (and ADC activation) works correctly + */ +void stream_test_mic_activate() { + assert( uBit.audio.isMicrophoneEnabled() == false, "Microphone was enabled on startup?" ); + assert( uBit.audio.mic->output.isFlowing() == false, "isFlowing() should be false on startup." ); + int level = uBit.audio.levelSPL->getValue(); + assert( uBit.audio.isMicrophoneEnabled(), "getValue() failed to turn the MIC on!" ); + assert( uBit.audio.mic->output.isFlowing(), "isFlowing() was not true after mic activation" ); + assert( level > 0, "Detected level appears to be zero? Defective hardware?" ); + assert_pass( NULL ); +} + +void stream_test_getValue_interval() { + uBit.audio.levelSPL->getValue(); // Wake the stream :) + for( int i=0; i<10; i++ ) { + assert( uBit.audio.isMicrophoneEnabled(), "Microphone should still be active" ); + assert( uBit.audio.mic->output.isFlowing(), "isFlowing() should still be true" ); + int level = uBit.audio.levelSPL->getValue(); + assert( level > 0, "Detected level appears to be zero? Defective hardware?" ); + uBit.sleep( CODAL_STREAM_IDLE_TIMEOUT_MS / 2 ); + } + uBit.sleep( CODAL_STREAM_IDLE_TIMEOUT_MS * 2 ); // Ensure we go quiscient + assert( uBit.audio.isMicrophoneEnabled() == false, "Microphone should be shut down after 2 * CODAL_STREAM_IDLE_TIMEOUT_MS" ); + assert( uBit.audio.mic->output.isFlowing() == false, "isFlowing() should be false after 2 * CODAL_STREAM_IDLE_TIMEOUT_MS" ); + assert_pass( NULL ); +} + +void stream_test_all() { + stream_test_mic_activate(); + stream_test_getValue_interval(); + assert_pass( NULL ); +} \ No newline at end of file diff --git a/source/samples/Tests.h b/source/samples/Tests.h index 3e17b95c..828ebadf 100644 --- a/source/samples/Tests.h +++ b/source/samples/Tests.h @@ -22,7 +22,7 @@ void display_test2(); void concurrent_display_test(); void fade_test(); void mems_mic_test(); -void piezo_mic_test(); +void mems_mic_zero_offset_test(); void speaker_test(int plays); void speaker_test2(int plays); void gpio_test(); @@ -38,7 +38,6 @@ void button_blinky_test(); void spirit_level(); void edge_connector_test(); void analog_test(); -void piezo_clap_test(int wait_for_clap = 0); void mems_clap_test(int wait_for_clap = 0); void mems_clap_test_spl(int wait_for_clap = 0); void showSerialNumber(); @@ -48,11 +47,9 @@ void display_radio(); void spirit_level2(); void button_blinky_test2(); int isPiezoMic2(); -int out_of_box_experience(); int hasPassedFactoryTests(); void record_factory_pass(); void display_arrows(); -void factory_radio_transmitter(); void square_wave_test(); void red_power_test(); void green_power_test(); @@ -76,6 +73,7 @@ void mems_mic_drift_test(); void mc_clap_test(); void synthesizer_test(); void version_test(); +void off_test(); void power_consumption_test(); void power_source_test(); void standby_test(); @@ -83,6 +81,8 @@ void sound_emoji_test(); void interactive_off_test(); void deep_sleep_test1(); void deep_sleep_test2(); +void interactive_deep_sleep_test(); +void usb_connection_test(); void sound_emoji_streamer(); void flash_storage_test(); void sound_expression_test(); @@ -93,5 +93,15 @@ void mixer_test2(); void speaker_pin_test(); void say_hello(); void stream_mixer_to_serial(); +void out_of_box_experience_v2(); +void out_of_box_experience(); +void level_meter(); +void init_clap_detect(); +void ble_test(); +void deepsleep_test( int test); +void neopixel_test(); +void stream_test_mic_activate(); +void stream_test_getValue_interval(); +void stream_test_all(); #endif diff --git a/utils/cmake/toolchains/ARM_GCC/toolchain.cmake b/utils/cmake/toolchains/ARM_GCC/toolchain.cmake index eafdfbcf..ad68a6ac 100644 --- a/utils/cmake/toolchains/ARM_GCC/toolchain.cmake +++ b/utils/cmake/toolchains/ARM_GCC/toolchain.cmake @@ -7,6 +7,9 @@ find_program(ARM_NONE_EABI_OBJCOPY arm-none-eabi-objcopy) set(CMAKE_OSX_SYSROOT "/") set(CMAKE_OSX_DEPLOYMENT_TARGET "") +set(CMAKE_SYSTEM_NAME "Generic") +set(CMAKE_SYSTEM_VERSION "2.0.0") + set(CODAL_TOOLCHAIN "ARM_GCC") if(CMAKE_VERSION VERSION_LESS "3.5.0") diff --git a/utils/python/codal_utils.py b/utils/python/codal_utils.py index 68cb017c..fb432e6d 100644 --- a/utils/python/codal_utils.py +++ b/utils/python/codal_utils.py @@ -8,19 +8,26 @@ import os, re, json, xml.etree.ElementTree from optparse import OptionParser +import subprocess def system(cmd): if os.system(cmd) != 0: sys.exit(1) -def build(clean, verbose = False): +def build(clean, verbose = False, parallelism = 10): if platform.system() == "Windows": # configure system("cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G \"Ninja\"") + if clean: + system("ninja clean") + # build - system("ninja") + if verbose: + system("ninja -j {} --verbose".format(parallelism)) + else: + system("ninja -j {}".format(parallelism)) else: # configure system("cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G \"Unix Makefiles\"") @@ -30,9 +37,9 @@ def build(clean, verbose = False): # build if verbose: - system("make -j 10 VERBOSE=1") + system("make -j {} VERBOSE=1".format(parallelism)) else: - system("make -j 10") + system("make -j {}".format(parallelism)) def read_json(fn): json_file = "" @@ -52,12 +59,16 @@ def read_config(): target = read_json("libraries/" + targetdir + "/target.json") return (codal, targetdir, target) -def update(allow_detached=False): +def update(allow_detached=False, sync_dev=False): (codal, targetdir, target) = read_config() dirname = os.getcwd() for ln in target['libraries']: os.chdir(dirname + "/libraries/" + ln['name']) - system("git checkout " + ln['branch']) + if sync_dev: + default_branch = list(filter( lambda v: v.strip().startswith('HEAD'), str(subprocess.check_output( ["git", "remote", "show", "origin"] ), "utf8").splitlines()))[0].split(":")[1].strip() + system("git checkout " + default_branch) + else: + system("git checkout " + ln['branch']) system("git pull") os.chdir(dirname + "/libraries/" + targetdir) if ("HEAD detached" in os.popen('git branch').read().strip() and @@ -74,22 +85,41 @@ def revision(rev): os.chdir(dirname) update(True) -def printstatus(): +def printstatus( logLines = 3, detail = False ): print("\n***%s" % os.getcwd()) - system("git status -s") - system("git rev-parse HEAD") - system("git branch") - -def status(): + branch = str(subprocess.check_output( [ "git", "branch", "--show-current"] ), "utf8").strip() + hash = str(subprocess.check_output( [ "git", "rev-parse", "HEAD" ] ), "utf8").strip() + tag = "..." + try: + tag = str(subprocess.check_output( [ "git", "describe", "--tags", "--abbrev=0" ], stderr=subprocess.STDOUT ), "utf8").strip() + except subprocess.CalledProcessError as e: + tag = "~none~" + + print( "Branch: {branch}, Nearest Tag: {tag} ({hash})".format(branch=branch, tag=tag, hash=hash) ) + if detail: + system( "git --no-pager log -n {} --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit".format(logLines) ) + print( "" ) + + system("git status -sb") + print( "" ) + + +def status( logLines = 3, detail = True, libs = [] ): (codal, targetdir, target) = read_config() dirname = os.getcwd() - for ln in target['libraries']: - os.chdir(dirname + "/libraries/" + ln['name']) - printstatus() - os.chdir(dirname + "/libraries/" + targetdir) - printstatus() - os.chdir(dirname) - printstatus() + + if len(libs) == 0: + for ln in target['libraries']: + os.chdir(dirname + "/libraries/" + ln['name']) + printstatus( logLines, detail ) + os.chdir(dirname + "/libraries/" + targetdir) + printstatus( logLines, detail ) + os.chdir(dirname) + printstatus( logLines, detail ) + else: + for lib in libs: + os.chdir(dirname + "/libraries/" + lib) + printstatus( logLines, detail ) def get_next_version(options): if options.version: From 189a2cfa2429bef7d56174461b9fcb3e53fcf88b Mon Sep 17 00:00:00 2001 From: AshrafIbrahim03 Date: Sat, 26 Aug 2023 11:17:26 -0400 Subject: [PATCH 2/2] Corrected some import misspellings --- source/Finch.cpp | 2 +- source/Hummingbird.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Finch.cpp b/source/Finch.cpp index 911ca7ab..de62e1d7 100644 --- a/source/Finch.cpp +++ b/source/Finch.cpp @@ -1,6 +1,6 @@ #include "MicroBit.h" #include "BirdBrain.h" -#include "SPIControl.h" +#include "SpiControl.h" #include "BBMicroBit.h" #include "Finch.h" #include "BLESerial.h" diff --git a/source/Hummingbird.cpp b/source/Hummingbird.cpp index ea059626..bacf3ea7 100644 --- a/source/Hummingbird.cpp +++ b/source/Hummingbird.cpp @@ -1,6 +1,6 @@ #include "MicroBit.h" #include "BirdBrain.h" -#include "SPIControl.h" +#include "SpiControl.h" #include "BBMicroBit.h" #include "Hummingbird.h" #include "BLESerial.h"