├── .clang-format ├── .github └── workflows │ ├── build.yml │ └── docker-image.yml ├── .gitignore ├── .vscode ├── extensions.json └── launch.json ├── .yotta_ignore ├── AUTHORS ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── README.md ├── build.py ├── codal.ble.json ├── codal.json ├── module.json ├── source ├── helpers.cpp ├── helpers.h ├── link.cpp ├── link.h ├── main.cpp ├── main.cpp.old ├── radio.cpp ├── radio.h ├── samples │ ├── AccelerometerTest.cpp │ ├── AudioTest.cpp │ ├── BLETest.cpp │ ├── BlinkyTest.cpp │ ├── ButtonTest.cpp │ ├── CapTouchTest.cpp │ ├── DeepSleepTest.cpp │ ├── DisplayTest.cpp │ ├── GPIOTest.cpp │ ├── LightLevelTestRaw.cpp │ ├── MicrophoneTest.cpp │ ├── NoiseProfiler.cpp │ ├── NoiseProfiler.h │ ├── OOB.cpp │ ├── PowerManagementTest.cpp │ ├── README.md │ ├── RadioTestRx.cpp │ ├── SerialNumber.cpp │ ├── SerialStreamer.cpp │ ├── SerialStreamer.h │ ├── SpeakerTest.cpp │ ├── TemperatureTest.cpp │ ├── Tests.h │ └── USBFlashTest.cpp ├── sequence.cpp ├── sequence.h ├── timer.cpp └── timer.h └── utils ├── __init__.py ├── cmake ├── JSONParser.cmake ├── buildtools │ ├── codal.cmake │ └── yotta.cmake ├── colours.cmake ├── toolchains │ ├── ARM_GCC │ │ ├── bin-generator.cmake │ │ ├── compiler-flags.cmake │ │ ├── hex-generator.cmake │ │ ├── platform_includes.h │ │ └── toolchain.cmake │ ├── AVR_GCC │ │ ├── bin-generator.cmake │ │ ├── compiler-flags.cmake │ │ ├── hex-generator.cmake │ │ ├── platform_includes.h │ │ └── toolchain.cmake │ └── XTENSA_GCC │ │ ├── bin-generator.cmake │ │ ├── compiler-flags.cmake │ │ ├── hex-generator.cmake │ │ ├── platform_includes.h │ │ └── toolchain.cmake └── util.cmake ├── debug ├── dmesg.js └── meminfo.js ├── esptool.py ├── generate_libraries.py ├── merge_hex.py ├── python ├── __init__.py ├── codal_utils.py └── doc_gen │ ├── __init__.py │ ├── doc_gen.py │ ├── doxygen_extractor.py │ ├── md_converter.py │ └── system_utils.py ├── targets.json └── uf2conv.py /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 4 3 | UseTab: Never 4 | ColumnLimit: 100 5 | BreakBeforeBraces: Allman 6 | AccessModifierOffset: -4 7 | AllowShortFunctionsOnASingleLine: Inline 8 | SortIncludes: false 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Natively 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build-py-script: 11 | strategy: 12 | matrix: 13 | os: [ubuntu-18.04, macos-latest, windows-2016] 14 | gcc: ['7-2017-q4', 'latest'] 15 | cmake: ['3.6.0', '3.21.3'] 16 | fail-fast: false 17 | runs-on: ${{ matrix.os }} 18 | name: ${{ matrix.os }}, gcc ${{ matrix.gcc }}, cmake ${{ matrix.cmake || 'latest'}} 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Setup Python 22 | uses: actions/setup-python@v2 23 | with: 24 | python-version: '3.8' 25 | - name: Setup arm-none-eabi-gcc ${{ matrix.gcc }} 26 | uses: carlosperate/arm-none-eabi-gcc-action@v1 27 | with: 28 | release: ${{ matrix.gcc }} 29 | - name: Setup CMake ${{ matrix.cmake }} 30 | uses: jwlawson/actions-setup-cmake@v1 31 | with: 32 | cmake-version: ${{ matrix.cmake }} 33 | - name: Install Ninja via PyPI 34 | run: python -m pip install ninja 35 | - name: Check Versions 36 | run: | 37 | arm-none-eabi-gcc --version 38 | cmake --version 39 | ninja --version 40 | python --version 41 | - name: Build using build.py 42 | run: python build.py 43 | - name: Upload hex file 44 | uses: actions/upload-artifact@v1 45 | with: 46 | name: build-py-${{ matrix.os }} 47 | path: MICROBIT.hex 48 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Build via Docker 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Build using the Docker image 16 | env: 17 | DOCKER_BUILDKIT: 1 18 | run: docker build -t microbit-tools --output type=local,dest=out . 19 | - name: Directory Listing 20 | run: ls -al 21 | - name: Upload hex file 22 | uses: actions/upload-artifact@v1 23 | with: 24 | name: Export from Docker 25 | path: out/MICROBIT.hex 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | libraries 3 | .yotta.json 4 | yotta_modules 5 | yotta_targets 6 | *.swp 7 | *~ 8 | Makefile 9 | *.hex 10 | *.DS_Store 11 | .vscode 12 | *.uf2 13 | *.bin 14 | pxtapp 15 | buildcache.json 16 | *.pyc 17 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "marus25.cortex-debug" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "micro:bit PyOCD Cortex Debug", 5 | "cwd": "${workspaceFolder}", 6 | "executable": "build/MICROBIT", 7 | "request": "launch", 8 | "type": "cortex-debug", 9 | "servertype": "pyocd", 10 | "interface": "swd", 11 | "device": "nrf52", 12 | "targetId": "nrf52", 13 | "svdFile": "libraries/codal-nrf52/nrfx/mdk/nrf52833.svd", 14 | "preLaunchCommands": [ 15 | "load build/MICROBIT", 16 | "enable breakpoint", 17 | "monitor reset" 18 | ] 19 | }, 20 | 21 | { 22 | "name": "micro:bit OpenOCD Cortex Debug", 23 | "cwd": "${workspaceFolder}", 24 | "executable": "build/MICROBIT", 25 | "request": "launch", 26 | "type": "cortex-debug", 27 | "servertype": "openocd", 28 | "configFiles": [ 29 | "interface/cmsis-dap.cfg", 30 | "target/nrf52.cfg" 31 | ], 32 | "interface": "swd", 33 | "preLaunchCommands": [ 34 | "load build/MICROBIT", 35 | "enable breakpoint", 36 | "monitor reset" 37 | ] 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /.yotta_ignore: -------------------------------------------------------------------------------- 1 | # build.py uses CMake as well and this top level file is not Yotta compatible 2 | CMakeLists.txt 3 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Joe Finney (@finneyj) 2 | James Devine (@jamesadevine) 3 | Martin Wiliams (@martinwork) 4 | Michał Moskal (@mmoskal) 5 | Raphael Gault (@raphaelgault) 6 | Sam Kent (@microbit-sam) 7 | Jonny Auston (@jaustin) 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 as builder 2 | 3 | RUN apt-get update -qq && \ 4 | apt-get install -y --no-install-recommends \ 5 | software-properties-common && \ 6 | add-apt-repository -y ppa:team-gcc-arm-embedded/ppa && \ 7 | apt-get update -qq && \ 8 | apt-get install -y --no-install-recommends \ 9 | git make cmake python3 \ 10 | gcc-arm-embedded && \ 11 | apt-get autoremove -y && \ 12 | apt-get clean -y && \ 13 | rm -rf /var/lib/apt/lists/* 14 | 15 | # Project sources volume should be mounted at /app 16 | COPY . /opt/microbit-samples 17 | WORKDIR /opt/microbit-samples 18 | 19 | RUN python3 build.py 20 | 21 | FROM scratch AS export-stage 22 | COPY --from=builder /opt/microbit-samples/MICROBIT.bin . 23 | COPY --from=builder /opt/microbit-samples/MICROBIT.hex . 24 | 25 | ENTRYPOINT ["/bin/bash"] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Lancaster University 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Btlejack firmware for Micro:Bit v2 (for now) 2 | 3 | **This is a work in progress, stay tuned** 4 | 5 | ## Raising Issues 6 | 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. 7 | 8 | # Installation 9 | 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. 10 | 11 | - [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) 12 | - [Github desktop](https://desktop.github.com/) 13 | - [CMake](https://cmake.org/download/) 14 | - [Python 3](https://www.python.org/downloads/) 15 | 16 | We use Ubuntu Linux for most of our tests. You can also install these tools easily through the package manager: 17 | 18 | ``` 19 | sudo apt install gcc 20 | sudo apt install git 21 | sudo apt install cmake 22 | sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi 23 | ``` 24 | 25 | ## Yotta 26 | For backwards compatibility with [microbit-samples](https://github.com/lancaster-university/microbit-samples) users, we also provide a yotta target for this repository. 27 | 28 | ## Docker 29 | 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. 30 | 31 | 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: 32 | 33 | ``` 34 | docker build -t microbit-tools --output out . 35 | ``` 36 | 37 | To omit the final output stage (for CI, for example) run without the `--output` arguments: 38 | 39 | ``` 40 | docker build -t microbit-tools . 41 | ``` 42 | 43 | # Building 44 | - Clone this repository 45 | - In the root of this repository type `python build.py` 46 | - The hex file will be built `MICROBIT.HEX` and placed in the root folder. 47 | 48 | # Developing 49 | 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. 50 | 51 | The `samples` folder contains a number of simple sample programs that utilise you may find useful. 52 | 53 | # Debugging 54 | 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: 55 | 56 | 1. Install either [OpenOCD](http://openocd.org) or [PyOCD](https://github.com/pyocd/pyOCD). 57 | 2. Install the `marus25.cortex-debug` VS Code extension. 58 | 3. Build your program. 59 | 4. Click the Run and Debug option in the toolbar. 60 | 5. Two debugging options are provided: one for OpenOCD, and one for PyOCD. Select the correct one depending on the debugger you installed. 61 | 62 | 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. 63 | 64 | # Compatibility 65 | 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. 66 | 67 | # Documentation 68 | API documentation is embedded in the code using doxygen. We will produce integrated web-based documentation soon. 69 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # The MIT License (MIT) 4 | 5 | # Copyright (c) 2017 Lancaster University. 6 | 7 | # Permission is hereby granted, free of charge, to any person obtaining a 8 | # copy of this software and associated documentation files (the "Software"), 9 | # to deal in the Software without restriction, including without limitation 10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | # and/or sell copies of the Software, and to permit persons to whom the 12 | # Software is furnished to do so, subject to the following conditions: 13 | 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | # DEALINGS IN THE SOFTWARE. 24 | 25 | import os 26 | import sys 27 | import optparse 28 | import platform 29 | import json 30 | import shutil 31 | import re 32 | from utils.python.codal_utils import system, build, read_json, checkgit, read_config, update, revision, printstatus, status, get_next_version, lock, delete_build_folder, generate_docs 33 | 34 | parser = optparse.OptionParser(usage="usage: %prog target-name-or-url [options]", description="This script manages the build system for a codal device. Passing a target-name generates a codal.json for that devices, to list all devices available specify the target-name as 'ls'.") 35 | parser.add_option('-c', '--clean', dest='clean', action="store_true", help='Whether to clean before building. Applicable only to unix based builds.', default=False) 36 | parser.add_option('-t', '--test-platforms', dest='test_platform', action="store_true", help='Specify whether the target platform is a test platform or not.', default=False) 37 | parser.add_option('-l', '--lock', dest='lock_target', action="store_true", help='Create target-lock.json, updating patch version', default=False) 38 | parser.add_option('-b', '--branch', dest='branch', action="store_true", help='With -l, use vX.X.X-BRANCH.Y', default=False) 39 | parser.add_option('-m', '--minor', dest='update_minor', action="store_true", help='With -l, update minor version', default=False) 40 | parser.add_option('-M', '--major', dest='update_major', action="store_true", help='With -l, update major version', default=False) 41 | parser.add_option('-V', '--version', dest='version', metavar="VERSION", help='With -l, set the version; use "-V v0.0.1" to bootstrap', default=False) 42 | parser.add_option('-u', '--update', dest='update', action="store_true", help='git pull target and libraries', default=False) 43 | parser.add_option('-s', '--status', dest='status', action="store_true", help='git status target and libraries', default=False) 44 | parser.add_option('-r', '--revision', dest='revision', action="store", help='Checkout a specific revision of the target', default=False) 45 | parser.add_option('-d', '--dev', dest='dev', action="store_true", help='enable developer mode (does not use target-locked.json)', default=False) 46 | parser.add_option('-g', '--generate-docs', dest='generate_docs', action="store_true", help='generate documentation for the current target', default=False) 47 | 48 | (options, args) = parser.parse_args() 49 | 50 | if not os.path.exists("build"): 51 | os.mkdir("build") 52 | 53 | if options.lock_target: 54 | lock(options) 55 | exit(0) 56 | 57 | if options.update: 58 | update() 59 | exit(0) 60 | 61 | if options.status: 62 | status() 63 | exit(0) 64 | 65 | if options.revision: 66 | revision(options.revision) 67 | exit(0) 68 | 69 | # out of source build! 70 | os.chdir("build") 71 | 72 | test_json = read_json("../utils/targets.json") 73 | 74 | # configure the target a user has specified: 75 | if len(args) == 1: 76 | 77 | target_name = args[0] 78 | target_config = None 79 | 80 | # list all targets 81 | if target_name == "ls": 82 | for json_obj in test_json: 83 | s = "%s: %s" % (json_obj["name"], json_obj["info"]) 84 | if "device_url" in json_obj.keys(): 85 | s += "(%s)" % json_obj["device_url"] 86 | print(s) 87 | exit(0) 88 | 89 | # cycle through out targets and check for a match 90 | for json_obj in test_json: 91 | if json_obj["name"] != target_name: 92 | continue 93 | 94 | del json_obj["device_url"] 95 | del json_obj["info"] 96 | 97 | target_config = json_obj 98 | break 99 | 100 | if target_config == None and target_name.startswith("http"): 101 | target_config = { 102 | "name": re.sub("^.*/", "", target_name), 103 | "url": target_name, 104 | "branch": "master", 105 | "type": "git" 106 | } 107 | 108 | if target_config == None: 109 | print("'" + target_name + "'" + " is not a valid target.") 110 | exit(1) 111 | 112 | # developer mode is for users who wish to contribute, it will clone and checkout commitable branches. 113 | if options.dev: 114 | target_config["dev"] = True 115 | 116 | config = { 117 | "target":target_config 118 | } 119 | 120 | with open("../codal.json", 'w') as codal_json: 121 | json.dump(config, codal_json, indent=4) 122 | 123 | # remove the build folder, a user could be swapping targets. 124 | delete_build_folder() 125 | 126 | 127 | elif len(args) > 1: 128 | print("Too many arguments supplied, only one target can be specified.") 129 | exit(1) 130 | 131 | if not options.test_platform: 132 | 133 | if not os.path.exists("../codal.json"): 134 | print("No target specified in codal.json, does codal.json exist?") 135 | exit(1) 136 | 137 | if options.generate_docs: 138 | generate_docs() 139 | exit(0) 140 | 141 | build(options.clean) 142 | exit(0) 143 | 144 | for json_obj in test_json: 145 | 146 | # some platforms aren't supported by travis, ignore them when testing. 147 | if "test_ignore" in json_obj: 148 | print("ignoring: " + json_obj["name"]) 149 | continue 150 | 151 | # ensure we have a clean build tree. 152 | delete_build_folder() 153 | 154 | # clean libs 155 | if os.path.exists("../libraries"): 156 | shutil.rmtree('../libraries') 157 | 158 | # configure the target and tests... 159 | config = { 160 | "target":json_obj, 161 | "output":".", 162 | "application":"libraries/"+json_obj["name"]+"/tests/" 163 | } 164 | 165 | with open("../codal.json", 'w') as codal_json: 166 | json.dump(config, codal_json, indent=4) 167 | 168 | build(True, True) 169 | -------------------------------------------------------------------------------- /codal.ble.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": { 3 | "name": "codal-microbit-v2", 4 | "url": "https://github.com/lancaster-university/codal-microbit-v2", 5 | "branch": "master", 6 | "type": "git", 7 | "test_ignore": true, 8 | "dev": true 9 | } , 10 | "config":{ 11 | "SOFTDEVICE_PRESENT": 1, 12 | "DEVICE_BLE": 1, 13 | "MICROBIT_BLE_ENABLED" : 1, 14 | "MICROBIT_BLE_PAIRING_MODE": 1, 15 | "MICROBIT_BLE_DFU_SERVICE": 1, 16 | "MICROBIT_BLE_DEVICE_INFORMATION_SERVICE": 1, 17 | "MICROBIT_BLE_EVENT_SERVICE" : 1, 18 | "MICROBIT_BLE_PARTIAL_FLASHING" : 0, 19 | "MICROBIT_BLE_SECURITY_LEVEL": "SECURITY_MODE_ENCRYPTION_NO_MITM" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /codal.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": { 3 | "name": "codal-microbit-v2", 4 | "url": "https://github.com/virtualabs/codal-microbit-v2", 5 | "branch": "master", 6 | "type": "git", 7 | "test_ignore": true, 8 | "dev": true 9 | } , 10 | "config":{ 11 | "NO_BLE": 1, 12 | "MICROBIT_BLE_ENABLED" : 0, 13 | "MICROBIT_BLE_PAIRING_MODE": 0 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codal", 3 | "version": "0.0.1", 4 | "description": "Component Oriented Device Abstraction Layer (CODAL) - root", 5 | "license": "MIT", 6 | "dependencies": { 7 | "codal-microbit": "git@github.com:virtualabs/codal-microbit-v2.git#master" 8 | }, 9 | "targetDependencies": {}, 10 | "extraIncludes": [ 11 | "yotta_modules/" 12 | ], 13 | "bin": "./source", 14 | "scripts": {} 15 | } 16 | -------------------------------------------------------------------------------- /source/helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | 3 | /** 4 | * BTLE CRC reverse routine, originally written by Mike Ryan, 5 | * Dominic Spill and Michael Ossmann, taken from ubertooth_le. 6 | **/ 7 | 8 | uint32_t btle_reverse_crc(uint32_t crc, uint8_t *data, int len) 9 | { 10 | uint32_t state = crc; 11 | uint32_t lfsr_mask = 0xb4c000; 12 | uint32_t ret; 13 | uint8_t cur; 14 | int i, j, top_bit; 15 | 16 | for (i = len - 1; i >= 0; --i) { 17 | cur = data[i]; 18 | for (j = 0; j < 8; ++j) { 19 | top_bit = state >> 23; 20 | state = (state << 1) & 0xffffff; 21 | state |= top_bit ^ ((cur >> (7 - j)) & 1); 22 | if (top_bit) 23 | state ^= lfsr_mask; 24 | } 25 | } 26 | 27 | ret = 0; 28 | for (i = 0; i < 24; ++i) 29 | ret |= ((state >> i) & 1) << (23 - i); 30 | 31 | return ret; 32 | } 33 | 34 | 35 | /** 36 | * swap_bits 37 | * 38 | * Swap every bit of a byte. 39 | **/ 40 | 41 | uint8_t swap_bits(uint8_t b) 42 | { 43 | uint8_t o = 0; 44 | int i =0; 45 | 46 | for (i=0; i<8; i++) 47 | { 48 | o = o << 1; 49 | o |= (b&(1<=0; j--) 71 | { 72 | if (lfsr & 0x80) 73 | { 74 | lfsr ^= 0x11; 75 | c ^= (1<>24; 98 | b = (aa & 0x00ff0000)>>16; 99 | c = (aa & 0x0000ff00)>>8; 100 | d = (aa & 0x000000ff); 101 | if ((a==b) && (b==c) && (c==d)) 102 | return 0; 103 | 104 | /* Not the advertising access address. */ 105 | if (aa == 0x8E89BED6) 106 | return 0; 107 | 108 | /* Check consecutive bits. */ 109 | bb = aa; 110 | for (i=0; i<26; i++) 111 | { 112 | if (((bb&0x3F) == 0) || ((bb&0x3F)==0x3F)) 113 | return 0; 114 | bb >>= 1; 115 | } 116 | 117 | /* Check transitions. */ 118 | bb = aa; 119 | t = 0; 120 | a = (bb & 0x80000000)>>31; 121 | for (i=30; i>=0; i--) 122 | { 123 | if (((bb & (1<>i) != a) 124 | { 125 | a = ((bb & (1<>i); 126 | t++; 127 | if (t>24) 128 | return 0; 129 | } 130 | if ((i < 26) && (t<2)) 131 | return 0; 132 | } 133 | 134 | return 1; 135 | } 136 | 137 | 138 | /** 139 | * chm_to_array() 140 | * 141 | * Convert a 5-byte channel map into a 37-byte array. 142 | **/ 143 | 144 | void chm_to_array(uint8_t *chm, uint8_t *chmArray) 145 | { 146 | int i,j; 147 | 148 | for (i=0; i<5; i++) 149 | { 150 | for (j=0; j<8; j++) 151 | { 152 | if ((8*i + j) < 37) 153 | { 154 | if (chm[i] & (1<serial; 8 | m_bit = ubit; 9 | 10 | /* Upgrade the default tx buffer. */ 11 | #if defined(YOTTA_CFG_BAUD) 12 | m_serial->baud(YOTTA_CFG_BAUD); 13 | #else 14 | m_serial->setBaudrate(115200); 15 | #endif 16 | m_serial->setTxBufferSize(254); 17 | m_serial->setRxBufferSize(254); 18 | 19 | /* Clear RX and TX. */ 20 | m_serial->clearRxBuffer(); 21 | m_serial->clearTxBuffer(); 22 | 23 | /* Current status: waiting. */ 24 | m_status = LK_WAITING; 25 | m_nbRecvBytes = 0; 26 | } 27 | 28 | uint8_t Link::crc(uint8_t *pData, int size, uint8_t prevCrc) 29 | { 30 | 31 | for (int i=0; iisReadable()) 51 | { 52 | nbBytesRead = (uint8_t)m_serial->read(&m_payload[m_nbRecvBytes], 1); 53 | if (nbBytesRead != MICROBIT_SERIAL_IN_USE) 54 | m_nbRecvBytes += nbBytesRead; 55 | } 56 | 57 | if (nbBytesRead > 0) 58 | { 59 | /* Packet must start with 0xBC. */ 60 | if ((m_payload[0] == 0xBC)) 61 | { 62 | if (m_nbRecvBytes>4) 63 | { 64 | /* Parse packet. */ 65 | pktSize = m_payload[2] | (m_payload[3]<<8); 66 | if (m_nbRecvBytes >= (pktSize + 5)) 67 | { 68 | /* Check crc. */ 69 | checksum = crc(m_payload, pktSize + 4); 70 | if (checksum == m_payload[pktSize+4]) 71 | { 72 | /* Fill data. */ 73 | *ptOperation = (T_OPERATION)(m_payload[1] & 0x0F); 74 | *pubFlags = (m_payload[1]>>4); 75 | 76 | /* Copy data. */ 77 | if (*pnCount < pktSize) 78 | dataSize = *pnCount; 79 | else 80 | dataSize = pktSize; 81 | *pnCount = dataSize; 82 | 83 | for (i=0; i> 8); 121 | 122 | /* Compute checksum. */ 123 | for (i=0; i<4; i++) 124 | checksum ^= header[i]; 125 | 126 | /* Send header first. */ 127 | m_serial->send(header, 4, ASYNC); 128 | 129 | /* Send payload next. */ 130 | for (i=0; i 0) 135 | m_serial->send(pData, nCount, ASYNC); 136 | 137 | /* Send checksum. */ 138 | m_serial->send(&checksum, 1, ASYNC); 139 | 140 | return true; 141 | } 142 | 143 | 144 | bool Link::sendNotification(T_NOTIFICATION_TYPE tNotification, uint8_t *pData, int nCount) 145 | { 146 | return sendPacket((T_OPERATION)tNotification, pData, nCount, PKT_NOTIFICATION); 147 | } 148 | 149 | 150 | bool Link::debug(uint8_t *pData) 151 | { 152 | /* Send debug message. */ 153 | return sendPacket(DEBUG, pData, strlen((char *)pData), PKT_RESPONSE); 154 | } 155 | 156 | bool Link::verbose(uint8_t *pData) 157 | { 158 | /* Send debug message. */ 159 | return sendPacket(VERBOSE, pData, strlen((char *)pData), PKT_RESPONSE); 160 | } 161 | 162 | bool Link::version(uint8_t major, uint8_t minor) 163 | { 164 | uint8_t buffer[2]; 165 | 166 | /* Set major and minor. */ 167 | buffer[0] = major; 168 | buffer[1] = minor; 169 | 170 | /* Send version. */ 171 | return sendPacket(VERSION, buffer, 2, PKT_RESPONSE); 172 | } 173 | 174 | 175 | bool Link::notifyAccessAddress(uint32_t accessAddress, int channel, uint8_t rssi) 176 | { 177 | uint8_t buffer[6]; 178 | uint32_t *paa = (uint32_t *)&buffer[2]; 179 | 180 | /* Fill in the buffer. */ 181 | buffer[0] = channel; 182 | buffer[1] = rssi; 183 | *paa = accessAddress; 184 | 185 | /* Send packet. */ 186 | return sendNotification(N_ACCESS_ADDRESS, buffer, 6); 187 | } 188 | 189 | bool Link::notifyCrc(uint32_t accessAddress, uint32_t crc) 190 | { 191 | uint8_t buffer[8]; 192 | uint32_t *paa = (uint32_t *)&buffer[0]; 193 | uint32_t *pcrc = (uint32_t *)&buffer[4]; 194 | 195 | /* Fill in the buffer. */ 196 | *paa = accessAddress; 197 | *pcrc = crc; 198 | 199 | /* Send packet. */ 200 | return sendNotification(N_CRC, buffer, 8); 201 | } 202 | 203 | bool Link::notifyChannelMap(uint32_t accessAddress, uint8_t *chm) 204 | { 205 | uint8_t buffer[9]; 206 | uint32_t *paa = (uint32_t *)&buffer[0]; 207 | 208 | /* Fill in the buffer. */ 209 | *paa = accessAddress; 210 | array_to_chm(chm, &buffer[4]); 211 | 212 | /* Send packet. */ 213 | return sendNotification(N_CHANNEL_MAP, buffer, 9); 214 | } 215 | 216 | bool Link::notifyHopInterval(uint32_t accessAddress, uint16_t hopInterval) 217 | { 218 | uint8_t buffer[6]; 219 | uint32_t *paa = (uint32_t *)&buffer[0]; 220 | uint16_t *phi = (uint16_t *)&buffer[4]; 221 | 222 | *paa = accessAddress; 223 | *phi = hopInterval; 224 | 225 | /* Send packet. */ 226 | return sendNotification(N_HOP_INTERVAL, buffer, 6); 227 | } 228 | 229 | bool Link::notifyHopIncrement(uint32_t accessAddress, uint8_t hopIncrement) 230 | { 231 | uint8_t buffer[5]; 232 | uint32_t *paa = (uint32_t *)&buffer[0]; 233 | 234 | *paa = accessAddress; 235 | buffer[4] = hopIncrement; 236 | 237 | /* Send packet. */ 238 | return sendNotification(N_HOP_INCREMENT, buffer, 5); 239 | } 240 | 241 | bool Link::notifyConnectionPacket(uint8_t *pPacket, int nPacketSize) 242 | { 243 | return sendNotification(N_CONNECT_REQ, pPacket, nPacketSize); 244 | } 245 | 246 | bool Link::notifyHijackStatus(uint8_t status) 247 | { 248 | uint8_t buffer[1]; 249 | 250 | /* Write status into buffer. */ 251 | buffer[0] = status; 252 | 253 | /* Send packet. */ 254 | return sendNotification(N_HIJACK_STATUS, buffer, 1); 255 | } 256 | 257 | 258 | bool Link::notifyBlePacket(uint8_t *pPacket, int nPacketSize) 259 | { 260 | /* Send notification. */ 261 | return sendNotification(N_PACKET, pPacket, nPacketSize); 262 | } 263 | 264 | bool Link::notifyNordicTapBlePacket( 265 | uint8_t *pPacket, 266 | int nPacketSize, 267 | uint8_t channel, 268 | uint8_t rssi, 269 | uint8_t direction, 270 | uint32_t delta, 271 | uint16_t eventCounter) 272 | { 273 | int i; 274 | 275 | /* Format nordic_tap header */ 276 | m_nordic_tap[0] = nPacketSize; 277 | m_nordic_tap[1] = (direction == 0)?3:1; 278 | m_nordic_tap[2] = channel; 279 | m_nordic_tap[3] = rssi; 280 | m_nordic_tap[4] = (eventCounter & 0xFF); 281 | m_nordic_tap[5] = (eventCounter & 0xFF00) >> 8; 282 | m_nordic_tap[6] = (delta & 0xff); 283 | m_nordic_tap[7] = (delta & 0xff00) >> 8; 284 | m_nordic_tap[8] = (delta & 0xff0000) >> 16; 285 | m_nordic_tap[9] = (delta & 0xff000000) >> 24; 286 | 287 | for (i=0; i 200) v++; 43 | if ( g > 500) v++; 44 | 45 | return v; 46 | } 47 | 48 | void 49 | spirit_level2() 50 | { 51 | DMESG("SPIRIT_LEVEL_2"); 52 | 53 | int ox=0; 54 | int oy=0; 55 | int moves = 0; 56 | 57 | while(moves < 15) 58 | { 59 | int x = uBit.accelerometer.getX(); 60 | int y = uBit.accelerometer.getY(); 61 | int z = uBit.accelerometer.getZ(); 62 | 63 | DMESG("Acc [X:%d][Y:%d][Z:%d]\r\n", x, y, z); 64 | 65 | int px = g_to_pix(x); 66 | int py = g_to_pix(y); 67 | 68 | if (ox != px || oy != py) 69 | moves++; 70 | 71 | ox = px; 72 | oy = py; 73 | 74 | uBit.display.image.clear(); 75 | uBit.display.image.setPixelValue(px,py,255); 76 | 77 | uBit.sleep(100); 78 | } 79 | 80 | uBit.display.clear(); 81 | } 82 | 83 | void 84 | spirit_level() 85 | { 86 | while(1) 87 | { 88 | int x = uBit.accelerometer.getX(); 89 | int y = uBit.accelerometer.getY(); 90 | int z = uBit.accelerometer.getZ(); 91 | 92 | DMESG("Acc [X:%d][Y:%d][Z:%d]", x, y, z); 93 | 94 | int px = g_to_pix(x); 95 | int py = g_to_pix(y); 96 | 97 | uBit.display.image.clear(); 98 | uBit.display.image.setPixelValue(px,py,255); 99 | 100 | uBit.sleep(100); 101 | } 102 | } 103 | 104 | void 105 | compass_test1() 106 | { 107 | while(1) 108 | { 109 | DMESG("Mag [X:%d][Y:%d][Z:%d]", uBit.compass.getX(), uBit.compass.getY(), uBit.compass.getZ()); 110 | uBit.sleep(1000); 111 | } 112 | } 113 | 114 | void 115 | compass_test2() 116 | { 117 | while(1) 118 | { 119 | DMESG("Heading [%d]", uBit.compass.heading()); 120 | uBit.sleep(1000); 121 | } 122 | } 123 | 124 | void 125 | compass_accelerometer_test() 126 | { 127 | while(1) 128 | { 129 | DMESG("ACC [X:%d][Y:%d][Z:%d]\n", uBit.accelerometer.getX(), uBit.accelerometer.getY(), uBit.accelerometer.getZ()); 130 | DMESG("MAG [X:%d][Y:%d][Z:%d]\n", uBit.compass.getX(), uBit.compass.getY(), uBit.compass.getZ()); 131 | 132 | uBit.sleep(1000); 133 | } 134 | } 135 | 136 | void 137 | shake_test() 138 | { 139 | //uBit.messageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, onAccelerometerData); 140 | //uBit.messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, onCompassData); 141 | uBit.messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_SHAKE, onShake); 142 | 143 | while(1) 144 | { 145 | uBit.sleep(10000); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /source/samples/AudioTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | enum Note { 5 | C = 262, 6 | CSharp = 277, 7 | D = 294, 8 | Eb = 311, 9 | E = 330, 10 | F = 349, 11 | FSharp = 370, 12 | G = 392, 13 | GSharp = 415, 14 | A = 440, 15 | Bb = 466, 16 | B = 494, 17 | C3 = 131, 18 | CSharp3 = 139, 19 | D3 = 147, 20 | Eb3 = 156, 21 | E3 = 165, 22 | F3 = 175, 23 | FSharp3 = 185, 24 | G3 = 196, 25 | GSharp3 = 208, 26 | A3 = 220, 27 | Bb3 = 233, 28 | B3 = 247, 29 | C4 = 262, 30 | CSharp4 = 277, 31 | D4 = 294, 32 | Eb4 = 311, 33 | E4 = 330, 34 | F4 = 349, 35 | FSharp4 = 370, 36 | G4 = 392, 37 | GSharp4 = 415, 38 | A4 = 440, 39 | Bb4 = 466, 40 | B4 = 494, 41 | C5 = 523, 42 | CSharp5 = 555, 43 | D5 = 587, 44 | Eb5 = 622, 45 | E5 = 659, 46 | F5 = 698, 47 | FSharp5 = 740, 48 | G5 = 784, 49 | GSharp5 = 831, 50 | A5 = 880, 51 | Bb5 = 932, 52 | B5 = 988, 53 | }; 54 | 55 | static Pin *pin = NULL; 56 | static uint8_t pitchVolume = 0xff; 57 | 58 | // Pin control as per MakeCode. 59 | void analogPitch(int frequency, int ms) { 60 | if (frequency <= 0 || pitchVolume == 0) { 61 | pin->setAnalogValue(0); 62 | } else { 63 | // I don't understand the logic of this value. 64 | // It is much louder on the real pin. 65 | int v = 1 << (pitchVolume >> 5); 66 | // If you flip the order of these they crash on the real pin with E030. 67 | pin->setAnalogValue(v); 68 | pin->setAnalogPeriodUs(1000000/frequency); 69 | } 70 | if (ms > 0) { 71 | fiber_sleep(ms); 72 | pin->setAnalogValue(0); 73 | fiber_sleep(5); 74 | } 75 | } 76 | 77 | void playScale() { 78 | const int beat = 500; 79 | analogPitch(Note::C5, beat); 80 | analogPitch(Note::B, beat); 81 | analogPitch(Note::A, beat); 82 | analogPitch(Note::G, beat); 83 | analogPitch(Note::F, beat); 84 | analogPitch(Note::E, beat); 85 | analogPitch(Note::D, beat); 86 | analogPitch(Note::C, beat); 87 | } 88 | 89 | void audio_virtual_pin_melody() 90 | { 91 | pin = &uBit.audio.virtualOutputPin; 92 | playScale(); 93 | 94 | // For comparison: 95 | pin = &uBit.io.P0; 96 | playScale(); 97 | } 98 | 99 | void audio_sound_expression_test() 100 | { 101 | const ManagedString names[] = { 102 | ManagedString("giggle"), 103 | ManagedString("happy"), 104 | ManagedString("hello"), 105 | ManagedString("mysterious"), 106 | ManagedString("sad"), 107 | ManagedString("slide"), 108 | ManagedString("soaring"), 109 | ManagedString("spring"), 110 | ManagedString("twinkle"), 111 | ManagedString("yawn"), 112 | // "sad" but with an additional zero-duration effect which previously caused errors: 113 | ManagedString("010232279000001440226608881023012800000000240000000000000000000000000000,000000440000000440044008880000012800000000240000000000000000000000000000,310232226070801440162408881023012800000100240000000000000000000000000000,310231623093602440093908880000012800000100240000000000000000000000000000"), 114 | // Just a zero-duration frame. 115 | ManagedString("000000440000000440044008880000012800000000240000000000000000000000000000"), 116 | ManagedString("") 117 | }; 118 | 119 | // uBit.audio.virtualOutputPin.setAnalogPeriodUs(6068); 120 | while (1) { 121 | for (int i = 0; names[i].length() != 0; ++i) { 122 | DMESG("sound %s", names[i].toCharArray()); 123 | uBit.audio.setVolume(255); 124 | uBit.audio.soundExpressions.play(names[i]); 125 | 126 | uBit.audio.setVolume(85); 127 | uBit.audio.soundExpressions.play(names[i]); 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /source/samples/BLETest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Lancaster University. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include "MicroBit.h" 26 | #include "Tests.h" 27 | 28 | extern MicroBit uBit; 29 | MicroBitUARTService *uart; 30 | 31 | // we use events abd the 'connected' variable to keep track of the status of the Bluetooth connection 32 | void onConnected(MicroBitEvent) 33 | { 34 | uBit.display.print("C"); 35 | } 36 | 37 | void onDisconnected(MicroBitEvent) 38 | { 39 | uBit.display.print("D"); 40 | } 41 | 42 | void onDelim(MicroBitEvent) 43 | { 44 | ManagedString r = uart->readUntil("\r\n"); 45 | uart->send(r); 46 | } 47 | 48 | void ble_test() 49 | { 50 | // Configuration Tips 51 | // 52 | // An example codal.json is provided in the root directory: codal.ble.json 53 | // Rename codal.ble.json to codal.json to use this BLE sample 54 | // 55 | // codal.json contains various Bluetooth related properties some of which are explained here: 56 | // 57 | // "SOFTDEVICE_PRESENT": 1 Determines whether the build contains softdevice 58 | // "DEVICE_BLE": 1 Determines whether BLE is enabled 59 | // "MICROBIT_BLE_ENABLED" : 1 Determines whether BLE is enabled 60 | // "MICROBIT_BLE_PAIRING_MODE": 1 Determines whether Pairing Mode is enabled 61 | // "MICROBIT_BLE_DFU_SERVICE": 1 Determines whether the Nordic DFU Service is enabled 62 | // "MICROBIT_BLE_DEVICE_INFORMATION_SERVICE": 1 Determines whether the DIS is enabled 63 | // "MICROBIT_BLE_EVENT_SERVICE" : 1, Determines whether the Event Service is enabled 64 | // "MICROBIT_BLE_PARTIAL_FLASHING" : 0 Determines whether Partial Flashing is enabled (Needs MakeCode/Python) 65 | // "MICROBIT_BLE_SECURITY_LEVEL": "SECURITY_MODE_ENCRYPTION_WITH_MITM" Determines security mode 66 | // 67 | // Options for MICROBIT_BLE_SECURITY_LEVEL are: 68 | // SECURITY_MODE_ENCRYPTION_WITH_MITM, enables pairing with a passcode 69 | // SECURITY_MODE_ENCRYPTION_NO_MITM, enables pairing without a passcode 70 | // SECURITY_MODE_ENCRYPTION_OPEN_LINK, pairing is no required 71 | // 72 | // A cunning code to indicate during start-up the particular Bluetooth configuration in the build 73 | // 74 | // SERVICE CODES 75 | // A: Accelerometer Service 76 | // B: Button Service 77 | // D: Device Information Service 78 | // E: Event Service 79 | // F: DFU Service 80 | // I: IO Pin Service 81 | // L: LED Service 82 | // M: Magnetometer Service 83 | // T: Temperature Service 84 | // U: UART Service 85 | // 86 | 87 | // P: PASSKEY 88 | // J: Just Works 89 | // N: No Pairing Required 90 | 91 | 92 | // Services/Pairing Config/Power Level 93 | uBit.display.scroll("BLE ABDILMTU/P"); 94 | 95 | uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED, onConnected); 96 | uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, onDisconnected); 97 | 98 | uBit.messageBus.listen(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH, onDelim); 99 | 100 | new MicroBitAccelerometerService(*uBit.ble, uBit.accelerometer); 101 | new MicroBitButtonService(*uBit.ble); 102 | new MicroBitIOPinService(*uBit.ble, uBit.io); 103 | new MicroBitLEDService(*uBit.ble, uBit.display); 104 | new MicroBitMagnetometerService(*uBit.ble, uBit.compass); 105 | new MicroBitTemperatureService(*uBit.ble, uBit.thermometer); 106 | 107 | uart = new MicroBitUARTService(*uBit.ble, 32, 32); 108 | uart->eventOn("\r\n"); 109 | 110 | // If main exits, there may still be other fibers running or registered event handlers etc. 111 | // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then 112 | // sit in the idle task forever, in a power efficient sleep. 113 | release_fiber(); 114 | } 115 | 116 | -------------------------------------------------------------------------------- /source/samples/BlinkyTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | int clicks; 5 | int clickmode; 6 | 7 | void red_power_test() 8 | { 9 | uBit.io.row1.setDigitalValue(1); 10 | uBit.io.row2.getDigitalValue(); 11 | uBit.io.row3.getDigitalValue(); 12 | uBit.io.row4.getDigitalValue(); 13 | uBit.io.row5.getDigitalValue(); 14 | 15 | uBit.io.col1.setDigitalValue(0); 16 | uBit.io.col2.getDigitalValue(); 17 | uBit.io.col3.getDigitalValue(); 18 | uBit.io.col4.getDigitalValue(); 19 | uBit.io.col5.getDigitalValue(); 20 | 21 | } 22 | 23 | void green_power_test() 24 | { 25 | uBit.io.row1.setDigitalValue(0); 26 | uBit.io.row2.getDigitalValue(); 27 | uBit.io.row3.getDigitalValue(); 28 | uBit.io.row4.getDigitalValue(); 29 | uBit.io.row5.getDigitalValue(); 30 | 31 | uBit.io.col1.setDigitalValue(1); 32 | uBit.io.col2.getDigitalValue(); 33 | uBit.io.col3.getDigitalValue(); 34 | uBit.io.col4.getDigitalValue(); 35 | uBit.io.col5.getDigitalValue(); 36 | 37 | } 38 | 39 | void off_power_test() 40 | { 41 | uBit.io.row1.getDigitalValue(); 42 | uBit.io.row2.getDigitalValue(); 43 | uBit.io.row3.getDigitalValue(); 44 | uBit.io.row4.getDigitalValue(); 45 | uBit.io.row5.getDigitalValue(); 46 | 47 | uBit.io.col1.getDigitalValue(); 48 | uBit.io.col2.getDigitalValue(); 49 | uBit.io.col3.getDigitalValue(); 50 | uBit.io.col4.getDigitalValue(); 51 | uBit.io.col5.getDigitalValue(); 52 | 53 | } 54 | 55 | 56 | void setDisplay(int mode) 57 | { 58 | DMESG(mode ? "RED\n" : "GREEN\n"); 59 | 60 | uBit.io.row1.setDigitalValue(mode); 61 | uBit.io.row2.setDigitalValue(mode); 62 | uBit.io.row3.setDigitalValue(mode); 63 | uBit.io.row4.setDigitalValue(mode); 64 | uBit.io.row5.setDigitalValue(mode); 65 | 66 | uBit.io.col1.setDigitalValue(!mode); 67 | uBit.io.col2.setDigitalValue(!mode); 68 | uBit.io.col3.setDigitalValue(!mode); 69 | uBit.io.col4.setDigitalValue(!mode); 70 | uBit.io.col5.setDigitalValue(!mode); 71 | } 72 | 73 | void setCol(int col, int mode) 74 | { 75 | int c = 0; 76 | 77 | for (NRF52Pin *p : uBit.ledRowPins) 78 | p->setDigitalValue(mode == 2 ? 0 : mode); 79 | 80 | for (NRF52Pin *p : uBit.ledColPins) 81 | { 82 | if (c == col) 83 | p->setDigitalValue(mode == 2 ? 0 : !mode); 84 | else 85 | p->setDigitalValue(mode == 2 ? 0 : mode); 86 | 87 | c++; 88 | } 89 | } 90 | 91 | 92 | static void onButtonA(MicroBitEvent) 93 | { 94 | if (clickmode != 1) 95 | clicks++; 96 | 97 | clickmode = 1; 98 | 99 | setDisplay(1); 100 | } 101 | 102 | static void onButtonB(MicroBitEvent) 103 | { 104 | if (clickmode != 2) 105 | clicks++; 106 | 107 | clickmode = 2; 108 | 109 | setDisplay(0); 110 | } 111 | 112 | void button_blinky_test() 113 | { 114 | clicks = 0; 115 | clickmode = 0; 116 | uBit.display.disable(); 117 | uBit.messageBus.listen(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, onButtonA); 118 | uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonB); 119 | 120 | setDisplay(1); 121 | 122 | release_fiber(); 123 | } 124 | 125 | void button_blinky_test2() 126 | { 127 | clicks = 0; 128 | clickmode = 0; 129 | uBit.display.disable(); 130 | uBit.messageBus.listen(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, onButtonA); 131 | uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonB); 132 | 133 | setDisplay(1); 134 | 135 | while(clicks < 4) 136 | uBit.sleep(100); 137 | 138 | uBit.messageBus.ignore(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, onButtonA); 139 | uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonB); 140 | uBit.display.enable(); 141 | } 142 | 143 | void fade_test() 144 | { 145 | uBit.display.disable(); 146 | 147 | int period = 40; 148 | int brightness[5] = {0,20,40,60,80}; 149 | int dx[5] = {1,1,1,1,1}; 150 | int compression = 25; 151 | 152 | while(1) 153 | { 154 | for (int c=0; c<5; c++) 155 | { 156 | //green 157 | setCol(c==2?5:c,0); 158 | target_wait_us(period * brightness[c]) ; 159 | 160 | //red 161 | setCol(c,1); 162 | target_wait_us(period * (((100-brightness[c])*compression)/100)); 163 | } 164 | 165 | for (int c=0; c<5; c++) 166 | { 167 | brightness[c] += dx[c]; 168 | 169 | if (brightness[c] == 100 || brightness[c] == 0) 170 | dx[c] = -dx[c]; 171 | } 172 | } 173 | 174 | } 175 | 176 | void blinky() 177 | { 178 | uBit.display.disable(); 179 | uBit.io.row1.setDigitalValue(1); 180 | uBit.io.row2.setDigitalValue(1); 181 | 182 | while (1) { 183 | 184 | uBit.io.col1.setDigitalValue(0); 185 | uBit.io.col2.setDigitalValue(0); 186 | 187 | DMESG("ON"); 188 | uBit.sleep(500); 189 | 190 | uBit.io.col1.setDigitalValue(1); 191 | uBit.io.col2.setDigitalValue(1); 192 | 193 | DMESG("OFF"); 194 | uBit.sleep(500); 195 | } 196 | } 197 | 198 | 199 | -------------------------------------------------------------------------------- /source/samples/ButtonTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | void 5 | button_test1() 6 | { 7 | while(1) 8 | { 9 | if (uBit.io.P5.getDigitalValue()) 10 | uBit.display.image.setPixelValue(0,0,0); 11 | else 12 | uBit.display.image.setPixelValue(0,0,255); 13 | 14 | if (uBit.io.P11.getDigitalValue()) 15 | uBit.display.image.setPixelValue(4,0,0); 16 | else 17 | uBit.display.image.setPixelValue(4,0,255); 18 | 19 | uBit.sleep(100); 20 | } 21 | } 22 | 23 | void 24 | button_test2() 25 | { 26 | while(1) 27 | { 28 | if (uBit.buttonA.isPressed()) 29 | uBit.display.image.setPixelValue(0,0,255); 30 | else 31 | uBit.display.image.setPixelValue(0,0,0); 32 | 33 | if (uBit.buttonB.isPressed()) 34 | uBit.display.image.setPixelValue(4,0,255); 35 | else 36 | uBit.display.image.setPixelValue(4,0,0); 37 | 38 | uBit.sleep(100); 39 | } 40 | } 41 | 42 | void 43 | onButtonA(MicroBitEvent) 44 | { 45 | uBit.display.print("Aa"); 46 | } 47 | 48 | void 49 | onButtonB(MicroBitEvent) 50 | { 51 | uBit.display.print("Bb"); 52 | } 53 | 54 | void 55 | onButtonAB(MicroBitEvent) 56 | { 57 | uBit.display.print("Cc"); 58 | } 59 | 60 | void listenerRemoved(MicroBitListener *) 61 | { 62 | DMESG("Listener deleted"); 63 | } 64 | 65 | void 66 | button_test3() 67 | { 68 | uBit.messageBus.listen(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, onButtonA); 69 | uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonB); 70 | uBit.messageBus.listen(DEVICE_ID_BUTTON_AB, DEVICE_BUTTON_EVT_CLICK, onButtonAB); 71 | 72 | while(1) 73 | uBit.sleep(1000); 74 | } 75 | 76 | void 77 | button_test4() 78 | { 79 | uBit.messageBus.setListenerDeletionCallback(listenerRemoved); 80 | 81 | uBit.messageBus.listen(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, onButtonA); 82 | uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonB); 83 | uBit.messageBus.listen(DEVICE_ID_BUTTON_AB, DEVICE_BUTTON_EVT_CLICK, onButtonAB); 84 | 85 | uBit.sleep(10000); 86 | 87 | uBit.messageBus.ignore(DEVICE_ID_BUTTON_AB, DEVICE_BUTTON_EVT_CLICK, onButtonAB); 88 | 89 | while(1) 90 | uBit.sleep(1000); 91 | } 92 | 93 | 94 | -------------------------------------------------------------------------------- /source/samples/CapTouchTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 British Broadcasting Corporation. 5 | This software is provided by Lancaster University by arrangement with the BBC. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #include "Tests.h" 27 | 28 | int last_t0, last_t1, last_t2; 29 | static int c0 = 0; 30 | static int c1 = 0; 31 | static int c2 = 0; 32 | 33 | #define TOUCH_SENSE_CLUSTER_LOW 0 34 | #define TOUCH_SENSE_CLUSTER_HIGH 1 35 | #define TOUCH_SENSE_INITIALISATION_COUNT 10 36 | #define TOUCH_SENSE_CONVERGENCE_RATE 0.98f 37 | #define TOUCH_SENSE_SMOOTHING_RATE 0.5f 38 | #define TOUCH_SENSE_CLUSTER_CEILING 10000 39 | 40 | int loops = 0; 41 | 42 | float threshold; 43 | int currentCluster = TOUCH_SENSE_CLUSTER_LOW; 44 | int initializing; 45 | 46 | float lo_mean; 47 | float hi_mean; 48 | float touch_level; 49 | 50 | void 51 | calibrateInit() 52 | { 53 | threshold = 500.0f; 54 | currentCluster = TOUCH_SENSE_CLUSTER_LOW; 55 | initializing = TOUCH_SENSE_INITIALISATION_COUNT; 56 | lo_mean = 0.0f; 57 | hi_mean = 0.0f; 58 | touch_level = 0.0f; 59 | } 60 | 61 | void 62 | calibrateTest(float sample) 63 | { 64 | if (initializing) 65 | { 66 | lo_mean += sample; 67 | initializing--; 68 | 69 | if (initializing == 0) 70 | { 71 | lo_mean = lo_mean / TOUCH_SENSE_INITIALISATION_COUNT; 72 | hi_mean = lo_mean + threshold * 2; 73 | touch_level = lo_mean; 74 | } 75 | return; 76 | } 77 | 78 | touch_level = touch_level * TOUCH_SENSE_SMOOTHING_RATE + sample * (1-TOUCH_SENSE_SMOOTHING_RATE); 79 | 80 | if (currentCluster == TOUCH_SENSE_CLUSTER_LOW && touch_level < TOUCH_SENSE_CLUSTER_CEILING && touch_level < hi_mean - threshold) 81 | lo_mean = lo_mean * TOUCH_SENSE_CONVERGENCE_RATE + touch_level * (1-TOUCH_SENSE_CONVERGENCE_RATE); 82 | 83 | if (currentCluster == TOUCH_SENSE_CLUSTER_HIGH && touch_level < TOUCH_SENSE_CLUSTER_CEILING && touch_level > lo_mean + threshold) 84 | hi_mean = hi_mean * TOUCH_SENSE_CONVERGENCE_RATE + touch_level * (1-TOUCH_SENSE_CONVERGENCE_RATE); 85 | 86 | if (touch_level < lo_mean + threshold) 87 | currentCluster = TOUCH_SENSE_CLUSTER_LOW; 88 | 89 | if (touch_level > hi_mean - threshold) 90 | currentCluster = TOUCH_SENSE_CLUSTER_HIGH; 91 | 92 | loops++; 93 | 94 | if (loops == 10){ 95 | DMESG("%d: [SAMPLE: %d][LEVEL: %d][LO_MEAN: %d] [HI_MEAN: %d]", currentCluster, (int)sample, (int)touch_level, (int)lo_mean, (int)hi_mean); 96 | loops = 0; 97 | } 98 | 99 | //DMESG("[SAMPLE: %d]", (int)sample); 100 | } 101 | 102 | void 103 | onCalibrate(MicroBitEvent) 104 | { 105 | 106 | uBit.serial.printf("--- CALIBRATE ---\n"); 107 | c0 = last_t0; 108 | c1 = last_t1; 109 | c2 = last_t2; 110 | } 111 | 112 | void 113 | onPrint(MicroBitEvent) 114 | { 115 | while(1) 116 | uBit.display.scroll(last_t2); 117 | } 118 | 119 | void onTouchP0(MicroBitEvent e) 120 | { 121 | DMESG("TOUCH: P0"); 122 | } 123 | void onTouchP1(MicroBitEvent e) 124 | { 125 | DMESG("TOUCH: P1"); 126 | } 127 | void onTouchP2(MicroBitEvent e) 128 | { 129 | DMESG("TOUCH: P2"); 130 | } 131 | void onTouchFace(MicroBitEvent e) 132 | { 133 | DMESG("TOUCH: FACE"); 134 | } 135 | 136 | void 137 | cap_touch_test() 138 | { 139 | uBit.messageBus.listen(MICROBIT_ID_IO_P0, MICROBIT_BUTTON_EVT_CLICK, onTouchP0); 140 | uBit.messageBus.listen(MICROBIT_ID_IO_P1, MICROBIT_BUTTON_EVT_CLICK, onTouchP1); 141 | uBit.messageBus.listen(MICROBIT_ID_IO_P2, MICROBIT_BUTTON_EVT_CLICK, onTouchP2); 142 | uBit.messageBus.listen(MICROBIT_ID_FACE, MICROBIT_BUTTON_EVT_CLICK, onTouchFace); 143 | 144 | while(1) 145 | { 146 | uBit.display.image.setPixelValue(0,0,uBit.io.P0.isTouched(TouchMode::Resistive) ? 255 : 0); 147 | uBit.display.image.setPixelValue(2,0,uBit.io.P1.isTouched(TouchMode::Resistive) ? 255 : 0); 148 | uBit.display.image.setPixelValue(4,0,uBit.io.P2.isTouched(TouchMode::Resistive) ? 255 : 0); 149 | 150 | uBit.display.image.setPixelValue(2,4,uBit.logo.isPressed() ? 255 : 0); 151 | 152 | // Only useful is pins are placed in capacitative mode... 153 | if (uBit.buttonA.isPressed()) 154 | { 155 | uBit.io.P0.touchCalibrate(); 156 | uBit.io.P1.touchCalibrate(); 157 | uBit.io.P2.touchCalibrate(); 158 | 159 | uBit.sleep(1000); 160 | } 161 | 162 | uBit.sleep(100); 163 | } 164 | } 165 | 166 | void 167 | cap_touch_test_raw() 168 | { 169 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onCalibrate); 170 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onPrint); 171 | 172 | // If main exits, there may still be other fibers running or registered event handlers etc. 173 | // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then 174 | // sit in the idle task forever, in a power efficient sleep. 175 | 176 | int t, t0, t1, t2; 177 | //int THRESHOLD = 100; 178 | int T_MAX = 2000; 179 | 180 | while(1) 181 | { 182 | // Discharge each pin 183 | uBit.io.P0.setDigitalValue(0); 184 | uBit.io.P1.setDigitalValue(0); 185 | uBit.io.P2.setDigitalValue(0); 186 | 187 | uBit.sleep(20); 188 | 189 | // Convert each pin to an input, and time how long it takes to rise to a CMOS logic HI. 190 | t=1; 191 | t0=0; 192 | t1=0; 193 | t2=0; 194 | 195 | uBit.io.P0.getDigitalValue(PullMode::None); 196 | uBit.io.P1.getDigitalValue(PullMode::None); 197 | uBit.io.P2.getDigitalValue(PullMode::None); 198 | 199 | while (t < T_MAX) 200 | { 201 | if (t0 == 0 && uBit.io.P0.getDigitalValue()) 202 | t0=t; 203 | 204 | if (t1 == 0 && uBit.io.P1.getDigitalValue()) 205 | t1=t; 206 | 207 | if (t2 == 0 && uBit.io.P2.getDigitalValue()) 208 | t2=t; 209 | 210 | t++; 211 | } 212 | 213 | if(t0 == 0) 214 | t0 = T_MAX; 215 | 216 | if(t1 == 0) 217 | t1 = T_MAX; 218 | 219 | if(t2 == 0) 220 | t2 = T_MAX; 221 | 222 | last_t0 = t0; 223 | last_t1 = t1; 224 | last_t2 = t2; 225 | 226 | // apply calibration 227 | t0 = t0 - c0; 228 | t1 = t1 - c1; 229 | t2 = t2 - c2; 230 | 231 | /* 232 | if (t0 > THRESHOLD) 233 | uBit.display.image.setPixelValue(0,0,255); 234 | else 235 | uBit.display.image.setPixelValue(0,0,0); 236 | 237 | if (t1 > THRESHOLD) 238 | uBit.display.image.setPixelValue(2,0,255); 239 | else 240 | uBit.display.image.setPixelValue(2,0,0); 241 | 242 | if (t2 > THRESHOLD) 243 | uBit.display.image.setPixelValue(4,0,255); 244 | else 245 | uBit.display.image.setPixelValue(4,0,0); 246 | */ 247 | uBit.serial.printf("[P0: %d] [P1: %d] [P2: %d]\n", t0, t1, t2); 248 | } 249 | 250 | 251 | release_fiber(); 252 | } 253 | 254 | -------------------------------------------------------------------------------- /source/samples/DeepSleepTest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MicroBit.h" 3 | #include "Tests.h" 4 | 5 | //////////////////////////////////////////////////////////////// 6 | // TESTS 7 | 8 | // A fiber that sleeps for a few seconds 9 | void deepsleep_test1(); 10 | 11 | // A fiber that sleeps until woken by button A or B 12 | void deepsleep_test2(); 13 | 14 | // A timer event handler that sleeps between events 15 | void deepsleep_test3(); 16 | 17 | // Wake to run button A or B handlers 18 | void deepsleep_test4(); 19 | 20 | // Two timer event handlers with different periods that sleep between events 21 | void deepsleep_test5(); 22 | 23 | //////////////////////////////////////////////////////////////// 24 | // TEST 25 | 26 | void deepsleep_test( int test) 27 | { 28 | switch ( test) 29 | { 30 | case 1: deepsleep_test1(); break; 31 | case 2: deepsleep_test2(); break; 32 | case 3: deepsleep_test3(); break; 33 | case 4: deepsleep_test4(); break; 34 | case 5: deepsleep_test5(); break; 35 | } 36 | 37 | release_fiber(); 38 | } 39 | 40 | //////////////////////////////////////////////////////////////// 41 | // HELPERS 42 | 43 | void deepsleep_test_zeroone(); 44 | void deepsleep_test_threefour(); 45 | void deepsleep_test_send_time( const char *suffix); 46 | 47 | //////////////////////////////////////////////////////////////// 48 | // TEST 1 49 | 50 | // A fiber that sleeps for a few seconds 51 | 52 | void deepsleep_test1_fiber() 53 | { 54 | while (true) 55 | { 56 | deepsleep_test_send_time( "deepsleep_test1_fiber\n"); 57 | deepsleep_test_zeroone(); 58 | 59 | uBit.power.deepSleep(3000); 60 | } 61 | } 62 | 63 | void deepsleep_test1() 64 | { 65 | deepsleep_test_send_time( "deepsleep_test2\n"); 66 | 67 | // Show that display is off during sleep 68 | uBit.display.image.setPixelValue( 2, 0, 128); 69 | 70 | create_fiber( deepsleep_test1_fiber); 71 | } 72 | 73 | //////////////////////////////////////////////////////////////// 74 | // TEST 2 75 | 76 | // A fiber that sleeps until woken by button A or B 77 | 78 | void deepsleep_test2_fiber() 79 | { 80 | while (true) 81 | { 82 | deepsleep_test_send_time( "deepsleep_test2_fiber\n"); 83 | 84 | uBit.power.deepSleep(); 85 | 86 | if ( uBit.buttonA.isPressed()) 87 | uBit.display.print('A'); 88 | else if ( uBit.buttonB.isPressed()) 89 | uBit.display.print('B'); 90 | else 91 | uBit.display.print('C'); 92 | } 93 | } 94 | 95 | 96 | void deepsleep_test2() 97 | { 98 | deepsleep_test_send_time( "deepsleep_test2\n"); 99 | 100 | // Show that display is off during sleep 101 | uBit.display.image.setPixelValue( 2, 0, 128); 102 | 103 | uBit.io.buttonA.wakeOnActive(1); 104 | uBit.io.buttonB.wakeOnActive(1); 105 | 106 | create_fiber( deepsleep_test2_fiber); 107 | } 108 | 109 | //////////////////////////////////////////////////////////////// 110 | // TEST 3 111 | 112 | // A timer event handler that sleeps between events 113 | 114 | void deepsleep_test3_onTimer(MicroBitEvent e) 115 | { 116 | deepsleep_test_send_time( "deepsleep_test3_onTimer\n"); 117 | deepsleep_test_zeroone(); 118 | 119 | // Request deep sleep and exit the handler 120 | uBit.power.deepSleepAsync(); 121 | } 122 | 123 | 124 | void deepsleep_test3() 125 | { 126 | deepsleep_test_send_time( "deepsleep_test3\n"); 127 | 128 | // Show that display is off during sleep 129 | uBit.display.image.setPixelValue( 2, 0, 128); 130 | 131 | uint16_t timer_id = 60000; 132 | uint16_t timer_value = 1; 133 | CODAL_TIMESTAMP timer_period = 5000; //ms 134 | 135 | uBit.messageBus.listen( timer_id, timer_value, deepsleep_test3_onTimer); 136 | 137 | // CODAL_TIMER_EVENT_FLAGS_WAKEUP makes the timer event trigger power up 138 | system_timer_event_every( timer_period, timer_id, timer_value, CODAL_TIMER_EVENT_FLAGS_WAKEUP); 139 | } 140 | 141 | //////////////////////////////////////////////////////////////// 142 | // TEST 4 143 | 144 | // Wake to run button A or B handlers 145 | 146 | void deepsleep_test4_onButtonA(MicroBitEvent e) 147 | { 148 | // Disable deep sleep power down until we have finished 149 | uBit.power.powerDownDisable(); 150 | 151 | deepsleep_test_zeroone(); 152 | uBit.sleep(500); 153 | deepsleep_test_zeroone(); 154 | 155 | uBit.power.powerDownEnable(); 156 | uBit.power.deepSleepAsync(); 157 | } 158 | 159 | 160 | void deepsleep_test4_onButtonB(MicroBitEvent e) 161 | { 162 | uBit.power.powerDownDisable(); 163 | 164 | deepsleep_test_threefour(); 165 | uBit.sleep(500); 166 | deepsleep_test_threefour(); 167 | 168 | uBit.power.powerDownEnable(); 169 | uBit.power.deepSleepAsync(); 170 | } 171 | 172 | 173 | void deepsleep_test4() 174 | { 175 | deepsleep_test_send_time( "deepsleep_test4\n"); 176 | 177 | // Show that display is off during sleep 178 | uBit.display.image.setPixelValue( 2, 0, 128); 179 | 180 | uBit.messageBus.listen( MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_DOWN, deepsleep_test4_onButtonA); 181 | uBit.messageBus.listen( MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_DOWN, deepsleep_test4_onButtonB); 182 | 183 | uBit.io.buttonA.wakeOnActive(1); 184 | uBit.io.buttonB.wakeOnActive(1); 185 | 186 | uBit.power.deepSleepAsync(); 187 | } 188 | 189 | //////////////////////////////////////////////////////////////// 190 | // TEST 5 191 | 192 | // Two timer event handlers with different periods that sleep between events 193 | 194 | void deepsleep_test5_onTimer1(MicroBitEvent e) 195 | { 196 | uBit.power.powerDownDisable(); 197 | 198 | deepsleep_test_send_time( "deepsleep_test5_onTimer1\n"); 199 | 200 | deepsleep_test_zeroone(); 201 | uBit.sleep(500); 202 | deepsleep_test_zeroone(); 203 | 204 | uBit.power.powerDownEnable(); 205 | 206 | // Request deep sleep and exit the handler 207 | uBit.power.deepSleepAsync(); 208 | } 209 | 210 | 211 | void deepsleep_test5_onTimer2(MicroBitEvent e) 212 | { 213 | uBit.power.powerDownDisable(); 214 | 215 | deepsleep_test_send_time( "deepsleep_test5_onTimer2\n"); 216 | 217 | deepsleep_test_threefour(); 218 | uBit.sleep(500); 219 | deepsleep_test_threefour(); 220 | 221 | uBit.power.powerDownEnable(); 222 | 223 | // Request deep sleep and exit the handler 224 | uBit.power.deepSleepAsync(); 225 | } 226 | 227 | 228 | void deepsleep_test5() 229 | { 230 | deepsleep_test_send_time( "deepsleep_test5\n"); 231 | 232 | // Show that display is off during sleep 233 | uBit.display.image.setPixelValue( 2, 0, 128); 234 | 235 | uint16_t timer_id = 60000; 236 | uint16_t timer_value = 1; 237 | 238 | uBit.messageBus.listen( timer_id, timer_value, deepsleep_test5_onTimer1); 239 | uBit.messageBus.listen( timer_id, timer_value + 1, deepsleep_test5_onTimer2); 240 | 241 | // CODAL_TIMER_EVENT_FLAGS_WAKEUP makes the timer event trigger power up 242 | system_timer_event_every( 6000, timer_id, timer_value, CODAL_TIMER_EVENT_FLAGS_WAKEUP); 243 | system_timer_event_every( 20000, timer_id, timer_value + 1, CODAL_TIMER_EVENT_FLAGS_WAKEUP); 244 | 245 | uBit.power.deepSleepAsync(); 246 | } 247 | 248 | //////////////////////////////////////////////////////////////// 249 | // HELPERS 250 | 251 | void deepsleep_test_togglePixel( int x, int y) 252 | { 253 | uBit.display.image.setPixelValue( x, y, uBit.display.image.getPixelValue( x, y) ? 0 : 255); 254 | } 255 | 256 | 257 | void deepsleep_test_sirenPixels( int x0, int y0, int x1, int y1, int ms) 258 | { 259 | deepsleep_test_togglePixel( x0, y0); 260 | uBit.sleep(ms); 261 | deepsleep_test_togglePixel( x0, y0); 262 | deepsleep_test_togglePixel( x1, y1); 263 | uBit.sleep(ms); 264 | deepsleep_test_togglePixel( x1, y1); 265 | } 266 | 267 | 268 | void deepsleep_test_zeroone() 269 | { 270 | deepsleep_test_send_time( "deepsleep_test_zeroone\n"); 271 | deepsleep_test_sirenPixels( 0, 0, 1, 0, 150); 272 | } 273 | 274 | 275 | void deepsleep_test_threefour() 276 | { 277 | deepsleep_test_send_time( "deepsleep_test_threefour\n"); 278 | deepsleep_test_sirenPixels( 3, 0, 4, 0, 500); 279 | } 280 | 281 | 282 | void deepsleep_test_send_time( const char *suffix) 283 | { 284 | uint64_t second = 1000000; 285 | 286 | uint64_t now = system_timer_current_time_us(); 287 | 288 | int u = (int) (now % second); 289 | int s = (int) (now / second); 290 | int m = s / 60; 291 | s = s % 60; 292 | int h = m / 60; 293 | m = m % 60; 294 | 295 | ManagedString sh( h); 296 | ManagedString sm( m); sm = "00" + sm; sm = sm.substring( sm.length() - 2, 2); 297 | ManagedString ss( s); ss = "00" + ss; ss = ss.substring( ss.length() - 2, 2); 298 | ManagedString su( u); su = "000000" + su; su = su.substring( su.length() - 6, 6); 299 | ManagedString msg = sh + ":" + sm + ":" + ss + "." + su + " " + ManagedString(suffix); 300 | uBit.serial.send( msg); 301 | } 302 | 303 | -------------------------------------------------------------------------------- /source/samples/DisplayTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | const char * const arrow_left_emoji ="\ 5 | 000,000,255,000,000\n\ 6 | 000,255,000,000,000\n\ 7 | 255,255,255,255,255\n\ 8 | 000,255,000,000,000\n\ 9 | 000,000,255,000,000\n"; 10 | 11 | const char * const arrow_right_emoji ="\ 12 | 000,000,255,000,000\n\ 13 | 000,000,000,255,000\n\ 14 | 255,255,255,255,255\n\ 15 | 000,000,000,255,000\n\ 16 | 000,000,255,000,000\n"; 17 | 18 | const char * const tick_emoji ="\ 19 | 000,000,000,000,000\n\ 20 | 000,000,000,000,255\n\ 21 | 000,000,000,255,000\n\ 22 | 255,000,255,000,000\n\ 23 | 000,255,000,000,000\n"; 24 | 25 | const char * const radio_emoji ="\ 26 | 255,255,255,000,000\n\ 27 | 000,000,000,255,000\n\ 28 | 255,255,000,000,255\n\ 29 | 000,000,255,000,255\n\ 30 | 255,000,255,000,255\n"; 31 | 32 | const char * const happy_emoji ="\ 33 | 000,255,000,255,000\n\ 34 | 000,000,000,000,000\n\ 35 | 255,000,000,000,255\n\ 36 | 000,255,255,255,000\n\ 37 | 000,000,000,000,000\n"; 38 | 39 | const char * const wink_emoji ="\ 40 | 000,255,000,000,000\n\ 41 | 000,000,000,000,000\n\ 42 | 255,000,000,000,255\n\ 43 | 000,255,255,255,000\n\ 44 | 000,000,000,000,000\n"; 45 | 46 | const char * const sad_emoji ="\ 47 | 000,255,000,255,000\n\ 48 | 000,000,000,000,000\n\ 49 | 000,000,000,000,000\n\ 50 | 000,255,255,255,000\n\ 51 | 255,000,000,000,255\n"; 52 | 53 | Image happy(happy_emoji); 54 | Image sad(sad_emoji); 55 | 56 | void 57 | concurrent_display_test_t1() 58 | { 59 | while(1) 60 | { 61 | uBit.display.print("JJ"); 62 | uBit.sleep(1000); 63 | } 64 | } 65 | 66 | void 67 | concurrent_display_test_t2() 68 | { 69 | uBit.sleep(500); 70 | while(1) 71 | { 72 | uBit.display.print("FF"); 73 | uBit.sleep(1000); 74 | } 75 | } 76 | 77 | void 78 | concurrent_display_test() 79 | { 80 | DMESG("CONCURRENT_DISPLAY_TEST1:"); 81 | 82 | create_fiber(concurrent_display_test_t1); 83 | create_fiber(concurrent_display_test_t2); 84 | 85 | release_fiber(); 86 | } 87 | 88 | void 89 | display_test1() 90 | { 91 | DMESG("DISPLAY_TEST1:"); 92 | while(1) 93 | { 94 | uBit.display.image.print('J'); 95 | uBit.sleep(500); 96 | uBit.display.image.print('F'); 97 | uBit.sleep(500); 98 | } 99 | } 100 | 101 | void 102 | display_test2() 103 | { 104 | DMESG("DISPLAY_TEST2:"); 105 | while(1) 106 | { 107 | uBit.display.scroll("HELLO"); 108 | uBit.display.scroll("WORLD"); 109 | uBit.sleep(2000); 110 | } 111 | } 112 | 113 | void 114 | display_wink() 115 | { 116 | DMESG("DISPLAY_WINK:"); 117 | 118 | MicroBitImage smile(happy_emoji); 119 | MicroBitImage wink(wink_emoji); 120 | 121 | uBit.display.print(smile); 122 | uBit.sleep(1000); 123 | uBit.display.print(wink); 124 | uBit.sleep(1000); 125 | uBit.display.print(smile); 126 | uBit.sleep(1000); 127 | 128 | uBit.display.clear(); 129 | } 130 | 131 | void 132 | display_brightness_test() 133 | { 134 | MicroBitImage smile(happy_emoji); 135 | uBit.display.print(smile); 136 | uBit.display.setBrightness(50); 137 | 138 | while(1) 139 | { 140 | for (int i=0; i<=255; i++) 141 | { 142 | uBit.display.setBrightness(i); 143 | uBit.sleep(10); 144 | } 145 | 146 | for (int i=255; i>=0; i--) 147 | { 148 | uBit.display.setBrightness(i); 149 | uBit.sleep(10); 150 | } 151 | } 152 | } 153 | 154 | 155 | void 156 | display_tick() 157 | { 158 | DMESG("DISPLAY_TICK:"); 159 | 160 | MicroBitImage tick(tick_emoji); 161 | uBit.display.print(tick); 162 | } 163 | 164 | void 165 | display_arrows() 166 | { 167 | DMESG("DISPLAY_ARROWS:"); 168 | 169 | MicroBitImage arrowL(arrow_left_emoji); 170 | MicroBitImage arrowR(arrow_right_emoji); 171 | 172 | uBit.display.print(arrowL); 173 | uBit.sleep(200); 174 | uBit.display.clear(); 175 | uBit.sleep(200); 176 | uBit.display.print(arrowL); 177 | uBit.sleep(200); 178 | uBit.display.clear(); 179 | uBit.sleep(200); 180 | 181 | uBit.display.print(arrowR); 182 | uBit.sleep(200); 183 | uBit.display.clear(); 184 | uBit.sleep(200); 185 | uBit.display.print(arrowR); 186 | uBit.sleep(200); 187 | uBit.display.clear(); 188 | uBit.sleep(200); 189 | 190 | uBit.display.clear(); 191 | } 192 | 193 | void 194 | display_radio() 195 | { 196 | DMESG("DISPLAY_RADIO:"); 197 | 198 | MicroBitImage radio(radio_emoji); 199 | uBit.display.print(radio); 200 | } 201 | 202 | void 203 | display_countdown() 204 | { 205 | for (int i=9; i>0; i--) 206 | { 207 | uBit.display.print(i); 208 | uBit.sleep(1000); 209 | } 210 | } 211 | 212 | void 213 | raw_blinky_test() 214 | { 215 | uBit.io.row1.setDigitalValue(0); 216 | uBit.io.row2.setDigitalValue(0); 217 | uBit.io.row3.setDigitalValue(0); 218 | uBit.io.row4.setDigitalValue(0); 219 | uBit.io.row5.setDigitalValue(0); 220 | 221 | uBit.io.col1.setDigitalValue(0); 222 | uBit.io.col2.setDigitalValue(0); 223 | uBit.io.col3.setDigitalValue(0); 224 | uBit.io.col4.setDigitalValue(0); 225 | uBit.io.col5.setDigitalValue(0); 226 | 227 | while(1) 228 | { 229 | uBit.io.row1.setDigitalValue(1); 230 | uBit.io.row2.setDigitalValue(1); 231 | uBit.io.row3.setDigitalValue(1); 232 | uBit.io.row4.setDigitalValue(1); 233 | uBit.io.row5.setDigitalValue(1); 234 | DMESG("LED: ON...\n"); 235 | uBit.sleep(500); 236 | 237 | uBit.io.row1.setDigitalValue(0); 238 | uBit.io.row2.setDigitalValue(0); 239 | uBit.io.row3.setDigitalValue(0); 240 | uBit.io.row4.setDigitalValue(0); 241 | uBit.io.row5.setDigitalValue(0); 242 | DMESG("LED: OFF...\n"); 243 | uBit.sleep(500); 244 | } 245 | } 246 | 247 | 248 | void 249 | onButtonAPressed(MicroBitEvent) 250 | { 251 | const char * const a_emoji ="\ 252 | 255,000,000,000,255\n\ 253 | 000,000,000,000,000\n\ 254 | 255,255,255,255,255\n\ 255 | 000,000,000,255,255\n\ 256 | 000,000,000,255,255\n"; 257 | 258 | MicroBitImage img_a(a_emoji); 259 | uBit.display.print(img_a); 260 | } 261 | 262 | void 263 | onButtonBPressed(MicroBitEvent) 264 | { 265 | const char * const b_emoji ="\ 266 | 000,255,000,000,255\n\ 267 | 000,000,255,255,000\n\ 268 | 000,000,255,255,000\n\ 269 | 000,000,255,255,000\n\ 270 | 000,255,000,000,255\n"; 271 | MicroBitImage img_b(b_emoji); 272 | uBit.display.print(img_b); 273 | } 274 | 275 | void 276 | onButtonABPressed(MicroBitEvent) 277 | { 278 | const char * const c_emoji ="\ 279 | 000,000,000,255,255\n\ 280 | 000,000,000,255,255\n\ 281 | 255,255,255,255,255\n\ 282 | 255,255,255,255,255\n\ 283 | 000,255,000,255,000\n"; 284 | MicroBitImage img_c(c_emoji); 285 | uBit.display.print(img_c); 286 | } 287 | 288 | void 289 | onShakePressed(MicroBitEvent) 290 | { 291 | const char * const d_emoji ="\ 292 | 255,000,000,000,255\n\ 293 | 000,255,000,255,000\n\ 294 | 000,000,000,000,000\n\ 295 | 255,255,255,255,255\n\ 296 | 255,000,255,000,255\n"; 297 | MicroBitImage img_d(d_emoji); 298 | uBit.display.print(img_d); 299 | } 300 | 301 | void 302 | do_something_forever() 303 | { 304 | uBit.sleep(10); 305 | } 306 | 307 | void 308 | display_button_icon_test() 309 | { 310 | const char * const heart_emoji ="\ 311 | 000,255,000,255,000\n\ 312 | 255,255,255,255,255\n\ 313 | 255,255,255,255,255\n\ 314 | 000,255,255,255,000\n\ 315 | 000,000,255,000,000\n"; 316 | 317 | MicroBitImage img_heart(heart_emoji); 318 | uBit.display.print(img_heart); 319 | 320 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonAPressed); 321 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBPressed); 322 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_AB, MICROBIT_BUTTON_EVT_CLICK, onButtonABPressed); 323 | uBit.messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_ACCELEROMETER_EVT_SHAKE, onShakePressed); 324 | 325 | create_fiber(do_something_forever); 326 | release_fiber(); 327 | } 328 | 329 | void 330 | display_brightness_AB_test() 331 | { 332 | for (int i=0; i<25; i++) 333 | uBit.display.image.setPixelValue(i / 5, i % 5, (i+1)*4); 334 | 335 | int b = 255; 336 | 337 | while(1) 338 | { 339 | if (uBit.buttonA.isPressed()) 340 | b--; 341 | 342 | if (uBit.buttonB.isPressed()) 343 | b++; 344 | 345 | if (b < 0) 346 | b = 0; 347 | 348 | if (b > 255) 349 | b = 255; 350 | 351 | uBit.display.setBrightness(b); 352 | 353 | uBit.sleep(100); 354 | } 355 | } 356 | 357 | void 358 | display_lightlevel_test() 359 | { 360 | for (int i=0; i<25; i++) 361 | uBit.display.image.setPixelValue(i / 5, i % 5, 255); 362 | 363 | while(1) 364 | { 365 | uBit.display.setBrightness(uBit.display.readLightLevel()); 366 | uBit.sleep(100); 367 | } 368 | } 369 | 370 | void 371 | display_lightlevel_test2() 372 | { 373 | for (int i=0; i<25; i++) 374 | uBit.display.image.setPixelValue(i / 5, i % 5, i*10+1); 375 | 376 | int i = 0; 377 | 378 | while(1) 379 | { 380 | uBit.sleep(500); 381 | 382 | if (i >= 10) 383 | { 384 | uBit.serial.printf("LIGHT: %d\n", uBit.display.readLightLevel()); 385 | } 386 | 387 | if (i == 20) 388 | { 389 | uBit.display.setDisplayMode(DisplayMode::DISPLAY_MODE_GREYSCALE); 390 | i = 0; 391 | } 392 | 393 | i++; 394 | } 395 | } -------------------------------------------------------------------------------- /source/samples/GPIOTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | #include "NRF52PWM.h" 4 | #include "MemorySource.h" 5 | 6 | Pin *edgeConnector[] = { 7 | &uBit.io.P0, 8 | &uBit.io.P1, 9 | &uBit.io.P2, 10 | &uBit.io.P3, 11 | &uBit.io.P4, 12 | &uBit.io.P5, 13 | &uBit.io.P6, 14 | &uBit.io.P7, 15 | &uBit.io.P8, 16 | &uBit.io.P9, 17 | &uBit.io.P10, 18 | &uBit.io.P11, 19 | &uBit.io.P12, 20 | &uBit.io.P13, 21 | &uBit.io.P14, 22 | &uBit.io.P15, 23 | &uBit.io.P16, 24 | &uBit.io.P19, 25 | &uBit.io.P20 26 | }; 27 | 28 | //Pin *analogPins[] = {&uBit.io.P1, &uBit.io.P2}; 29 | static Pin *analogPins[] = {&uBit.io.P1}; 30 | static NRF52PWM *pwm = NULL; 31 | static MemorySource *pwmSource = NULL; 32 | 33 | static uint16_t square[4]; 34 | 35 | void 36 | edge_connector_test() 37 | { 38 | uBit.display.disable(); 39 | uBit.buttonA.disable(); 40 | uBit.buttonB.disable(); 41 | 42 | for (Pin *p : edgeConnector) 43 | p->setDigitalValue(0); 44 | 45 | while(1) 46 | { 47 | for (Pin *p : edgeConnector) 48 | { 49 | p->setDigitalValue(1); 50 | uBit.sleep(500); 51 | p->setDigitalValue(0); 52 | uBit.sleep(500); 53 | } 54 | } 55 | } 56 | 57 | void 58 | analog_test() 59 | { 60 | Image level(5,5); 61 | 62 | while(1) 63 | { 64 | int x=0; 65 | int y=0; 66 | int px = analogPins[0]->getAnalogValue() / 40; 67 | 68 | level.clear(); 69 | 70 | while(px) 71 | { 72 | level.setPixelValue(x,y, 255); 73 | x = (x+1) % 5; 74 | if (x == 0) 75 | y = (y+1) % 5; 76 | 77 | px--; 78 | } 79 | 80 | uBit.display.print(level); 81 | 82 | for (Pin *p : analogPins) 83 | { 84 | int v = p->getAnalogValue(); 85 | DMESG("%d", v); 86 | } 87 | 88 | DMESG("----"); 89 | uBit.sleep(100); 90 | } 91 | } 92 | void 93 | gpio_test() 94 | { 95 | int value = 0; 96 | 97 | uBit.io.P2.getDigitalValue(); 98 | uBit.io.P2.setPull(PullMode::Up); 99 | 100 | while(1) 101 | { 102 | if (uBit.io.P2.getDigitalValue()) 103 | uBit.display.image.setPixelValue(0,0,255); 104 | else 105 | uBit.display.image.setPixelValue(0,0,0); 106 | 107 | uBit.io.P1.setDigitalValue(value); 108 | value = !value; 109 | 110 | uBit.sleep(100); 111 | } 112 | } 113 | 114 | void 115 | highDriveTest() 116 | { 117 | while(1){ 118 | 119 | for (NRF52Pin *p : uBit.ledRowPins) 120 | p->setHighDrive(true); 121 | 122 | for (NRF52Pin *p : uBit.ledColPins) 123 | p->setHighDrive(true); 124 | 125 | uBit.sleep(1000); 126 | 127 | for (NRF52Pin *p : uBit.ledRowPins) 128 | p->setHighDrive(false); 129 | 130 | for (NRF52Pin *p : uBit.ledColPins) 131 | p->setHighDrive(false); 132 | 133 | uBit.sleep(1000); 134 | } 135 | } 136 | 137 | void 138 | pwm_pin_test() 139 | { 140 | int freq = 200; 141 | uBit.display.print('c'); 142 | uBit.sleep(500); 143 | DMESG("PWM_PIN_TEST: STARTING..."); 144 | uBit.io.speaker.setAnalogValue(512); 145 | DMESG("PWM_PIN_TEST: setAnalogValue..."); 146 | 147 | while(1) 148 | { 149 | uBit.io.speaker.setAnalogPeriodUs(1000000/freq); 150 | DMESG("PWM_PIN_TEST: setAnalogPeriodUs..."); 151 | 152 | uBit.sleep(1000); 153 | uBit.io.speaker.setAnalogValue(0); 154 | uBit.sleep(1000); 155 | uBit.io.speaker.setAnalogValue(512); 156 | 157 | freq += 100; 158 | } 159 | } 160 | 161 | void 162 | pwm_test() 163 | { 164 | DMESG("PWM TEST: STARTING..."); 165 | 166 | if (pwmSource == NULL) 167 | pwmSource = new MemorySource(); 168 | 169 | if (pwm == NULL) 170 | pwm = new NRF52PWM(NRF_PWM0, pwmSource->output, 200); 171 | 172 | uBit.io.speaker.setHighDrive(true); 173 | 174 | pwm->connectPin(uBit.io.speaker, 0); 175 | pwm->connectPin(uBit.io.P0, 1); 176 | 177 | DMESG("SPEAKER TEST: WOBBLING... [max: %d]", pwm->getSampleRange()); 178 | 179 | int freq = 200; 180 | 181 | while(1) 182 | { 183 | pwm->setSampleRate(freq); 184 | for (int i=0; i<4; i++) 185 | square[i] = pwm->getSampleRange()/2; 186 | 187 | pwmSource->play(square, 4, 0); 188 | 189 | DMESG("SPEAKER TEST: %d Hz", freq); 190 | uBit.sleep(3000); 191 | 192 | freq = freq + 100; 193 | } 194 | 195 | // Should never get here... 196 | DMESG("SPEAKER TEST: EXITING..."); 197 | } 198 | -------------------------------------------------------------------------------- /source/samples/LightLevelTestRaw.cpp: -------------------------------------------------------------------------------- 1 | #include "Tests.h" 2 | 3 | void 4 | light_level_test_raw() 5 | { 6 | int t; 7 | 8 | uBit.io.row1.getDigitalValue(); 9 | uBit.io.row2.getDigitalValue(); 10 | uBit.io.row3.getDigitalValue(); 11 | uBit.io.row4.getDigitalValue(); 12 | uBit.io.row5.getDigitalValue(); 13 | 14 | uBit.io.col1.setDigitalValue(1); 15 | uBit.io.col2.setDigitalValue(1); 16 | uBit.io.col3.setDigitalValue(1); 17 | uBit.io.col4.setDigitalValue(1); 18 | uBit.io.col5.setDigitalValue(1); 19 | 20 | while(1) 21 | { 22 | t = 0; 23 | uBit.io.row1.setDigitalValue(0); 24 | while(t < 1000000 && uBit.io.row1.getDigitalValue(PullMode::None) == 0) 25 | t++; 26 | 27 | DMESG("DECAY: %d\n", t); 28 | 29 | uBit.sleep(500); 30 | } 31 | } -------------------------------------------------------------------------------- /source/samples/MicrophoneTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "SerialStreamer.h" 3 | #include "StreamNormalizer.h" 4 | #include "LevelDetector.h" 5 | #include "LevelDetectorSPL.h" 6 | #include "Tests.h" 7 | 8 | static NRF52ADCChannel *mic = NULL; 9 | static SerialStreamer *streamer = NULL; 10 | static StreamNormalizer *processor = NULL; 11 | static LevelDetector *level = NULL; 12 | static LevelDetectorSPL *levelSPL = NULL; 13 | static int claps = 0; 14 | static volatile int sample; 15 | 16 | void 17 | onLoud(MicroBitEvent) 18 | { 19 | DMESG("LOUD"); 20 | claps++; 21 | if (claps >= 10) 22 | claps = 0; 23 | 24 | uBit.display.print(claps); 25 | } 26 | 27 | void 28 | onQuiet(MicroBitEvent) 29 | { 30 | DMESG("QUIET"); 31 | } 32 | 33 | void mems_mic_drift_test() 34 | { 35 | uBit.io.runmic.setDigitalValue(1); 36 | uBit.io.runmic.setHighDrive(true); 37 | 38 | while(true) 39 | { 40 | sample = uBit.io.P0.getAnalogValue(); 41 | uBit.sleep(250); 42 | 43 | sample = uBit.io.microphone.getAnalogValue(); 44 | uBit.sleep(250); 45 | 46 | uBit.display.scroll(sample); 47 | } 48 | } 49 | 50 | void 51 | mems_mic_test() 52 | { 53 | if (mic == NULL){ 54 | mic = uBit.adc.getChannel(uBit.io.microphone); 55 | mic->setGain(7,0); // Uncomment for v1.47.2 56 | //mic->setGain(7,1); // Uncomment for v1.46.2 57 | } 58 | 59 | if (processor == NULL) 60 | processor = new StreamNormalizer(mic->output, 0.05f, true, DATASTREAM_FORMAT_8BIT_SIGNED); 61 | 62 | if (streamer == NULL) 63 | streamer = new SerialStreamer(processor->output, SERIAL_STREAM_MODE_BINARY); 64 | 65 | uBit.io.runmic.setDigitalValue(1); 66 | uBit.io.runmic.setHighDrive(true); 67 | 68 | while(1) 69 | uBit.sleep(1000); 70 | } 71 | 72 | void 73 | mems_clap_test(int wait_for_clap) 74 | { 75 | claps = 0; 76 | 77 | if (mic == NULL){ 78 | mic = uBit.adc.getChannel(uBit.io.microphone); 79 | mic->setGain(7,0); 80 | } 81 | 82 | if (processor == NULL) 83 | processor = new StreamNormalizer(mic->output, 1.0f, true, DATASTREAM_FORMAT_UNKNOWN, 10); 84 | 85 | if (level == NULL) 86 | level = new LevelDetector(processor->output, 150, 75); 87 | 88 | uBit.io.runmic.setDigitalValue(1); 89 | uBit.io.runmic.setHighDrive(true); 90 | 91 | uBit.messageBus.listen(DEVICE_ID_SYSTEM_LEVEL_DETECTOR, LEVEL_THRESHOLD_HIGH, onLoud); 92 | uBit.messageBus.listen(DEVICE_ID_SYSTEM_LEVEL_DETECTOR, LEVEL_THRESHOLD_LOW, onQuiet); 93 | 94 | while(!wait_for_clap || (wait_for_clap && claps < 3)) 95 | uBit.sleep(1000); 96 | 97 | uBit.messageBus.ignore(DEVICE_ID_SYSTEM_LEVEL_DETECTOR, LEVEL_THRESHOLD_HIGH, onLoud); 98 | uBit.messageBus.ignore(DEVICE_ID_SYSTEM_LEVEL_DETECTOR, LEVEL_THRESHOLD_LOW, onQuiet); 99 | } 100 | 101 | void 102 | mems_clap_test_spl(int wait_for_clap) 103 | { 104 | claps = 0; 105 | 106 | if (mic == NULL){ 107 | mic = uBit.adc.getChannel(uBit.io.microphone); 108 | mic->setGain(7,0); 109 | } 110 | 111 | if (processor == NULL) 112 | processor = new StreamNormalizer(mic->output, 1.0f, true, DATASTREAM_FORMAT_UNKNOWN, 10); 113 | 114 | if (levelSPL == NULL) 115 | levelSPL = new LevelDetectorSPL(processor->output, 75.0, 60.0, 9, 52, DEVICE_ID_MICROPHONE); 116 | 117 | uBit.io.runmic.setDigitalValue(1); 118 | uBit.io.runmic.setHighDrive(true); 119 | 120 | uBit.messageBus.listen(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_HIGH, onLoud); 121 | uBit.messageBus.listen(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_LOW, onQuiet); 122 | 123 | while(!wait_for_clap || (wait_for_clap && claps < 3)) 124 | uBit.sleep(1000); 125 | 126 | uBit.messageBus.ignore(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_HIGH, onLoud); 127 | uBit.messageBus.ignore(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_LOW, onQuiet); 128 | } 129 | 130 | class MakeCodeMicrophoneTemplate { 131 | public: 132 | MIC_DEVICE microphone; 133 | LevelDetectorSPL level; 134 | MakeCodeMicrophoneTemplate() MIC_INIT { MIC_ENABLE; } 135 | }; 136 | 137 | void 138 | mc_clap_test() 139 | { 140 | new MakeCodeMicrophoneTemplate(); 141 | 142 | uBit.messageBus.listen(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_HIGH, onLoud); 143 | uBit.messageBus.listen(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_LOW, onQuiet); 144 | 145 | while(1) 146 | { 147 | uBit.sleep(1000); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /source/samples/NoiseProfiler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Lancaster University. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include "NoiseProfiler.h" 26 | #include "Tests.h" 27 | 28 | /** 29 | * Creates a simple component that generates a noise profile of an 8 bit data stream provided 30 | * @param source a DataSource to measure. 31 | */ 32 | NoiseProfiler::NoiseProfiler(DataSource &source) : upstream(source) 33 | { 34 | reset(); 35 | 36 | // Register with our upstream component 37 | source.connect(*this); 38 | } 39 | 40 | /** 41 | * Callback provided when data is ready. 42 | */ 43 | int 44 | NoiseProfiler::pullRequest() 45 | { 46 | ManagedBuffer buf = upstream.pull(); 47 | 48 | int8_t *p = (int8_t *)&buf[0]; 49 | int8_t *end = (int8_t *)p + buf.length(); 50 | int s,s1; 51 | bool first = true; 52 | 53 | while (p < end) 54 | { 55 | if (samples < NOISE_PROFILE_TOTAL_SAMPLES) 56 | { 57 | s = *p; 58 | 59 | if (s <= NOISE_PROFILE_RANGE && s >= -NOISE_PROFILE_RANGE) 60 | noiseProfile[s+NOISE_PROFILE_RANGE]++; 61 | 62 | if (first) 63 | first = false; 64 | else 65 | variance += abs(s-s1); 66 | 67 | s1 = s; 68 | samples++; 69 | 70 | } 71 | 72 | p++; 73 | } 74 | 75 | return DEVICE_OK; 76 | } 77 | 78 | void 79 | NoiseProfiler::reset() 80 | { 81 | // Reset our state 82 | for (int i=0; i= NOISE_PROFILE_TOTAL_SAMPLES; 112 | } -------------------------------------------------------------------------------- /source/samples/NoiseProfiler.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Lancaster University. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include "MicroBit.h" 26 | #include "CodalConfig.h" 27 | #include "DataStream.h" 28 | 29 | #ifndef NOISE_PROFILER_H 30 | #define NOISE_PROFILER_H 31 | 32 | #define NOISE_PROFILE_RANGE 10 33 | #define NOISE_PROFILE_SIZE (2*NOISE_PROFILE_RANGE+1) 34 | #define NOISE_PROFILE_TOTAL_SAMPLES 110000 35 | 36 | 37 | class NoiseProfiler : public DataSink 38 | { 39 | DataSource &upstream; 40 | int noiseProfile[NOISE_PROFILE_SIZE]; 41 | int variance; 42 | int samples; 43 | 44 | public: 45 | /** 46 | * Creates a simple component that generates a noise profile of an 8 bit data stream provided 47 | * @param source a DataSource to measure. 48 | */ 49 | NoiseProfiler(DataSource &source); 50 | 51 | /** 52 | * Callback provided when data is ready. 53 | */ 54 | virtual int pullRequest(); 55 | 56 | /** 57 | * reset gathered data 58 | */ 59 | void reset(); 60 | 61 | /** 62 | * Output the results gathered to the DMESG buffer 63 | */ 64 | void printResults(); 65 | 66 | /** 67 | * Determines the state of the test 68 | * @return true if the test is complete, fasle otherwise 69 | */ 70 | bool isDone(); 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /source/samples/PowerManagementTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | #include "MicroBitPowerManager.h" 5 | 6 | const char * const dc_emoji ="\ 7 | 000,000,000,000,000\n\ 8 | 000,000,000,000,000\n\ 9 | 255,255,255,255,255\n\ 10 | 000,000,000,000,000\n\ 11 | 000,000,000,000,000\n"; 12 | 13 | const char * const usb_emoji ="\ 14 | 000,000,000,000,000\n\ 15 | 255,255,255,255,255\n\ 16 | 255,000,000,000,255\n\ 17 | 000,255,255,255,000\n\ 18 | 000,000,000,000,000\n"; 19 | 20 | const char * const battery_emoji ="\ 21 | 000,000,255,000,000\n\ 22 | 000,255,255,255,000\n\ 23 | 000,255,255,255,000\n\ 24 | 000,255,255,255,000\n\ 25 | 000,255,255,255,000\n"; 26 | 27 | static MicroBitImage dc(dc_emoji); 28 | static MicroBitImage usb(usb_emoji); 29 | static MicroBitImage battery(battery_emoji); 30 | 31 | void 32 | version_test() 33 | { 34 | MicroBitVersion v; 35 | 36 | v.board = 0; 37 | v.daplink = 0; 38 | v.i2c = 0; 39 | 40 | v = uBit.power.getVersion(); 41 | DMESG("VERSION: [board: %d] [daplink: %d] [i2c-protocol %d]", v.board, v.daplink, v.i2c); 42 | } 43 | 44 | void 45 | off_test() 46 | { 47 | uBit.power.off(); 48 | } 49 | 50 | static void power_management_enter_standby(MicroBitEvent) 51 | { 52 | DMESG("Entering System Off in 1 second..."); 53 | uBit.sleep(1000); 54 | 55 | uBit.power.off(); 56 | } 57 | 58 | static void power_management_deep_sleep_until_button_b(MicroBitEvent) 59 | { 60 | DMESG("Entering Deep Sleep, wake on button B."); 61 | uBit.io.buttonB.setActiveLo(); 62 | uBit.io.buttonB.wakeOnActive(1); 63 | uBit.power.deepSleep(); 64 | DMESG("Leaving Deep Sleep..."); 65 | } 66 | 67 | static void power_management_deep_sleep_until_P0_high(MicroBitEvent) 68 | { 69 | DMESG("Entering Deep Sleep, on P0 LO->HI"); 70 | uBit.io.P0.setPull(PullMode::Down); 71 | uBit.io.P0.setActiveHi(); 72 | uBit.io.P0.wakeOnActive(1); 73 | uBit.power.deepSleep(); 74 | } 75 | 76 | void 77 | interactive_off_test() 78 | { 79 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, power_management_enter_standby); 80 | uBit.display.print("*"); 81 | 82 | while(1) 83 | uBit.sleep(10000); 84 | } 85 | 86 | void 87 | deep_sleep_test1() 88 | { 89 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, power_management_deep_sleep_until_button_b); 90 | uBit.display.print("*"); 91 | 92 | while(1) 93 | uBit.sleep(10000); 94 | } 95 | 96 | void 97 | deep_sleep_test2() 98 | { 99 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, power_management_deep_sleep_until_P0_high); 100 | uBit.display.print("*"); 101 | 102 | while(1) 103 | uBit.sleep(10000); 104 | } 105 | 106 | void 107 | interactive_deep_sleep_test() 108 | { 109 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, power_management_enter_standby); 110 | uBit.display.print("*"); 111 | 112 | while(1) 113 | uBit.sleep(10000); 114 | } 115 | 116 | 117 | void 118 | usb_connection_test() 119 | { 120 | while(1) 121 | { 122 | uBit.display.print(" "); 123 | uBit.sleep(100); 124 | DMESG("POWER_CONSUMPTION: %d", uBit.power.getPowerConsumption()); 125 | uBit.sleep(2000); 126 | 127 | uBit.display.print("*"); 128 | uBit.sleep(100); 129 | DMESG("POWER_CONSUMPTION: %d", uBit.power.getPowerConsumption()); 130 | uBit.sleep(2000); 131 | } 132 | } 133 | 134 | void 135 | power_source_test() 136 | { 137 | while(1) 138 | { 139 | MicroBitPowerSource p = uBit.power.getPowerSource(); 140 | 141 | if (p == PWR_SOURCE_NONE) 142 | { 143 | DMESG("POWER_SOURCE: NONE"); 144 | uBit.display.print(dc); 145 | uBit.sleep(2000); 146 | } 147 | 148 | if (p == PWR_USB_ONLY) 149 | { 150 | DMESG("POWER_SOURCE: USB"); 151 | uBit.display.print(usb); 152 | uBit.sleep(2000); 153 | } 154 | 155 | if (p == PWR_BATT_ONLY) 156 | { 157 | DMESG("POWER_SOURCE: BATTERY"); 158 | uBit.display.print(battery); 159 | uBit.sleep(2000); 160 | 161 | } 162 | 163 | if (p == PWR_USB_AND_BATT) 164 | { 165 | DMESG("POWER_SOURCE: USB+BATTERY"); 166 | uBit.display.print(usb); 167 | uBit.sleep(500); 168 | uBit.display.print(battery); 169 | uBit.sleep(500); 170 | uBit.display.print(usb); 171 | uBit.sleep(500); 172 | uBit.display.print(battery); 173 | uBit.sleep(500); 174 | } 175 | } 176 | } -------------------------------------------------------------------------------- /source/samples/README.md: -------------------------------------------------------------------------------- 1 | # samples 2 | This folder includes a range of short micro:bit v2 programs that illustrate the capability of the device and how to use CODAL to access those features. 3 | 4 | # ** PLEASE NOTE: ** 5 | These samples are work in progress. Some of them may illustrate ways to test prototype version sof the device and may no longer be the easiest/best way to achieve the results shown. We will be updating these regualrly to reflect the evolving nature of this repository. 6 | -------------------------------------------------------------------------------- /source/samples/RadioTestRx.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | int data_received; 5 | 6 | void onData(MicroBitEvent) 7 | { 8 | PacketBuffer b = uBit.radio.datagram.recv(); 9 | 10 | if (b[0] == '1') 11 | uBit.display.print("A"); 12 | 13 | if (b[0] == '2') 14 | uBit.display.print("B"); 15 | } 16 | 17 | void onData2(MicroBitEvent) 18 | { 19 | PacketBuffer b = uBit.radio.datagram.recv(); 20 | DMESG("RECV"); 21 | 22 | if (b[0] =='M' && b[1] =='B' && b[2] =='N' && b[3] =='E' && b[4] =='X' && b[5] =='T') 23 | data_received = 1; 24 | } 25 | 26 | void radio_rx_test() 27 | { 28 | uBit.messageBus.listen(DEVICE_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, onData); 29 | uBit.radio.enable(); 30 | 31 | while(1) 32 | uBit.sleep(1000); 33 | } 34 | 35 | void radio_rx_test2() 36 | { 37 | data_received = 0; 38 | 39 | uBit.messageBus.listen(DEVICE_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, onData2); 40 | uBit.radio.enable(); 41 | 42 | while(!data_received) 43 | uBit.sleep(1000); 44 | 45 | uBit.messageBus.ignore(DEVICE_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, onData2); 46 | } 47 | 48 | void radio_tx_test() 49 | { 50 | uBit.radio.enable(); 51 | 52 | while(1) 53 | { 54 | if (uBit.buttonA.isPressed()) 55 | uBit.radio.datagram.send("1"); 56 | 57 | else if (uBit.buttonB.isPressed()) 58 | uBit.radio.datagram.send("2"); 59 | 60 | uBit.sleep(100); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /source/samples/SerialNumber.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | #define MEMS_MIC 1 5 | #define PIEZO_MIC 2 6 | 7 | #define SETTLE_DELAY 1000 8 | #define FACTORY_DATA 0x0007FC00 9 | 10 | 11 | // 12 | // Configuration to map a given pin to it's associated NRF52 analog ID. 13 | // 14 | static const KeyValueTableEntry nrf52_id_to_mic_config_data[] = { 15 | {2,PIEZO_MIC}, 16 | {0x3892F209,MEMS_MIC} 17 | }; 18 | CREATE_KEY_VALUE_TABLE(nrf52_id_to_mic_config, nrf52_id_to_mic_config_data); 19 | 20 | int isMemsMic() 21 | { 22 | if (nrf52_id_to_mic_config.hasKey(microbit_serial_number())) 23 | return nrf52_id_to_mic_config.get(microbit_serial_number()) == MEMS_MIC; 24 | 25 | return 0; 26 | } 27 | 28 | int isPiezoMic() 29 | { 30 | if (nrf52_id_to_mic_config.hasKey(microbit_serial_number())) 31 | return nrf52_id_to_mic_config.get(microbit_serial_number()) == PIEZO_MIC; 32 | 33 | return 0; 34 | } 35 | 36 | int isPiezoMic2() 37 | { 38 | int sense1; 39 | int sense2; 40 | 41 | uBit.io.speaker.setDigitalValue(0); 42 | uBit.io.runmic.setDigitalValue(1); 43 | uBit.sleep(100); 44 | 45 | uBit.io.speaker.setDigitalValue(1); 46 | target_wait_us(SETTLE_DELAY); 47 | 48 | sense1 = uBit.io.microphone.getAnalogValue(); 49 | { 50 | uBit.io.speaker.setDigitalValue(0); 51 | target_wait_us(SETTLE_DELAY); 52 | sense2 = uBit.io.microphone.getAnalogValue(); 53 | } 54 | 55 | DMESG("[SENSE1: %d] [SENSE2: %d]", sense1, sense2); 56 | 57 | if (abs(sense1 - sense2) > 40) 58 | return 1; 59 | 60 | return 0; 61 | } 62 | 63 | void showSerialNumber() 64 | { 65 | int piezo = isPiezoMic2(); 66 | 67 | DMESG("MBNEXT: [SERIAL_NUMBER:%x] [%s]", microbit_serial_number(), piezo ? "PIEZO" : "MEMS"); 68 | 69 | if (piezo) 70 | uBit.display.print("P"); 71 | else 72 | uBit.display.print("M"); 73 | 74 | while(1) 75 | uBit.sleep(1000); 76 | } 77 | 78 | int 79 | hasPassedFactoryTests() 80 | { 81 | uint32_t *state = (uint32_t *)FACTORY_DATA; 82 | 83 | return ((*state == 0) ? 1 : 0); 84 | } 85 | 86 | void 87 | record_factory_pass() 88 | { 89 | uint32_t *state = (uint32_t *)FACTORY_DATA; 90 | DMESG("FACTORY_PASS"); 91 | 92 | if (*state) 93 | { 94 | DMESG("STORING...\n"); 95 | // Enable Flash Writes 96 | NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos); 97 | while (NRF_NVMC->READY == NVMC_READY_READY_Busy); 98 | 99 | // Configure PINS for GPIO use. 100 | *state = 0; 101 | 102 | // Disable Flash Writes 103 | NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos); 104 | while (NRF_NVMC->READY == NVMC_READY_READY_Busy); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /source/samples/SerialStreamer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Lancaster University. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include "SerialStreamer.h" 26 | #include "Tests.h" 27 | 28 | /** 29 | * Creates a simple component that logs a stream of signed 16 bit data as signed 8-bit data over serial. 30 | * @param source a DataSource to measure the level of. 31 | * @param mode the format of the serialised data. Valid options are SERIAL_STREAM_MODE_BINARY (default), SERIAL_STREAM_MODE_DECIMAL, SERIAL_STREAM_MODE_HEX. 32 | */ 33 | SerialStreamer::SerialStreamer(DataSource &source, int mode) : upstream(source) 34 | { 35 | this->mode = mode; 36 | 37 | // Register with our upstream component 38 | source.connect(*this); 39 | } 40 | 41 | /** 42 | * Callback provided when data is ready. 43 | */ 44 | int SerialStreamer::pullRequest() 45 | { 46 | static volatile int pr = 0; 47 | 48 | if(!pr) 49 | { 50 | pr++; 51 | while(pr) 52 | { 53 | lastBuffer = upstream.pull(); 54 | streamBuffer(lastBuffer); 55 | pr--; 56 | } 57 | } 58 | else 59 | { 60 | pr++; 61 | } 62 | 63 | return DEVICE_OK; 64 | } 65 | 66 | /** 67 | * returns the last buffer processed by this component 68 | */ 69 | ManagedBuffer SerialStreamer::getLastBuffer() 70 | { 71 | return lastBuffer; 72 | } 73 | 74 | /** 75 | * Callback provided when data is ready. 76 | */ 77 | void SerialStreamer::streamBuffer(ManagedBuffer buffer) 78 | { 79 | int CRLF = 0; 80 | int bps = upstream.getFormat(); 81 | 82 | // If a BINARY mode is requested, simply output all the bytes to the serial port. 83 | if (mode == SERIAL_STREAM_MODE_BINARY) 84 | { 85 | uint8_t *p = &buffer[0]; 86 | uint8_t *end = p + buffer.length(); 87 | 88 | while(p < end) 89 | uBit.serial.putc(*p++); 90 | } 91 | 92 | // if a HEX mode is requested, format using printf, framed by sample size.. 93 | if (mode == SERIAL_STREAM_MODE_HEX || mode == SERIAL_STREAM_MODE_DECIMAL) 94 | { 95 | uint8_t *d = &buffer[0]; 96 | uint8_t *end = d+buffer.length(); 97 | uint32_t data; 98 | 99 | while(d < end) 100 | { 101 | data = *d++; 102 | 103 | if (bps > DATASTREAM_FORMAT_8BIT_SIGNED) 104 | data |= (*d++) << 8; 105 | if (bps > DATASTREAM_FORMAT_16BIT_SIGNED) 106 | data |= (*d++) << 16; 107 | if (bps > DATASTREAM_FORMAT_24BIT_SIGNED) 108 | data |= (*d++) << 24; 109 | 110 | if (mode == SERIAL_STREAM_MODE_HEX) 111 | uBit.serial.printf("%x ", data); 112 | else 113 | uBit.serial.printf("%d ", data); 114 | 115 | CRLF++; 116 | 117 | if (CRLF == 16){ 118 | uBit.serial.printf("\n"); 119 | CRLF = 0; 120 | } 121 | } 122 | 123 | if (CRLF > 0) 124 | uBit.serial.printf("\n"); 125 | } 126 | 127 | // We're alway hungry, so deschedule ourselves after processing each buffer. 128 | schedule(); 129 | } 130 | 131 | 132 | -------------------------------------------------------------------------------- /source/samples/SerialStreamer.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Lancaster University. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include "MicroBit.h" 26 | #include "CodalConfig.h" 27 | #include "DataStream.h" 28 | 29 | #ifndef SERIAL_STREAMER_H 30 | #define SERIAL_STREAMER_H 31 | 32 | #define SERIAL_STREAM_MODE_BINARY 1 33 | #define SERIAL_STREAM_MODE_DECIMAL 2 34 | #define SERIAL_STREAM_MODE_HEX 3 35 | 36 | class SerialStreamer : public DataSink 37 | { 38 | DataSource &upstream; 39 | ManagedBuffer lastBuffer; 40 | int mode; 41 | 42 | public: 43 | /** 44 | * Creates a simple component that logs a stream of signed 16 bit data as signed 8-bit data over serial. 45 | * @param source a DataSource to measure the level of. 46 | * @param mode the format of the serialised data. Valid options are SERIAL_STREAM_MODE_BINARY (default), SERIAL_STREAM_MODE_DECIMAL, SERIAL_STREAM_MODE_HEX. 47 | */ 48 | SerialStreamer(DataSource &source, int mode = SERIAL_STREAM_MODE_BINARY); 49 | 50 | /** 51 | * Callback provided when data is ready. 52 | */ 53 | virtual int pullRequest(); 54 | 55 | /** 56 | * Stream the last buffer received to the serial port. 57 | * n.b. this occurs automatically upon the buffer is made available by our upstream component. 58 | * Call this method explicitly only if your wish to send the buffer again. 59 | */ 60 | void streamBuffer(ManagedBuffer buffer); 61 | 62 | /** 63 | * returns the last buffer processed by this component 64 | */ 65 | ManagedBuffer getLastBuffer(); 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /source/samples/TemperatureTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | void 5 | temperature_test() 6 | { 7 | while(1) 8 | { 9 | DMESG("TEMPERATURE: %d", uBit.thermometer.getTemperature()); 10 | uBit.display.scroll(uBit.thermometer.getTemperature()); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /source/samples/Tests.h: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "CodalDmesg.h" 3 | 4 | #ifndef MB_NEXT_TESTS_H 5 | #define MB_NEXT_TESTS_H 6 | 7 | #define MICROBIT_UBIT_AS_STATIC_OBJECT 8 | 9 | #ifdef MICROBIT_UBIT_AS_STATIC_OBJECT 10 | extern MicroBit uBit; 11 | #else 12 | extern MicroBit& uBit; 13 | #endif 14 | 15 | void blinky(); 16 | void button_test1(); 17 | void button_test2(); 18 | void button_test3(); 19 | void button_test4(); 20 | void display_test1(); 21 | void display_test2(); 22 | void concurrent_display_test(); 23 | void fade_test(); 24 | void mems_mic_test(); 25 | void speaker_test(int plays); 26 | void speaker_test2(int plays); 27 | void gpio_test(); 28 | void highDriveTest(); 29 | void radio_rx_test(); 30 | void radio_rx_test2(); 31 | void radio_tx_test(); 32 | void temperature_test(); 33 | void accelerometer_test1(); 34 | void compass_test1(); 35 | void compass_test2(); 36 | void button_blinky_test(); 37 | void spirit_level(); 38 | void edge_connector_test(); 39 | void analog_test(); 40 | void mems_clap_test(int wait_for_clap = 0); 41 | void mems_clap_test_spl(int wait_for_clap = 0); 42 | void showSerialNumber(); 43 | void display_wink(); 44 | void display_tick(); 45 | void display_radio(); 46 | void spirit_level2(); 47 | void button_blinky_test2(); 48 | int isPiezoMic2(); 49 | int hasPassedFactoryTests(); 50 | void record_factory_pass(); 51 | void display_arrows(); 52 | void square_wave_test(); 53 | void red_power_test(); 54 | void green_power_test(); 55 | void off_power_test(); 56 | void shake_test(); 57 | int read_light_level(); 58 | void compass_accelerometer_test(); 59 | void display_countdown(); 60 | void raw_blinky_test(); 61 | void display_button_icon_test(); 62 | void display_brightness_test(); 63 | void pwm_test(); 64 | void pwm_pin_test(); 65 | void cap_touch_test(); 66 | void cap_touch_test_raw(); 67 | void light_level_test_raw(); 68 | void display_brightness_AB_test(); 69 | void display_lightlevel_test(); 70 | void display_lightlevel_test2(); 71 | void mems_mic_drift_test(); 72 | void mc_clap_test(); 73 | void synthesizer_test(); 74 | void version_test(); 75 | void power_consumption_test(); 76 | void power_source_test(); 77 | void standby_test(); 78 | void sound_emoji_test(); 79 | void interactive_off_test(); 80 | void deep_sleep_test1(); 81 | void deep_sleep_test2(); 82 | void interactive_deep_sleep_test(); 83 | void usb_connection_test(); 84 | void sound_emoji_streamer(); 85 | void flash_storage_test(); 86 | void sound_expression_test(); 87 | void audio_sound_expression_test(); 88 | void audio_virtual_pin_melody(); 89 | void mixer_test(); 90 | void mixer_test2(); 91 | void speaker_pin_test(); 92 | void say_hello(); 93 | void stream_mixer_to_serial(); 94 | void out_of_box_experience(); 95 | void level_meter(); 96 | void init_clap_detect(); 97 | void ble_test(); 98 | void deepsleep_test( int test); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /source/samples/USBFlashTest.cpp: -------------------------------------------------------------------------------- 1 | #include "MicroBit.h" 2 | #include "Tests.h" 3 | 4 | #include "MicroBitUSBFlashManager.h" 5 | 6 | static void 7 | onReadFlashStatus() 8 | { 9 | DMESG("Reading CONFIG:"); 10 | 11 | //MicroBitUSBFlashConfig config = uBit.flash.getConfiguration(); 12 | MicroBitUSBFlashGeometry geometry = uBit.flash.getGeometry(); 13 | //DMESG("FLASH CONFIG: [filename: %s] [size:%d] [visible:%d]", config.fileName.toCharArray(), config.fileSize, config.visible ? 1 : 0); 14 | DMESG("FLASH GEOMETRY: [blockSize: %d][blockCount: %d]", geometry.blockSize, geometry.blockCount); 15 | } 16 | 17 | static void 18 | onWriteFlashStatus() 19 | { 20 | DMESG("witeFlashStatus:"); 21 | 22 | DMESG("Erasing CONFIG:"); 23 | uBit.flash.eraseConfig(); 24 | 25 | MicroBitUSBFlashConfig config; 26 | 27 | config.fileName = "JOE.TXT"; 28 | config.fileSize = 8; 29 | config.visible = true; 30 | 31 | DMESG("Writing CONFIG:"); 32 | 33 | uBit.flash.setConfiguration(config, true); 34 | 35 | DMESG("Done"); 36 | } 37 | 38 | static void 39 | onReadFlash() 40 | { 41 | int address = 90; 42 | int size = 30; 43 | 44 | DMESG("Reading FLASH... [address: %d] [length: %d]", address, size); 45 | 46 | ManagedBuffer response(size); 47 | response = uBit.flash.read(address, size); 48 | 49 | /* 50 | for (int i=0; i 'z') 101 | c = 'a'; 102 | } 103 | 104 | uBit.flash.write(b, address); 105 | } 106 | 107 | static void 108 | onRemount(MicroBitEvent) 109 | { 110 | DMESG("remount:"); 111 | uBit.flash.remount(); 112 | } 113 | 114 | static void 115 | onStartFlashTest(MicroBitEvent) 116 | { 117 | DMESG("FLASH_STORAGE_TEST: STARTING IN 3 SECONDS"); 118 | uBit.sleep(3000); 119 | 120 | DMESG("FLASH_STORAGE_TEST: ERASING 4K PAGES"); 121 | onEraseFlash(); 122 | 123 | DMESG("FLASH_STORAGE_TEST: WRITING"); 124 | onWriteFlash(); 125 | 126 | DMESG("FLASH_STORAGE_TEST: READING"); 127 | onReadFlash(); 128 | 129 | DMESG("FLASH_STORAGE_TEST: ERASING bytes"); 130 | onPartialEraseFlash(); 131 | 132 | DMESG("FLASH_STORAGE_TEST: READING (AGAIN)"); 133 | onReadFlash(); 134 | 135 | DMESG("FLASH_STORAGE_TEST: DONE"); 136 | 137 | microbit_dmesg_flush(); 138 | 139 | } 140 | 141 | void flash_storage_test() 142 | { 143 | //UNUSED FUNCTIONS 144 | (void) onReadFlashStatus; 145 | (void) onWriteFlashStatus; 146 | 147 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onStartFlashTest); 148 | uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onRemount); 149 | 150 | while(1) 151 | uBit.sleep(10000); 152 | } -------------------------------------------------------------------------------- /source/sequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef UNITTEST 4 | #include "MicroBit.h" 5 | #else 6 | #include 7 | #include 8 | #endif 9 | 10 | class ISequenceGenerator 11 | { 12 | public: 13 | virtual bool initialize(uint8_t *chm, uint32_t accessAddress); 14 | virtual void resetConnection(void); 15 | virtual void prepareToFollow(void); 16 | virtual void updateChannelMap(uint8_t *chm); 17 | virtual int getNextChannel(void); 18 | virtual int getCurrentChannel(void); 19 | virtual int getFirstChannel(void); 20 | virtual int getSecondChannel(void); 21 | virtual int getHopIncrement(int interval); 22 | virtual void setHopIncrement(int increment); 23 | virtual uint8_t get_channel(uint16_t counter); 24 | virtual int resolveCounter(uint32_t *measures, int count, uint8_t channel); 25 | 26 | }; 27 | 28 | /** 29 | * Sequence generator 30 | **/ 31 | 32 | class LegacySequenceGenerator : public ISequenceGenerator 33 | { 34 | 35 | private: 36 | 37 | /* Recovery parameters. */ 38 | uint8_t m_sequences[12][37]; 39 | uint8_t m_remapping[37]; 40 | uint8_t m_chm[37]; 41 | int m_rlut[37]; 42 | int m_nchannels; 43 | int m_firstChannel; 44 | int m_secondChannel; 45 | 46 | /* Connection following parameters. */ 47 | int m_hopIncrement; 48 | int m_currentChannel; 49 | 50 | void generateSequence(int hopIncrement, uint8_t *sequence); 51 | int computeDistance(int hopIncrement, int firstChannel, int secondChannel); 52 | int findChannelIndex(int hopIncrement, int channel, int start); 53 | void generateLUT(uint8_t *lookupTable, int firstChannel, int secondChannel); 54 | 55 | public: 56 | 57 | /* Constructor. */ 58 | LegacySequenceGenerator(); 59 | 60 | /* Connection recovery routines. */ 61 | bool initialize(uint8_t *chm, uint32_t accessAddress); 62 | int getFirstChannel(void); 63 | int getSecondChannel(void); 64 | int getHopIncrement(int interval); 65 | 66 | /* Connection following. */ 67 | void setHopIncrement(int increment); 68 | void resetConnection(void); 69 | void prepareToFollow(void); 70 | void updateChannelMap(uint8_t *chm); 71 | int getNextChannel(void); 72 | int getCurrentChannel(void); 73 | uint8_t get_channel(uint16_t counter); 74 | int resolveCounter(uint32_t *measures, int count, uint8_t channel); 75 | 76 | 77 | 78 | }; 79 | 80 | 81 | class Ble5SequenceGenerator : public ISequenceGenerator 82 | { 83 | 84 | private: 85 | 86 | /* Recovery parameters. */ 87 | uint8_t m_chm[37]; 88 | int m_nChannels; 89 | uint16_t m_candidates[500]; 90 | int m_nCandidates; 91 | int m_totalHops; 92 | int m_hopInterval; 93 | 94 | /* Connection following parameters. */ 95 | uint32_t m_accessAddress; 96 | uint16_t m_chanId; 97 | uint16_t m_counter; 98 | 99 | /* Basic operations (PRNG) */ 100 | uint16_t channel_id(uint32_t accessAddress); 101 | uint16_t permute(uint16_t v); 102 | uint16_t mam(uint16_t a, uint16_t b); 103 | uint16_t unmapped_event_channel_selection(uint16_t counter, uint16_t chanid); 104 | uint8_t remap_channel(uint8_t channel); 105 | uint8_t get_channel(uint16_t counter, uint16_t chanid); 106 | 107 | 108 | 109 | public: 110 | 111 | /* Constructor. */ 112 | Ble5SequenceGenerator(); 113 | 114 | /* Connection recovery routines. */ 115 | bool initialize(uint8_t *chm, uint32_t accessAddress); 116 | uint8_t get_channel(uint16_t counter); 117 | int resolveCounter(uint32_t *measures, int count, uint8_t channel); 118 | 119 | /* Connection following. */ 120 | void resetConnection(void); 121 | void prepareToFollow(void); 122 | void updateChannelMap(uint8_t *chm); 123 | int getNextChannel(void); 124 | int getCurrentChannel(void); 125 | int getFirstChannel(void); 126 | int getSecondChannel(void); 127 | int getHopIncrement(int interval); 128 | void setHopIncrement(int increment); 129 | }; 130 | -------------------------------------------------------------------------------- /source/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | #include "link.h" 3 | 4 | /** 5 | * @brief Constructor 6 | * 7 | * Instanciate a CustomTimer: 8 | * - associate a specific channel to this CustomTimer instance 9 | * - relies on a single NRFLowLevelTimer able to handle 3 dedicated channels. 10 | **/ 11 | 12 | CustomTimer::CustomTimer() { 13 | /* Instanciate NRFLowLevelTimer if required. */ 14 | if (CustomTimer::m_timer == NULL) 15 | { 16 | /* Create our timer and enable it. */ 17 | CustomTimer::m_timer = new NRFLowLevelTimer(NRF_TIMER0, TIMER0_IRQn); 18 | CustomTimer::m_timer->setMode(TimerMode::TimerModeTimer); 19 | CustomTimer::m_timer->timer_pointer = CustomTimer::timer_callback; 20 | CustomTimer::m_timer->setClockSpeed(1000); /* 1MHz, 1us period. */ 21 | CustomTimer::m_timer->enable(); 22 | CustomTimer::m_timer->enableIRQ(); 23 | } 24 | 25 | /* Assign a channel to this timer. */ 26 | m_channel = CustomTimer::m_current_channel; 27 | CustomTimer::m_current_channel++; 28 | } 29 | 30 | /** 31 | * @brief Trigger a specific callback after a given period of time (in microseconds). 32 | * Callback is only called once. 33 | * @param pfn_callback Callback function to be called. 34 | * @param period Delay in microseconds. 35 | **/ 36 | 37 | void CustomTimer::attach_us(FCallback pfn_callback, uint32_t period) 38 | { 39 | /* Save period. */ 40 | m_periods[m_channel] = period; 41 | 42 | /* Save callback. */ 43 | CustomTimer::m_callbacks[m_channel] = pfn_callback; 44 | 45 | /* Save period. */ 46 | CustomTimer::m_timer->setCompare(m_channel, CustomTimer::m_timer->captureCounter() + m_periods[m_channel]); 47 | //CustomTimer::m_timer->offsetCompare(m_channel, /*CustomTimer::m_timer->captureCounter() + */m_periods[m_channel]); 48 | } 49 | 50 | 51 | /** 52 | * @brief Get associated channel number. 53 | * @return channel number (0-2) 54 | **/ 55 | 56 | int CustomTimer::get_channel(void) 57 | { 58 | return m_channel; 59 | } 60 | 61 | 62 | /** 63 | * @brief Rearm this timer (callback will be called once its delay passed). 64 | **/ 65 | 66 | void CustomTimer::rearm(void) 67 | { 68 | CustomTimer::m_timer->offsetCompare(m_channel, m_periods[m_channel]); 69 | } 70 | 71 | /** 72 | * @brief Clear timer, it will not be triggered anymore. 73 | **/ 74 | 75 | void CustomTimer::detach(void) 76 | { 77 | CustomTimer::m_timer->clearCompare(m_channel); 78 | } 79 | 80 | /** 81 | * @brief Internal callback used to dispatch timer interrupts. 82 | * 83 | * @param channel_bitmsk Channel bitmask indicating triggered timer channels. 84 | **/ 85 | 86 | void CustomTimer::timer_callback(uint16_t channel_bitmsk) 87 | { 88 | CustomTimer::m_timer->disableIRQ(); 89 | for (int i=0; iclearCompare(i); 95 | 96 | /* Trigger callback. */ 97 | CustomTimer::m_callbacks[i](); 98 | 99 | /* Rearm timer. */ 100 | //CustomTimer::m_timer->offsetCompare(i, m_periods[i]); 101 | } 102 | } 103 | CustomTimer::m_timer->enableIRQ(); 104 | } 105 | 106 | /* Static values. */ 107 | NRFLowLevelTimer *CustomTimer::m_timer = NULL; 108 | int CustomTimer::m_current_channel = 0; 109 | FCallback CustomTimer::m_callbacks[] = {NULL, NULL, NULL}; 110 | uint32_t CustomTimer::m_periods[] = {0, 0, 0}; 111 | -------------------------------------------------------------------------------- /source/timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Micro:Bit Custom Timer 3 | * 4 | * This module provides a CustomTimer class based on nRF52's NRF_TIMER0 5 | * (Hardware timer). 6 | * 7 | * When CustomTimer::attach_us() is called, it sets a callback function 8 | * that will be triggered once the specified delay passed. 9 | * 10 | * /!\/!\/!\/!\ 11 | * 12 | * Be careful: this callback is in charge of rearming the timer if required. 13 | * ------------------------------------------------------------------------- 14 | * 15 | **/ 16 | 17 | #ifndef __INC_TIMER_H 18 | #define __INC_TIMER_H 19 | 20 | #include "MicroBit.h" 21 | 22 | #define NB_CHANNELS_MAX 3 23 | 24 | /* Callback type. */ 25 | typedef void (*FCallback)(void); 26 | 27 | /* uBit object from PXT or CODAL. 28 | * TODO: MICROBIT_DAL_PXT will be added to PXT to replace this define */ 29 | #ifdef MICROBIT_DAL_FIBER_USER_DATA 30 | #include "pxt.h" 31 | #else 32 | extern MicroBit uBit; 33 | #endif 34 | 35 | class CustomTimer { 36 | 37 | private: 38 | static void timer_callback(uint16_t channel_bitmsk); 39 | int m_channel; 40 | 41 | static int m_current_channel; 42 | static FCallback m_callbacks[NB_CHANNELS_MAX]; 43 | static uint32_t m_periods[NB_CHANNELS_MAX]; 44 | static NRFLowLevelTimer *m_timer; 45 | 46 | public: 47 | CustomTimer(); 48 | int get_channel(void); 49 | 50 | /* Attach a callback to this timer that will be triggered after microseconds. */ 51 | void attach_us(FCallback pfn_callback, uint32_t period); 52 | 53 | /* Rearm timer. */ 54 | void rearm(void); 55 | 56 | /* Detach callback. */ 57 | void detach(void); 58 | }; 59 | 60 | #endif /* __INC_TIMER_H */ -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/virtualabs/btlejack-firmware-nrf52/30f03e7655c443b6fc3bbc40c8a149ec06af9653/utils/__init__.py -------------------------------------------------------------------------------- /utils/cmake/buildtools/codal.cmake: -------------------------------------------------------------------------------- 1 | add_executable( 2 | ${device.device} 3 | ${SOURCE_FILES} 4 | ) 5 | 6 | if("${INCLUDE_DIRS}" STRGREATER "") 7 | target_include_directories(${device.device} PUBLIC "${INCLUDE_DIRS}") 8 | endif() 9 | 10 | set_target_properties(${device.device} PROPERTIES SUFFIX "" ENABLE_EXPORTS ON) 11 | 12 | # link the executable with supporting libraries. 13 | target_link_libraries( 14 | ${device.device} 15 | ${CODAL_DEPS} 16 | ) 17 | 18 | # import toolchain bin generation command 19 | if(${device.generate_bin}) 20 | include(${TOOLCHAIN_FOLDER}/bin-generator.cmake) 21 | endif() 22 | 23 | # import toolchain hex generation command 24 | if(${device.generate_hex}) 25 | include(${TOOLCHAIN_FOLDER}/hex-generator.cmake) 26 | endif() 27 | 28 | # post process command hook, depends on the hex file generated by the build system. 29 | if("${device.post_process.command}" STRGREATER "" OR "${device.post_process}" STRGREATER "") 30 | 31 | if("${device.post_process}" STRGREATER "") 32 | set(POST_PROCESS_COMMAND ${device.post_process}) 33 | else() 34 | set(POST_PROCESS_COMMAND ${device.post_process.command}) 35 | endif() 36 | 37 | set(POST_PROCESS_DEPENDS "${device.post_process.depends}") 38 | 39 | # replace specific strings in the command, this gives users flexibility, they don't have to manually specify the location of files 40 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR}/${device.device}.hex CODAL_POSTPROCESS_COMMAND ${POST_PROCESS_COMMAND}) 41 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 42 | string(REPLACE "" ${device.device} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 43 | 44 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR}/${device.device}.bin CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 45 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 46 | string(REPLACE "" ${device.device}.bin CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 47 | 48 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/build/${device.device} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 49 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 50 | string(REPLACE "" ${device.device} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 51 | 52 | string(REPLACE "" ${PROJECT_SOURCE_DIR}/${CODAL_APP_OUTPUT_DIR} CODAL_POSTPROCESS_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 53 | 54 | #convert to a command 55 | separate_arguments(FINAL_COMMAND UNIX_COMMAND ${CODAL_POSTPROCESS_COMMAND}) 56 | 57 | # execute 58 | if(POST_PROCESS_DEPENDS STREQUAL "ELF") 59 | add_custom_command( 60 | TARGET ${device.device} 61 | COMMAND ${FINAL_COMMAND} 62 | DEPENDS ${device.device} 63 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" 64 | COMMENT "Executing post process command" 65 | ) 66 | elseif(POST_PROCESS_DEPENDS STREQUAL "HEX") 67 | add_custom_command( 68 | TARGET ${device.device}_hex 69 | COMMAND ${FINAL_COMMAND} 70 | DEPENDS ${device.device} 71 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" 72 | COMMENT "Executing post process command" 73 | ) 74 | else() 75 | #by default post process should depend on hex 76 | add_custom_command( 77 | TARGET ${device.device}_bin 78 | COMMAND ${FINAL_COMMAND} 79 | DEPENDS ${device.device} 80 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" 81 | COMMENT "Executing post process command" 82 | ) 83 | endif() 84 | 85 | endif() -------------------------------------------------------------------------------- /utils/cmake/buildtools/yotta.cmake: -------------------------------------------------------------------------------- 1 | if("${INCLUDE_DIRS}" STRGREATER "") 2 | target_include_directories(codal PUBLIC "${INCLUDE_DIRS}") 3 | endif() 4 | 5 | add_library(codal "${SOURCE_FILES}") 6 | set_target_properties(codal PROPERTIES SUFFIX "" ENABLE_EXPORTS ON) 7 | 8 | target_compile_definitions(codal PUBLIC "${device.definitions}") 9 | target_include_directories(codal PUBLIC ${PLATFORM_INCLUDES_PATH}) 10 | target_compile_options(codal PUBLIC -include ${EXTRA_INCLUDES_PATH}) 11 | 12 | set(STRIPPED "") 13 | string(STRIP "${CMAKE_LINKER_FLAGS}" STRIPPED) 14 | # link the executable with supporting libraries. 15 | target_link_libraries(codal "${CODAL_DEPS};${STRIPPED}") 16 | 17 | # 18 | # Supress the addition of implicit linker flags (such as -rdynamic) 19 | # 20 | set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 21 | set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") 22 | set(CMAKE_EXE_EXPORTS_C_FLAG "") 23 | set(CMAKE_EXE_EXPORTS_CXX_FLAG "") -------------------------------------------------------------------------------- /utils/cmake/colours.cmake: -------------------------------------------------------------------------------- 1 | if(NOT WIN32) 2 | string(ASCII 27 Esc) 3 | set(ColourReset "${Esc}[m") 4 | set(ColourBold "${Esc}[1m") 5 | set(Red "${Esc}[31m") 6 | set(Green "${Esc}[32m") 7 | set(Yellow "${Esc}[33m") 8 | set(Blue "${Esc}[34m") 9 | set(Magenta "${Esc}[35m") 10 | set(Cyan "${Esc}[36m") 11 | set(White "${Esc}[37m") 12 | set(BoldRed "${Esc}[1;31m") 13 | set(BoldGreen "${Esc}[1;32m") 14 | set(BoldYellow "${Esc}[1;33m") 15 | set(BoldBlue "${Esc}[1;34m") 16 | set(BoldMagenta "${Esc}[1;35m") 17 | set(BoldCyan "${Esc}[1;36m") 18 | set(BoldWhite "${Esc}[1;37m") 19 | endif() 20 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/ARM_GCC/bin-generator.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" 3 | COMMAND "${ARM_NONE_EABI_OBJCOPY}" -O binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" 4 | DEPENDS ${device.device} 5 | COMMENT "converting to bin file." 6 | ) 7 | 8 | #specify a dependency on the elf file so that bin is automatically rebuilt when elf is changed. 9 | add_custom_target(${device.device}_bin ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin") 10 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/ARM_GCC/compiler-flags.cmake: -------------------------------------------------------------------------------- 1 | set(EXPLICIT_INCLUDES "") 2 | if((CMAKE_VERSION VERSION_GREATER "3.4.0") OR (CMAKE_VERSION VERSION_EQUAL "3.4.0")) 3 | # from CMake 3.4 are separate to in the 4 | # CMAKE__COMPILE_OBJECT, CMAKE__CREATE_ASSEMBLY_SOURCE, and 5 | # CMAKE__CREATE_PREPROCESSED_SOURCE commands 6 | set(EXPLICIT_INCLUDES " ") 7 | endif() 8 | 9 | # Override the link rules: 10 | set(CMAKE_C_CREATE_SHARED_LIBRARY "echo 'shared libraries not supported' && 1") 11 | set(CMAKE_C_CREATE_SHARED_MODULE "echo 'shared modules not supported' && 1") 12 | set(CMAKE_C_CREATE_STATIC_LIBRARY " -cr ") 13 | set(CMAKE_C_COMPILE_OBJECT " ${EXPLICIT_INCLUDES} -o -c ") 14 | 15 | set(CMAKE_C_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lm -lc -lgcc -lm -lc -lgcc -Wl,--end-group --specs=nano.specs -o ") 16 | 17 | set(CMAKE_CXX_OUTPUT_EXTENSION ".o") 18 | set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT -MF ") 19 | set(CMAKE_C_OUTPUT_EXTENSION ".o") 20 | set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT -MF ") 21 | 22 | set(CMAKE_C_FLAGS_DEBUG_INIT "-g -gdwarf-3") 23 | set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 24 | set(CMAKE_C_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 25 | set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 26 | set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") 27 | 28 | 29 | set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g -gdwarf-3") 30 | set(CMAKE_ASM_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 31 | set(CMAKE_ASM_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 32 | set(CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 33 | set(CMAKE_INCLUDE_SYSTEM_FLAG_ASM "-isystem ") 34 | 35 | set(CMAKE_CXX_CREATE_STATIC_LIBRARY " -cr ") 36 | 37 | set(CMAKE_CXX_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lnosys -lstdc++ -lsupc++ -lm -lc -lgcc -lstdc++ -lsupc++ -lm -lc -lgcc -Wl,--end-group --specs=nano.specs -o ") 38 | 39 | set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -gdwarf-3") 40 | set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 41 | set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 42 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 43 | set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") 44 | 45 | if (CMAKE_C_COMPILER_VERSION VERSION_GREATER "7.1.0" OR CMAKE_C_COMPILER_VERSION VERSION_EQUAL "7.1.0") 46 | message("${BoldRed}Supressing -Wexpansion-to-defined.${ColourReset}") 47 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-expansion-to-defined") 48 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-expansion-to-defined") 49 | endif () -------------------------------------------------------------------------------- /utils/cmake/toolchains/ARM_GCC/hex-generator.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" 3 | COMMAND "${ARM_NONE_EABI_OBJCOPY}" -O ihex "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" 4 | DEPENDS ${device.device} 5 | COMMENT "converting to hex file." 6 | ) 7 | 8 | #specify a dependency on the elf file so that hex is automatically rebuilt when elf is changed. 9 | add_custom_target(${device.device}_hex ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex") 10 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/ARM_GCC/platform_includes.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORM_INCLUDES 2 | #define PLATFORM_INCLUDES 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/ARM_GCC/toolchain.cmake: -------------------------------------------------------------------------------- 1 | find_program(ARM_NONE_EABI_RANLIB arm-none-eabi-ranlib) 2 | find_program(ARM_NONE_EABI_AR arm-none-eabi-ar) 3 | find_program(ARM_NONE_EABI_GCC arm-none-eabi-gcc) 4 | find_program(ARM_NONE_EABI_GPP arm-none-eabi-g++) 5 | find_program(ARM_NONE_EABI_OBJCOPY arm-none-eabi-objcopy) 6 | 7 | set(CMAKE_OSX_SYSROOT "/") 8 | set(CMAKE_OSX_DEPLOYMENT_TARGET "") 9 | 10 | set(CMAKE_SYSTEM_NAME "Generic") 11 | set(CMAKE_SYSTEM_VERSION "2.0.0") 12 | 13 | set(CODAL_TOOLCHAIN "ARM_GCC") 14 | 15 | if(CMAKE_VERSION VERSION_LESS "3.5.0") 16 | include(CMakeForceCompiler) 17 | cmake_force_c_compiler("${ARM_NONE_EABI_GCC}" GNU) 18 | cmake_force_cxx_compiler("${ARM_NONE_EABI_GPP}" GNU) 19 | else() 20 | # from 3.5 the force_compiler macro is deprecated: CMake can detect 21 | # arm-none-eabi-gcc as being a GNU compiler automatically 22 | set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") 23 | set(CMAKE_C_COMPILER "${ARM_NONE_EABI_GCC}") 24 | set(CMAKE_CXX_COMPILER "${ARM_NONE_EABI_GPP}") 25 | endif() 26 | 27 | SET(CMAKE_AR "${ARM_NONE_EABI_AR}" CACHE FILEPATH "Archiver") 28 | SET(CMAKE_RANLIB "${ARM_NONE_EABI_RANLIB}" CACHE FILEPATH "rlib") 29 | set(CMAKE_CXX_OUTPUT_EXTENSION ".o") 30 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/AVR_GCC/bin-generator.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" 3 | COMMAND "${AVR_OBJCOPY}" -O binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" 4 | DEPENDS ${device.device} 5 | COMMENT "converting to bin file." 6 | ) 7 | 8 | #specify a dependency on the elf file so that bin is automatically rebuilt when elf is changed. 9 | add_custom_target(${device.device}_bin ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin") 10 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/AVR_GCC/compiler-flags.cmake: -------------------------------------------------------------------------------- 1 | set(EXPLICIT_INCLUDES "") 2 | if((CMAKE_VERSION VERSION_GREATER "3.4.0") OR (CMAKE_VERSION VERSION_EQUAL "3.4.0")) 3 | # from CMake 3.4 are separate to in the 4 | # CMAKE__COMPILE_OBJECT, CMAKE__CREATE_ASSEMBLY_SOURCE, and 5 | # CMAKE__CREATE_PREPROCESSED_SOURCE commands 6 | set(EXPLICIT_INCLUDES " ") 7 | endif() 8 | 9 | # Override the link rules: 10 | set(CMAKE_C_CREATE_SHARED_LIBRARY "echo 'shared libraries not supported' && 1") 11 | set(CMAKE_C_CREATE_SHARED_MODULE "echo 'shared modules not supported' && 1") 12 | set(CMAKE_C_CREATE_STATIC_LIBRARY " rcs ") 13 | set(CMAKE_C_COMPILE_OBJECT " ${EXPLICIT_INCLUDES} -o -c ") 14 | 15 | set(CMAKE_C_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lm -lc -lgcc -lm -lc -lgcc -Wl,--end-group --specs=nano.specs -o ") 16 | 17 | set(CMAKE_CXX_OUTPUT_EXTENSION ".o") 18 | set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT -MF ") 19 | set(CMAKE_C_OUTPUT_EXTENSION ".o") 20 | set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT -MF ") 21 | 22 | set(CMAKE_C_FLAGS_DEBUG_INIT "-g -gdwarf-3") 23 | set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 24 | set(CMAKE_C_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 25 | set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 26 | set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") 27 | 28 | 29 | set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g -gdwarf-3") 30 | set(CMAKE_ASM_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 31 | set(CMAKE_ASM_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 32 | set(CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 33 | set(CMAKE_INCLUDE_SYSTEM_FLAG_ASM "-isystem ") 34 | 35 | set(CMAKE_CXX_CREATE_STATIC_LIBRARY " rcs ") 36 | 37 | set(CMAKE_CXX_LINK_EXECUTABLE " -Wl,-Map,.map -Wl,--start-group -lm -lc -lgcc -Wl,--end-group -o ") 38 | 39 | set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -gdwarf-3") 40 | set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 41 | set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 42 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 43 | set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") 44 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/AVR_GCC/hex-generator.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" 3 | COMMAND "${AVR_OBJCOPY}" -O ihex "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" 4 | DEPENDS ${device.device} 5 | COMMENT "converting to hex file." 6 | ) 7 | 8 | #specify a dependency on the elf file so that hex is automatically rebuilt when elf is changed. 9 | add_custom_target(${device.device}_hex ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex") 10 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/AVR_GCC/platform_includes.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORM_INCLUDES 2 | #define PLATFORM_INCLUDES 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/AVR_GCC/toolchain.cmake: -------------------------------------------------------------------------------- 1 | find_program(AVR_GCC_RANLIB avr-gcc-ranlib) 2 | find_program(AVR_AR avr-ar) 3 | find_program(AVR_AS avr-as) 4 | find_program(AVR_GCC avr-gcc) 5 | find_program(AVR_GPP avr-g++) 6 | find_program(AVR_OBJCOPY avr-objcopy) 7 | 8 | set(CMAKE_OSX_SYSROOT "/") 9 | set(CMAKE_OSX_DEPLOYMENT_TARGET "") 10 | 11 | set(CODAL_TOOLCHAIN "AVR_GCC") 12 | 13 | if(CMAKE_VERSION VERSION_LESS "3.5.0") 14 | include(CMakeForceCompiler) 15 | cmake_force_c_compiler("${AVR_GCC}" GNU) 16 | cmake_force_cxx_compiler("${AVR_GPP}" GNU) 17 | else() 18 | #-Wl,-flto -flto -fno-fat-lto-objects 19 | # from 3.5 the force_compiler macro is deprecated: CMake can detect 20 | # arm-none-eabi-gcc as being a GNU compiler automatically 21 | set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") 22 | set(CMAKE_C_COMPILER "${AVR_GCC}") 23 | set(CMAKE_CXX_COMPILER "${AVR_GPP}") 24 | endif() 25 | 26 | SET(CMAKE_ASM_COMPILER "${AVR_GCC}") 27 | SET(CMAKE_AR "${AVR_AR}" CACHE FILEPATH "Archiver") 28 | SET(CMAKE_RANLIB "${AVR_GCC_RANLIB}" CACHE FILEPATH "rlib") 29 | set(CMAKE_CXX_OUTPUT_EXTENSION ".o") 30 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/XTENSA_GCC/bin-generator.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" 3 | COMMAND "${XTENSA_OBJCOPY}" -O binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin" 4 | DEPENDS ${device.device} 5 | COMMENT "converting to bin file." 6 | ) 7 | 8 | #specify a dependency on the elf file so that bin is automatically rebuilt when elf is changed. 9 | add_custom_target(${device.device}_bin ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.bin") 10 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/XTENSA_GCC/compiler-flags.cmake: -------------------------------------------------------------------------------- 1 | set(EXPLICIT_INCLUDES "") 2 | if((CMAKE_VERSION VERSION_GREATER "3.4.0") OR (CMAKE_VERSION VERSION_EQUAL "3.4.0")) 3 | # from CMake 3.4 are separate to in the 4 | # CMAKE__COMPILE_OBJECT, CMAKE__CREATE_ASSEMBLY_SOURCE, and 5 | # CMAKE__CREATE_PREPROCESSED_SOURCE commands 6 | set(EXPLICIT_INCLUDES " ") 7 | endif() 8 | 9 | # Override the link rules: 10 | set(CMAKE_C_CREATE_SHARED_LIBRARY "echo 'shared libraries not supported' && 1") 11 | set(CMAKE_C_CREATE_SHARED_MODULE "echo 'shared modules not supported' && 1") 12 | set(CMAKE_C_CREATE_STATIC_LIBRARY " -cr ") 13 | set(CMAKE_C_COMPILE_OBJECT " ${EXPLICIT_INCLUDES} -o -c ") 14 | 15 | set(CMAKE_C_LINK_EXECUTABLE " -nostdlib -Wl,-Map,.map -Wl,--start-group -lupgrade -lssl -lmesh -lwpa2 -lsmartconfig -lespnow -lpp -lmain -lwpa -llwip -lnet80211 -lwps -lcrypto -lphy -lhal -lgcc -ldriver -lm -lat -lc -lstdc++ -Wl,--end-group -lgcc -o ") 16 | 17 | set(CMAKE_CXX_OUTPUT_EXTENSION ".o") 18 | set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT -MF ") 19 | set(CMAKE_C_OUTPUT_EXTENSION ".o") 20 | set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT -MF ") 21 | 22 | set(CMAKE_C_FLAGS_DEBUG_INIT "-g -gdwarf-3") 23 | set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 24 | set(CMAKE_C_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 25 | set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 26 | set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") 27 | 28 | 29 | set(CMAKE_ASM_FLAGS_DEBUG_INIT "-g -gdwarf-3") 30 | set(CMAKE_ASM_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 31 | set(CMAKE_ASM_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 32 | set(CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 33 | set(CMAKE_INCLUDE_SYSTEM_FLAG_ASM "-isystem ") 34 | 35 | set(CMAKE_CXX_CREATE_STATIC_LIBRARY " -cr ") 36 | set(CMAKE_CXX_LINK_EXECUTABLE " -nostdlib -Wl,-Map,.map -Wl,--start-group -lupgrade -lssl -lmesh -lwpa2 -lsmartconfig -lespnow -lpp -lmain -lwpa -llwip -lnet80211 -lwps -lcrypto -ldriver -lat -lphy -lhal -lgcc -lm -lc -lstdc++ -o ") 37 | #set(CMAKE_CXX_LINK_EXECUTABLE " -nostdlib -Wl,-Map,.map -Wl,--start-group -lpwm -lupgrade -lssl -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lmain -llwip -lcrypto -lm -lc -o ") 38 | 39 | set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -gdwarf-3") 40 | set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") 41 | set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Os -DNDEBUG") 42 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-Os -g -gdwarf-3 -DNDEBUG") 43 | set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") 44 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/XTENSA_GCC/hex-generator.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command( 2 | OUTPUT "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" 3 | COMMAND "${ARM_NONE_EABI_OBJCOPY}" -O ihex "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${device.device}" "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex" 4 | DEPENDS ${device.device} 5 | COMMENT "converting to hex file." 6 | ) 7 | 8 | #specify a dependency on the elf file so that hex is automatically rebuilt when elf is changed. 9 | add_custom_target(${device.device}_hex ALL DEPENDS "${PROJECT_SOURCE_DIR}/${codal.output_folder}/${device.device}.hex") 10 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/XTENSA_GCC/platform_includes.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORM_INCLUDES 2 | #define PLATFORM_INCLUDES 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /utils/cmake/toolchains/XTENSA_GCC/toolchain.cmake: -------------------------------------------------------------------------------- 1 | find_program(XTENSA_RANLIB xtensa-lx106-elf-gcc-ranlib) 2 | find_program(XTENSA_AR xtensa-lx106-elf-gcc-ar) 3 | find_program(XTENSA_GCC xtensa-lx106-elf-gcc) 4 | find_program(XTENSA_GPP xtensa-lx106-elf-g++) 5 | find_program(XTENSA_OBJCOPY xtensa-lx106-elf-objcopy) 6 | 7 | set(CMAKE_OSX_SYSROOT "/") 8 | set(CMAKE_OSX_DEPLOYMENT_TARGET "") 9 | 10 | set(CODAL_TOOLCHAIN "XTENSA_GCC") 11 | 12 | if(CMAKE_VERSION VERSION_LESS "3.5.0") 13 | include(CMakeForceCompiler) 14 | cmake_force_c_compiler("${XTENSA_GCC}" GNU) 15 | cmake_force_cxx_compiler("${XTENSA_GPP}" GNU) 16 | else() 17 | # from 3.5 the force_compiler macro is deprecated: CMake can detect 18 | # arm-none-eabi-gcc as being a GNU compiler automatically 19 | set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") 20 | set(CMAKE_C_COMPILER "${XTENSA_GCC}") 21 | set(CMAKE_CXX_COMPILER "${XTENSA_GPP}") 22 | endif() 23 | 24 | SET(CMAKE_AR "${XTENSA_AR}" CACHE FILEPATH "Archiver") 25 | SET(CMAKE_RANLIB "${XTENSA_RANLIB}" CACHE FILEPATH "rlib") 26 | set(CMAKE_CXX_OUTPUT_EXTENSION ".o") 27 | -------------------------------------------------------------------------------- /utils/cmake/util.cmake: -------------------------------------------------------------------------------- 1 | MACRO(RECURSIVE_FIND_DIR return_list dir pattern) 2 | FILE(GLOB_RECURSE new_list "${dir}/${pattern}") 3 | SET(dir_list "") 4 | FOREACH(file_path ${new_list}) 5 | GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) 6 | SET(dir_list ${dir_list} ${dir_path}) 7 | ENDFOREACH() 8 | LIST(REMOVE_DUPLICATES dir_list) 9 | SET(${return_list} ${dir_list}) 10 | ENDMACRO() 11 | 12 | MACRO(RECURSIVE_FIND_FILE return_list dir pattern) 13 | FILE(GLOB_RECURSE new_list "${dir}/${pattern}") 14 | SET(dir_list "") 15 | FOREACH(file_path ${new_list}) 16 | SET(dir_list ${dir_list} ${file_path}) 17 | ENDFOREACH() 18 | LIST(REMOVE_DUPLICATES dir_list) 19 | SET(${return_list} ${dir_list}) 20 | ENDMACRO() 21 | 22 | MACRO(SOURCE_FILES return_list dir pattern) 23 | FILE(GLOB new_list "${dir}/${pattern}") 24 | SET(dir_list "") 25 | FOREACH(file_path ${new_list}) 26 | LIST(APPEND dir_list ${file_path}) 27 | ENDFOREACH() 28 | LIST(REMOVE_DUPLICATES dir_list) 29 | SET(${return_list} ${dir_list}) 30 | ENDMACRO() 31 | 32 | function(EXTRACT_JSON_ARRAY json_file json_field_path fields values) 33 | 34 | set(VALUES "") 35 | set(FIELDS "") 36 | 37 | foreach(var ${${json_file}}) 38 | # extract any cmd line definitions specified in the json object, and add them 39 | # if it is not prefixed by json_field_path, do not consider the key. 40 | if("${var}" MATCHES "${json_field_path}") 41 | string(REGEX MATCH "[^${json_field_path}]([A-Z,a-z,0-9,_,]+)" VALUE "${var}") 42 | 43 | # never quote the value - gives more flexibility 44 | list(APPEND FIELDS ${VALUE}) 45 | list(APPEND VALUES "${${var}}") 46 | endif() 47 | endforeach() 48 | 49 | set(${fields} ${FIELDS} PARENT_SCOPE) 50 | set(${values} ${VALUES} PARENT_SCOPE) 51 | endfunction() 52 | 53 | function(FORM_DEFINITIONS fields values definitions) 54 | 55 | set(DEFINITIONS "") 56 | list(LENGTH ${fields} LEN) 57 | 58 | # - 1 for for loop index... 59 | MATH(EXPR LEN "${LEN}-1") 60 | 61 | foreach(i RANGE ${LEN}) 62 | list(GET ${fields} ${i} DEFINITION) 63 | list(GET ${values} ${i} VALUE) 64 | 65 | set(DEFINITIONS "${DEFINITIONS} #define ${DEFINITION}\t ${VALUE}\n") 66 | endforeach() 67 | 68 | set(${definitions} ${DEFINITIONS} PARENT_SCOPE) 69 | endfunction() 70 | 71 | function(UNIQUE_JSON_KEYS priority_fields priority_values secondary_fields secondary_values merged_fields merged_values) 72 | 73 | # always keep the first fields and values 74 | set(MERGED_FIELDS ${${priority_fields}}) 75 | set(MERGED_VALUES ${${priority_values}}) 76 | 77 | # measure the second set... 78 | list(LENGTH ${secondary_fields} LEN) 79 | # - 1 for for loop index... 80 | MATH(EXPR LEN "${LEN}-1") 81 | 82 | # iterate, dropping any duplicate fields regardless of the value 83 | foreach(i RANGE ${LEN}) 84 | list(GET ${secondary_fields} ${i} FIELD) 85 | list(GET ${secondary_values} ${i} VALUE) 86 | 87 | list(FIND MERGED_FIELDS ${FIELD} INDEX) 88 | 89 | if (${INDEX} GREATER -1) 90 | continue() 91 | endif() 92 | 93 | list(APPEND MERGED_FIELDS ${FIELD}) 94 | list(APPEND MERGED_VALUES ${VALUE}) 95 | endforeach() 96 | 97 | set(${merged_fields} ${MERGED_FIELDS} PARENT_SCOPE) 98 | set(${merged_values} ${MERGED_VALUES} PARENT_SCOPE) 99 | endfunction() 100 | 101 | MACRO(HEADER_FILES return_list dir) 102 | FILE(GLOB new_list "${dir}/*.h") 103 | SET(${return_list} ${new_list}) 104 | ENDMACRO() 105 | 106 | function(INSTALL_DEPENDENCY dir name url branch type) 107 | if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${dir}") 108 | message("Creating libraries folder") 109 | FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/${dir}") 110 | endif() 111 | 112 | if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${dir}/${name}") 113 | message("${name} is already installed") 114 | return() 115 | endif() 116 | 117 | if(${type} STREQUAL "git") 118 | message("Cloning into: ${url}") 119 | # git clone -b doesn't work with SHAs 120 | execute_process( 121 | COMMAND git clone --recurse-submodules ${url} ${name} 122 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir} 123 | ) 124 | 125 | if(NOT "${branch}" STREQUAL "") 126 | message("Checking out branch: ${branch}") 127 | execute_process( 128 | COMMAND git -c advice.detachedHead=false checkout ${branch} 129 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} 130 | ) 131 | execute_process( 132 | COMMAND git submodule update --init 133 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} 134 | ) 135 | execute_process( 136 | COMMAND git submodule sync 137 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} 138 | ) 139 | execute_process( 140 | COMMAND git submodule update 141 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir}/${name} 142 | ) 143 | endif() 144 | else() 145 | message("No mechanism exists to install this library.") 146 | endif() 147 | endfunction() 148 | 149 | MACRO(SUB_DIRS return_dirs dir) 150 | FILE(GLOB list "${PROJECT_SOURCE_DIR}/${dir}/*") 151 | SET(dir_list "") 152 | FOREACH(file_path ${list}) 153 | SET(dir_list ${dir_list} ${file_path}) 154 | ENDFOREACH() 155 | set(${return_dirs} ${dir_list}) 156 | ENDMACRO() 157 | -------------------------------------------------------------------------------- /utils/debug/dmesg.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | let fs = require("fs") 5 | let child_process = require("child_process") 6 | 7 | function fatal(msg) { 8 | console.log("Fatal error:", msg) 9 | process.exit(1) 10 | } 11 | 12 | function main() { 13 | let mapFileName = process.argv[2] 14 | if (!mapFileName) { 15 | console.log("usage: node " + process.argv[1] + " build/mytarget/source/myprog.map") 16 | return 17 | } 18 | console.log("Map file: " + mapFileName) 19 | let mapFile = fs.readFileSync(mapFileName, "utf8") 20 | let addr = 0 21 | let logSize = 1024 * 4 + 4 22 | for (let ln of mapFile.split(/\r?\n/)) { 23 | let m = /^\s*0x00000([0-9a-f]+)\s+(\S+)/.exec(ln) 24 | if (m && m[2] == "codalLogStore") { 25 | addr = parseInt(m[1], 16) 26 | break 27 | } 28 | } 29 | if (!addr) fatal("Cannot find codalLogStore symbol in map file") 30 | 31 | let dirs = [ 32 | process.env["HOME"] + "/Library/Arduino15", 33 | process.env["USERPROFILE"] + "/AppData/Local/Arduino15", 34 | process.env["HOME"] + "/.arduino15", 35 | ] 36 | 37 | let pkgDir = "" 38 | 39 | for (let d of dirs) { 40 | pkgDir = d + "/packages/arduino/" 41 | if (fs.existsSync(pkgDir)) break 42 | pkgDir = "" 43 | } 44 | 45 | if (!pkgDir) fatal("cannot find Arduino packages directory") 46 | 47 | let openocdPath = pkgDir + "tools/openocd/0.9.0-arduino/" 48 | if (!fs.existsSync(openocdPath)) fatal("openocd not installed in Arduino") 49 | 50 | let openocdBin = openocdPath + "bin/openocd" 51 | 52 | if (process.platform == "win32") 53 | openocdBin += ".exe" 54 | 55 | let zeroCfg = pkgDir + "hardware/samd/1.6.8/variants/arduino_zero/openocd_scripts/arduino_zero.cfg" 56 | let cmd = `init; set M(0) 0; mem2array M 8 ${addr} ${logSize}; parray M; exit` 57 | 58 | console.log("Starting openocd") 59 | child_process.execFile(openocdBin, ["-d2", 60 | "-s", openocdPath + "/share/openocd/scripts/", 61 | "-f", zeroCfg, 62 | "-c", cmd], { 63 | maxBuffer: 1 * 1024 * 1024, 64 | }, (err, stdout, stderr) => { 65 | if (err) { 66 | fatal("error: " + err.message) 67 | } 68 | let buf = new Buffer(logSize) 69 | for (let l of stdout.split(/\r?\n/)) { 70 | let m = /^M\((\d+)\)\s*=\s*(\d+)/.exec(l) 71 | if (m) { 72 | buf[parseInt(m[1])] = parseInt(m[2]) 73 | } 74 | } 75 | let len = buf.readUInt32LE(0) 76 | if (len == 0 || len > buf.length) { 77 | console.log(stderr) 78 | console.log("No logs.") 79 | } else { 80 | console.log("*\n* Logs\n*\n") 81 | console.log(buf.slice(4, 4 + len).toString("binary")) 82 | } 83 | }) 84 | } 85 | 86 | main() -------------------------------------------------------------------------------- /utils/debug/meminfo.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | function main() { 5 | let fs = require("fs"); 6 | let mfn = process.argv[2] 7 | if (!mfn) { 8 | console.log("usage: node " + process.argv[1] + " build/mytarget/source/myprog.map") 9 | return 10 | } 11 | console.log("Map file: " + mfn) 12 | let map = fs.readFileSync(mfn, "utf8") 13 | let inSect = 0 14 | let byFileRAM = {} 15 | let byFileROM = {} 16 | for (let ln of map.split(/\r?\n/)) { 17 | if (ln == "Linker script and memory map") { 18 | inSect = 1 19 | } 20 | if (/^OUTPUT\(/.test(ln)) { 21 | inSect = 2 22 | } 23 | if (inSect == 1) { 24 | let m = /^\s*(\S*)\s+0x00000([0-9a-f]+)\s+0x([0-9a-f]+)\s+(\S+)/.exec(ln) 25 | if (m) { 26 | let mark = m[1] 27 | if (mark == "*fill*" || mark == ".bss" || mark == ".relocate") 28 | continue; 29 | let addr = parseInt(m[2], 16) 30 | let sz = parseInt(m[3], 16) 31 | let fn = m[4] 32 | if (fn == "load" && mark) fn = mark; 33 | fn = fn.replace(/.*armv6-m/, "") 34 | if (sz) { 35 | let mm = addr < 0x10000000 ? byFileROM : byFileRAM 36 | mm[fn] = (mm[fn] || 0) + sz 37 | } 38 | } 39 | } 40 | } 41 | 42 | console.log("*\n* ROM\n*") 43 | dumpMap(byFileROM) 44 | console.log("*\n* RAM\n*") 45 | dumpMap(byFileRAM) 46 | } 47 | 48 | function printEnt(sz, s) { 49 | let ff = (" " + sz).slice(-7) 50 | console.log(ff + " " + s) 51 | } 52 | 53 | function dumpMap(m) { 54 | let k = Object.keys(m) 55 | k.sort((a, b) => m[a] - m[b]) 56 | let sum = 0 57 | for (let s of k) { 58 | printEnt(m[s], s) 59 | sum += m[s] 60 | } 61 | printEnt(sum, "TOTAL") 62 | } 63 | 64 | 65 | main() -------------------------------------------------------------------------------- /utils/generate_libraries.py: -------------------------------------------------------------------------------- 1 | import os 2 | import git 3 | from git import Actor 4 | import optparse 5 | import fnmatch 6 | import glob 7 | import shutil 8 | import ntpath 9 | import json 10 | 11 | def make_cmake(lib_name, lib_file_name, include_path, dest): 12 | print "LIB NAME " + lib_name 13 | with open(dest + "/CMakeLists.txt", 'w') as f: 14 | lines = [ 15 | "project(" + lib_name + ")\r\n" 16 | "add_library(" + lib_name + " STATIC " + lib_file_name + ")\r\n", 17 | "set_target_properties(" + lib_name +" PROPERTIES LINKER_LANGUAGE CXX)\r\n", 18 | "target_include_directories(" + lib_name + " PUBLIC \"" + include_path + "\")\r\n", 19 | ] 20 | print "LINES : " + str(lines) 21 | f.writelines(lines) 22 | f.close() 23 | 24 | def copytree(src, dst, symlinks=False, ignore=None): 25 | if not os.path.exists(dst): 26 | os.makedirs(dst) 27 | for item in os.listdir(src): 28 | s = os.path.join(src, item) 29 | d = os.path.join(dst, item) 30 | if os.path.isdir(s): 31 | copytree(s, d, symlinks, ignore) 32 | else: 33 | if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1: 34 | shutil.copy2(s, d) 35 | 36 | def path_leaf(path): 37 | head, tail = ntpath.split(path) 38 | return tail or ntpath.basename(head) 39 | 40 | def recursive_glob(treeroot, pattern): 41 | results = [] 42 | for base, dirs, files in os.walk(treeroot): 43 | goodfiles = fnmatch.filter(files, pattern) 44 | results.extend(os.path.join(base, f) for f in goodfiles) 45 | return results 46 | 47 | parser = optparse.OptionParser() 48 | parser.add_option('-c', '--clean', dest='clean', action="store_true", help='Whether to clean before building.', default=False) 49 | 50 | (options, args) = parser.parse_args() 51 | 52 | os.chdir("..") 53 | 54 | if not os.path.exists("build"): 55 | os.mkdir("build") 56 | 57 | # out of source build! 58 | os.chdir("build") 59 | 60 | # configure os.system("cmake ..") 61 | os.system("cmake .. -DCODAL_HEADER_EXTRACTION:BOOL=TRUE") 62 | 63 | if options.clean: 64 | os.system("make clean") 65 | 66 | # build 67 | os.system("make -j 10") 68 | 69 | with open('../codal.json') as data_file: 70 | codal = json.load(data_file) 71 | 72 | #ntpath.basename(f) 73 | folders = [path_leaf(f) for f in glob.glob("../libraries/*/")] 74 | header_folders = [path_leaf(f) for f in glob.glob("./build/*/")] 75 | 76 | print folders 77 | print header_folders 78 | 79 | mapping = [] 80 | 81 | #note for next time, need to copy all lib files to their appropriate build/lib place otherwise they get auto cleaned. 82 | 83 | valid_libs = [] 84 | 85 | for folder in header_folders: 86 | lib_file_name = "lib" + folder + ".a" 87 | if not os.path.exists("./"+lib_file_name): 88 | print "No library exists, skipping: " + lib_file_name 89 | continue 90 | 91 | shutil.copy("./" + lib_file_name, "./build/"+folder) 92 | valid_libs = valid_libs + [folder] 93 | 94 | 95 | for folder in valid_libs: 96 | lib_name = folder 97 | lib_file_name = "lib" + folder + ".a" 98 | folder_path = '../libraries/' + folder 99 | header_folder = "./build/" + folder 100 | header_ext = "includes" 101 | 102 | with open(folder_path + "CMakeLists.txt") as cmake: 103 | 104 | "target_link_libraries\((?:\s*(.+))+\s*\)" 105 | 106 | for line in cmake.lines(): 107 | if "target_link_libraries" in line 108 | 109 | 110 | 111 | # get the repo 112 | try: 113 | repo = git.Repo('../libraries/' + folder) 114 | except: 115 | print folder + " is not a valid git repository." 116 | continue 117 | 118 | active_branch = repo.active_branch.name 119 | 120 | # check for any uncommitted changes 121 | if len(repo.index.diff(None)) > 0 : 122 | print folder + " has uncommitted changes, skipping." 123 | continue; 124 | 125 | branch_names = [b.name for b in repo.branches] 126 | 127 | lib_branch_name = "lib_" + codal["target"]["processor"] + codal["target"]["device"] 128 | 129 | # tag using above + version specified in target.json 130 | 131 | # swap to an orphaned branch if none exists 132 | if lib_branch_name not in branch_names: 133 | repo.active_branch.checkout(orphan=lib_branch_name) 134 | 135 | for f in glob.glob(folder_path + "/*/"): 136 | shutil.rmtree(f) 137 | 138 | files = [f for f in os.listdir('.') if os.path.isfile(f)] 139 | 140 | for file in files: 141 | os.remove(file) 142 | else: 143 | repo.active_branch.checkout(lib_branch_name) 144 | 145 | repo.index.remove("*", r=True) 146 | 147 | copytree(header_folder, folder_path + "/") 148 | 149 | make_cmake(lib_name, lib_file_name, header_ext, folder_path + "/") 150 | 151 | repo.index.add("*") 152 | 153 | author = Actor("codal", "codal@example.com") 154 | 155 | repo.index.commit("Library generated", author=author, committer=author) 156 | 157 | #repo.git.checkout(active_branch) 158 | 159 | #break 160 | -------------------------------------------------------------------------------- /utils/merge_hex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2015 ARM Limited 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """This script will merge two hex files and write the output to a hex file. 18 | USAGE: merge_hex.py input_file1 input_file2 output_file. 19 | """ 20 | 21 | from optparse import OptionParser 22 | import sys 23 | 24 | parser = OptionParser() 25 | 26 | #command line options 27 | parser.add_option("-o", "--output", 28 | action="store", 29 | type="string", 30 | dest="output", 31 | default="", 32 | help="The relative path to the headers for the microbit-dal.") 33 | 34 | (options, args) = parser.parse_args() 35 | 36 | fail_color = '' 37 | 38 | # If colorama is present, set the fail color to red 39 | try: 40 | from colorama import init, deinit, Fore 41 | fail_color = Fore.RED 42 | except: 43 | pass 44 | 45 | def fail(message): 46 | print(fail_color + message) 47 | 48 | # If we've included ANSI color in output, reset the output style 49 | if fail_color: 50 | print(Fore.RESET) 51 | deinit() 52 | 53 | return 1 54 | 55 | def convert_start_addr(hex_file): 56 | if hex_file.start_addr and 'CS' in hex_file.start_addr: 57 | start_addr = {'EIP': (hex_file.start_addr['CS'] * 16) + hex_file.start_addr['IP']} 58 | hex_file.start_addr = start_addr 59 | 60 | def main(options, args): 61 | # If using ANSI coloring is available, initialize colorama 62 | if fail_color: 63 | init() 64 | 65 | # Import intelhex if avaialable, otherwise fail 66 | try: 67 | from intelhex import IntelHex 68 | except: 69 | return fail('error: You do not have \'intelhex\' installed. Please run \'pip install intelhex\' then retry.') 70 | 71 | if len(options.output) is 0: 72 | print "No output file specified" 73 | exit(1) 74 | 75 | if len(args) < 2: 76 | return fail('Only one file was provided to merge.') 77 | exit(0) 78 | 79 | # Get the two hex files, merge them, and save the result 80 | orig = IntelHex(args[0]) 81 | convert_start_addr(orig) 82 | 83 | args = args[1:] 84 | 85 | for arg in args: 86 | other = IntelHex(arg) 87 | convert_start_addr(other) 88 | orig.merge(other, overlap='replace') 89 | 90 | orig.write_hex_file(options.output) 91 | 92 | if __name__ == '__main__': 93 | sys.exit(main(options,args)) 94 | -------------------------------------------------------------------------------- /utils/python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/virtualabs/btlejack-firmware-nrf52/30f03e7655c443b6fc3bbc40c8a149ec06af9653/utils/python/__init__.py -------------------------------------------------------------------------------- /utils/python/codal_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import optparse 4 | import platform 5 | import json 6 | import shutil 7 | import re 8 | 9 | import os, re, json, xml.etree.ElementTree 10 | from optparse import OptionParser 11 | 12 | 13 | def system(cmd): 14 | if os.system(cmd) != 0: 15 | sys.exit(1) 16 | 17 | def build(clean, verbose = False): 18 | if platform.system() == "Windows": 19 | # configure 20 | system("cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G \"Ninja\"") 21 | 22 | # build 23 | system("ninja") 24 | else: 25 | # configure 26 | system("cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G \"Unix Makefiles\"") 27 | 28 | if clean: 29 | system("make clean") 30 | 31 | # build 32 | if verbose: 33 | system("make -j 10 VERBOSE=1") 34 | else: 35 | system("make -j 10") 36 | 37 | def read_json(fn): 38 | json_file = "" 39 | with open(fn) as f: 40 | json_file = f.read() 41 | return json.loads(json_file) 42 | 43 | def checkgit(): 44 | stat = os.popen('git status --porcelain').read().strip() 45 | if stat != "": 46 | print("Missing checkin in", os.getcwd(), "\n" + stat) 47 | exit(1) 48 | 49 | def read_config(): 50 | codal = read_json("codal.json") 51 | targetdir = codal['target']['name'] 52 | target = read_json("libraries/" + targetdir + "/target.json") 53 | return (codal, targetdir, target) 54 | 55 | def update(allow_detached=False): 56 | (codal, targetdir, target) = read_config() 57 | dirname = os.getcwd() 58 | for ln in target['libraries']: 59 | os.chdir(dirname + "/libraries/" + ln['name']) 60 | system("git checkout " + ln['branch']) 61 | system("git pull") 62 | os.chdir(dirname + "/libraries/" + targetdir) 63 | if ("HEAD detached" in os.popen('git branch').read().strip() and 64 | allow_detached == False): 65 | system("git checkout master") 66 | system("git pull") 67 | os.chdir(dirname) 68 | 69 | def revision(rev): 70 | (codal, targetdir, target) = read_config() 71 | dirname = os.getcwd() 72 | os.chdir("libraries/" + targetdir) 73 | system("git checkout " + rev) 74 | os.chdir(dirname) 75 | update(True) 76 | 77 | def printstatus(): 78 | print("\n***%s" % os.getcwd()) 79 | system("git status -s") 80 | system("git rev-parse HEAD") 81 | system("git branch") 82 | 83 | def status(): 84 | (codal, targetdir, target) = read_config() 85 | dirname = os.getcwd() 86 | for ln in target['libraries']: 87 | os.chdir(dirname + "/libraries/" + ln['name']) 88 | printstatus() 89 | os.chdir(dirname + "/libraries/" + targetdir) 90 | printstatus() 91 | os.chdir(dirname) 92 | printstatus() 93 | 94 | def get_next_version(options): 95 | if options.version: 96 | return options.version 97 | log = os.popen('git log -n 100').read().strip() 98 | m = re.search('Snapshot v(\d+)\.(\d+)\.(\d+)(-([\w\-]+).(\d+))?', log) 99 | if m is None: 100 | print("Cannot determine next version from git log") 101 | exit(1) 102 | v0 = int(m.group(1)) 103 | v1 = int(m.group(2)) 104 | v2 = int(m.group(3)) 105 | vB = -1 106 | branchName = os.popen('git rev-parse --abbrev-ref HEAD').read().strip() 107 | if not options.branch and branchName != "master": 108 | print("On non-master branch use -l -b") 109 | exit(1) 110 | suff = "" 111 | if options.branch: 112 | if m.group(4) and branchName == m.group(5): 113 | vB = int(m.group(6)) 114 | suff = "-%s.%d" % (branchName, vB + 1) 115 | elif options.update_major: 116 | v0 += 1 117 | v1 = 0 118 | v2 = 0 119 | elif options.update_minor: 120 | v1 += 1 121 | v2 = 0 122 | else: 123 | v2 += 1 124 | return "v%d.%d.%d%s" % (v0, v1, v2, suff) 125 | 126 | def lock(options): 127 | (codal, targetdir, target) = read_config() 128 | dirname = os.getcwd() 129 | for ln in target['libraries']: 130 | os.chdir(dirname + "/libraries/" + ln['name']) 131 | checkgit() 132 | stat = os.popen('git status --porcelain -b').read().strip() 133 | if "ahead" in stat: 134 | print("Missing push in", os.getcwd()) 135 | exit(1) 136 | sha = os.popen('git rev-parse HEAD').read().strip() 137 | ln['branch'] = sha 138 | print(ln['name'], sha) 139 | os.chdir(dirname + "/libraries/" + targetdir) 140 | ver = get_next_version(options) 141 | print("Creating snaphot", ver) 142 | system("git checkout target-locked.json") 143 | checkgit() 144 | target["snapshot_version"] = ver 145 | with open("target-locked.json", "w") as f: 146 | f.write(json.dumps(target, indent=4, sort_keys=True)) 147 | system("git commit -am \"Snapshot %s\"" % ver) # must match get_next_version() regex 148 | sha = os.popen('git rev-parse HEAD').read().strip() 149 | system("git tag %s" % ver) 150 | system("git pull") 151 | system("git push") 152 | system("git push --tags") 153 | os.chdir(dirname) 154 | print("\nNew snapshot: %s [%s]" % (ver, sha)) 155 | 156 | def delete_build_folder(in_folder = True): 157 | if in_folder: 158 | os.chdir("..") 159 | 160 | shutil.rmtree('./build') 161 | os.mkdir("./build") 162 | 163 | if in_folder: 164 | os.chdir("./build") 165 | 166 | def generate_docs(): 167 | from doc_gen.doxygen_extractor import DoxygenExtractor 168 | from doc_gen.md_converter import MarkdownConverter 169 | from doc_gen.system_utils import SystemUtils 170 | from doc_gen.doc_gen import generate_mkdocs 171 | 172 | os.chdir("..") 173 | (codal, targetdir, target) = read_config() 174 | 175 | lib_dir = os.getcwd() + "/libraries/" 176 | 177 | libraries = [lib_dir + targetdir] 178 | 179 | for l in target["libraries"]: 180 | libraries = libraries + [ lib_dir + l["name"]] 181 | 182 | os.chdir(lib_dir + targetdir) 183 | 184 | generate_mkdocs(libraries) 185 | 186 | 187 | -------------------------------------------------------------------------------- /utils/python/doc_gen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/virtualabs/btlejack-firmware-nrf52/30f03e7655c443b6fc3bbc40c8a149ec06af9653/utils/python/doc_gen/__init__.py -------------------------------------------------------------------------------- /utils/python/doc_gen/doc_gen.py: -------------------------------------------------------------------------------- 1 | import os, re, json, xml.etree.ElementTree 2 | from optparse import OptionParser 3 | 4 | from doxygen_extractor import DoxygenExtractor 5 | from md_converter import MarkdownConverter 6 | from system_utils import SystemUtils 7 | 8 | member_func_filter = ["idleCallback", "systemCallback", "~"] 9 | 10 | filters = True 11 | 12 | utils = SystemUtils() 13 | 14 | ### 15 | # the trigger for generating our documentation 16 | ### 17 | def generate_mkdocs(header_paths, type_colour = "#a71d5d", function_name_colour = "#795da3"): 18 | 19 | global member_func_filter 20 | doxygen = DoxygenExtractor(os.path.abspath("."), header_paths) 21 | markdown = MarkdownConverter(type_colour, function_name_colour, separate_defaults = True, display_defaults = False) 22 | 23 | doxygen.generate_doxygen() 24 | #utils.validate_version(doxygen.working_dir, header_paths, "./docs/archive") 25 | 26 | file_names = utils.find_files('docs','*.md') 27 | section_kind = ["public-func"] 28 | meta_data_regex = re.compile( r'\[comment\]: <> \((.*?)\)', re.MULTILINE | re.DOTALL ) 29 | 30 | for filename in file_names: 31 | print(filename) 32 | 33 | read_lines = utils.read(filename) 34 | 35 | file_lines = markdown.clean(read_lines, meta_data_regex) 36 | 37 | utils.write(filename, file_lines) 38 | 39 | previous = "" 40 | 41 | for line_number, line in enumerate(file_lines, 1): 42 | 43 | result = re.findall(meta_data_regex,line) 44 | 45 | if len(result) is not 0: 46 | 47 | meta_data = json.loads(result[0]) 48 | 49 | if previous is not "" and "end" in meta_data.keys() and meta_data['end'] == previous: 50 | previous = "" 51 | continue 52 | elif previous is "": 53 | try: 54 | previous = meta_data['className'] 55 | except: 56 | raise Exception('There isn\'t a match for the meta_data '+ meta_data) 57 | else: 58 | raise Exception('There isn\'t a match for the meta_data \''+ previous + "'") 59 | 60 | local_filter = member_func_filter 61 | 62 | if "filter" in meta_data: 63 | for member_function in meta_data["filter"]: 64 | local_filter = local_filter + [ str(member_function) ] 65 | 66 | print "Custom filter applied: " + str(member_func_filter) 67 | 68 | class_xml_files = list(utils.find_files("./xml","*class*"+meta_data['className'] + ".xml")) 69 | 70 | print class_xml_files 71 | 72 | if len(class_xml_files) == 0: 73 | raise Exception("Invalid classname: " + meta_data['className']) 74 | elif len(class_xml_files) > 1: 75 | class_xml_files 76 | 77 | doxygen_class_xml = xml.etree.ElementTree.parse(class_xml_files[0]).getroot() 78 | 79 | member_functions = [] 80 | 81 | for section_def in doxygen_class_xml.iter('sectiondef'): 82 | if section_def.attrib['kind'] in section_kind: 83 | for member_func in section_def.iter('memberdef'): 84 | new_member = doxygen.extract_member_function(member_func, local_filter, filter= filters) 85 | if new_member is not None: 86 | member_functions.append(new_member) 87 | 88 | before = file_lines[:line_number] 89 | after = file_lines[line_number:] 90 | 91 | between = markdown.gen_member_func_doc(meta_data['className'], member_functions) 92 | 93 | utils.write(filename, before + between + after) 94 | -------------------------------------------------------------------------------- /utils/python/doc_gen/doxygen_extractor.py: -------------------------------------------------------------------------------- 1 | import os 2 | from system_utils import SystemUtils 3 | 4 | class DoxygenExtractor: 5 | 6 | md_special_chars =[ 7 | { 8 | "md_char": "*", 9 | "replacement": "*" 10 | }, 11 | { 12 | "md_char": "#", 13 | "replacement": "#" 14 | }, 15 | { 16 | "md_char": "`", 17 | "replacement": "·" 18 | } 19 | ] 20 | 21 | #constructor 22 | def __init__(self, root, header_paths, working_dir = "./temp", doxygen_xml_dest = "./xml"): 23 | os.chdir(root) 24 | self.header_paths = header_paths 25 | self.utils = SystemUtils() 26 | self.doxygen_xml_dest = doxygen_xml_dest 27 | self.working_dir = working_dir 28 | 29 | ### 30 | # this function copies headers recursively from a source director to a destination 31 | # directory. 32 | ### 33 | def get_headers(self, from_dir, to_dir): 34 | self.utils.copy_files(from_dir, to_dir, "*.h") 35 | 36 | ### 37 | # Strips out reserved characters used in markdown notation, and replaces them 38 | # with html character codes. 39 | # 40 | # @param text the text to strip and replace the md special characters 41 | # 42 | # @return the stripped text. 43 | ### 44 | def escape_md_chars(self, text): 45 | for char in self.md_special_chars: 46 | text = text.replace(char['md_char'], "\\" + char['md_char']) 47 | return text 48 | 49 | 50 | ### 51 | # this function extracts data from an element tag ignoring the tag 'ref', but 52 | # obtains the textual data it has inside the ref tag. 53 | # 54 | # @param element the element to process 55 | # 56 | # @return a list of extracted strings. 57 | ### 58 | def extract_ignoring_refs(self, element): 59 | list = [] 60 | 61 | if element.text is not None: 62 | list.append(element.text) 63 | 64 | for ref in element.iter(tag="ref"): 65 | list.append(ref.text) 66 | 67 | return list 68 | 69 | ### 70 | # this function extracts data from an element tag including all sub elements 71 | # (recursive) 72 | # 73 | # @param element the element to process 74 | # 75 | # @return a list of extracted strings. 76 | ### 77 | def extract_with_subelements(self, element): 78 | list = [] 79 | 80 | list.append(element.text or "") 81 | 82 | #if element.text is not None: 83 | #list.append(element.text) 84 | 85 | for subelement in element: 86 | if subelement is not None: 87 | list = list + self.extract_with_subelements(subelement) 88 | 89 | list.append(element.tail or "") 90 | 91 | return list 92 | 93 | ### 94 | # this function was at one point intended to fetch a value of a default parameter 95 | # it is now only used to fetch the default parameters' name. 96 | # 97 | # @param document_root the root of the entire document 98 | # @param element the element containing the default parameter 99 | # 100 | # @return a dictionary containing: 101 | # { 102 | # 'name':'', 103 | # 'value':'' 104 | # } 105 | # 106 | # @note this would be more useful if it return the value, it currently does not. 107 | ### 108 | def extract_default(self, element): 109 | ref = element.find("ref") 110 | return {'name':' '.join(element.itertext()), 'value':''} 111 | 112 | ### 113 | # extracts a member function form the xml document 114 | # 115 | # @param root the document root 116 | # @param xml_element the member function xml element. 117 | # 118 | # @return a function dictionary: 119 | # { 120 | # 'short_name':"", 121 | # 'name':"", 122 | # 'return_type':"", 123 | # 'params':[], 124 | # 'description':[], 125 | # 'returns':"", 126 | # 'notes':"", 127 | # 'examples':"" 128 | # } 129 | ### 130 | def extract_member_function(self, xml_element, function_filter = [], filter = True): 131 | 132 | function = { 133 | 'short_name':"", 134 | 'name':"", 135 | 'return_type':"", 136 | 'params':[], 137 | 'description':[], 138 | 'returns':"", 139 | 'notes':"", 140 | 'examples':"" 141 | } 142 | 143 | function['name'] = xml_element.find('definition').text 144 | function['short_name'] = xml_element.find('name').text 145 | 146 | if filter and any(filtered_func in function['short_name'] for filtered_func in function_filter): 147 | print "Filtered out: " + function['short_name'] 148 | return 149 | 150 | print "Generating documentation for: " + function['short_name'] 151 | 152 | if xml_element.find('type') is not None: 153 | function['return_type'] = self.escape_md_chars(' '.join(self.extract_ignoring_refs(xml_element.find('type')))) 154 | 155 | #extract our parameters for this member function 156 | for parameter in xml_element.iter('param'): 157 | 158 | type = "" 159 | name = "" 160 | 161 | if parameter.find('type') is not None: 162 | type = self.escape_md_chars(' '.join(parameter.find('type').itertext())) 163 | 164 | if parameter.find('declname') is not None: 165 | name = ' '.join(self.extract_ignoring_refs(parameter.find('declname'))) 166 | 167 | param_object = { 168 | 'type': type, 169 | 'name': name, 170 | 'default':{ 171 | 'name':"", 172 | 'value':"" 173 | } 174 | } 175 | 176 | if parameter.find('defval') is not None: 177 | extracted = self.extract_default(parameter.find('defval')) 178 | param_object['default']['name'] = extracted['name'] 179 | param_object['default']['value'] = extracted['value'] 180 | 181 | function['params'].append(param_object) 182 | 183 | 184 | detailed_description = xml_element.find('detaileddescription') 185 | 186 | if len(detailed_description.findall("para")) is not 0: 187 | for para in detailed_description.findall("para"): 188 | if len(para.findall("programlisting")) is 0 and len(para.findall("simplesect")) is 0: 189 | function['description'] = function['description'] + self.extract_with_subelements(para) 190 | 191 | #para indicates a new paragraph - we should treat it as such... append \n! 192 | function['description'] = function['description'] + ["\n\n"] 193 | 194 | if len(detailed_description.findall("para/simplesect[@kind='return']/para")) is not 0: 195 | return_section = detailed_description.findall("para/simplesect[@kind='return']/para")[0] 196 | function['returns'] = ' '.join(return_section.itertext()) 197 | 198 | if len(detailed_description.findall("para/simplesect[@kind='note']/para")) is not 0: 199 | return_section = detailed_description.findall("para/simplesect[@kind='note']/para")[0] 200 | function['notes'] = ' '.join(return_section.itertext()) 201 | 202 | examples = detailed_description.find('para/programlisting') 203 | 204 | if examples is not None: 205 | function['examples'] = ''.join([('' if index is 0 else ' ')+word for index, word in enumerate(examples.itertext(),1) ]) 206 | 207 | param_list = detailed_description.findall('para/parameterlist') 208 | 209 | if len(param_list) is not 0: 210 | for parameter_desc in param_list[0].findall('parameteritem'): 211 | 212 | param_descriptor = { 213 | 'name':'', 214 | 'description':'' 215 | } 216 | 217 | param_name = parameter_desc.findall('parameternamelist/parametername') 218 | additional = parameter_desc.findall('parameterdescription/para') 219 | 220 | if len(param_name) is not 0: 221 | param_descriptor['name'] = param_name[0].text 222 | 223 | if len(additional) is not 0: 224 | param_descriptor['description'] = ' '.join(additional[0].itertext()) 225 | 226 | for descriptor in function['params']: 227 | if param_descriptor['name'] in descriptor['name']: 228 | descriptor['description'] = param_descriptor['description'] 229 | 230 | return function 231 | 232 | def generate_doxygen(self): 233 | self.utils.mk_dir(self.working_dir) 234 | self.utils.clean_dir(self.working_dir) 235 | 236 | for path in self.header_paths: 237 | self.get_headers(path, self.working_dir) 238 | 239 | if os.path.exists(self.doxygen_xml_dest): 240 | self.utils.clean_dir(self.doxygen_xml_dest) 241 | 242 | os.system('doxygen doxy-config.cfg') 243 | -------------------------------------------------------------------------------- /utils/python/doc_gen/md_converter.py: -------------------------------------------------------------------------------- 1 | import re, json, copy 2 | 3 | class MarkdownConverter: 4 | 5 | #constructor 6 | def __init__(self, type_colour, function_name_colour, separate_defaults = True, display_defaults = False): 7 | self.type_colour = type_colour 8 | self.function_name_colour = function_name_colour 9 | self.separate_defaults = separate_defaults 10 | self.display_defaults = display_defaults 11 | 12 | ### 13 | # wraps text in a div element with a given color 14 | # 15 | # @param text the text to wrap 16 | # @param color the desired text color 17 | # 18 | # @return a string representing the now wrapped text 19 | ### 20 | def wrap_text(self, text, color): 21 | return "
" + text + "
" 22 | 23 | ### 24 | # removes previously generated markdown from the file. 25 | # 26 | # @param file_lines a list of lines representing a file. 27 | # @param regexp the regular expression that dictates a match. 28 | ### 29 | def clean(self, file_lines, regexp): 30 | start = 0 31 | end = 0 32 | 33 | for line_number, line in enumerate(file_lines, 1): 34 | result = re.findall(regexp,line) 35 | 36 | if len(result) is not 0: 37 | meta_data = json.loads(result[0]) 38 | 39 | keys = meta_data.keys() 40 | 41 | #classname indicates the beginning of a meta_data section 42 | if 'className' in keys: 43 | start = line_number 44 | 45 | #end indicated the end of a meta_data section 46 | if 'end' in keys: 47 | end = line_number - 1 48 | 49 | return file_lines[:start] + file_lines[end:] 50 | 51 | ### 52 | # given a member function, this function derives the alternative versions 53 | # 54 | # @param member_func the member function that is required to be derrived 55 | # 56 | # @return a list of function dictionaries that contain the alternatives, based on the original 57 | ### 58 | def derive_functions(self, member_func): 59 | member_functions_derived = [] 60 | 61 | if len(member_func['params']) is not 0: 62 | 63 | param_index = 0 64 | 65 | for param in member_func['params']: 66 | if len(param['default']['name']) is 0: 67 | param_index = param_index + 1 68 | else: 69 | break 70 | 71 | bare_function = { 72 | 'short_name' : member_func['short_name'], 73 | 'name' : member_func['name'], 74 | 'params' : [], 75 | 'description' : member_func['description'], 76 | 'returns' : member_func['returns'], 77 | 'notes' : member_func['notes'], 78 | 'examples' : member_func['examples'], 79 | 'return_type' : member_func['return_type'], 80 | } 81 | 82 | for i in range(0, param_index): 83 | bare_function['params'] = bare_function['params'] + [member_func['params'][i]] 84 | 85 | member_functions_derived = member_functions_derived + [bare_function] 86 | 87 | current = copy.copy(bare_function) 88 | 89 | #lists retain references, so we have to copy objects to maintain separation 90 | for remainder in range(param_index, len(member_func['params'])): 91 | current['params'] = current['params'] + [member_func['params'][remainder]] 92 | member_functions_derived = member_functions_derived + [current] 93 | current = copy.copy(current) 94 | 95 | else: 96 | member_functions_derived = member_functions_derived + [member_func] 97 | 98 | return member_functions_derived 99 | 100 | ### 101 | # given a parameter, this function generates text 102 | # 103 | # @param param the parameter that needs a textual translation 104 | # 105 | # @return a string representing the parameter 106 | ### 107 | def gen_param_text(self, param): 108 | text = "\n> " 109 | 110 | if param['type'] is not None: 111 | text = text + " " + self.wrap_text(param['type'], self.type_colour) 112 | 113 | text = text + " " + param['name'] 114 | 115 | if self.display_defaults: 116 | if len(param['default']['name']) is not 0: 117 | text = text + " `= " + param['default']['name'] 118 | 119 | if len(param['default']['value']) is not 0: 120 | text = text + param['default']['value'] 121 | 122 | text = text + "`" 123 | 124 | if 'description' in param.keys(): 125 | text = text +" - " + param['description'] 126 | 127 | text = text.encode('ascii','ignore') 128 | 129 | return text 130 | 131 | ### 132 | # given a list of member functions, this function returns a list of new lines for the 133 | # file currently being processed. 134 | # 135 | # @param class_name the name of the current class (found in the meta data) 136 | # @param member_functions the list of member_functions extracted from XML 137 | # 138 | # @return a list containing the new lines to be inserted into the current file. 139 | ### 140 | def gen_member_func_doc(self, class_name, member_functions): 141 | 142 | # this is what a member function dictionary contains. 143 | # function = { 144 | # 'short_name':"", 145 | # 'name':"", 146 | # 'return_type':"", 147 | # 'params':[], 148 | # 'description':[], 149 | # 'returns':"", 150 | # 'notes':"", 151 | # 'examples':"", 152 | # 'default':None 153 | # } 154 | 155 | lines = [] 156 | 157 | for index, member_func in enumerate(member_functions,0): 158 | 159 | member_functions_derived = [] 160 | 161 | if index is 0 or member_func['short_name'] != member_functions[index - 1]['short_name']: 162 | if class_name == member_func["short_name"]: 163 | lines.append("##Constructor\n") 164 | else: 165 | lines.append("##" + member_func["short_name"]+"\n") 166 | 167 | #we want to clearly separate our different level of functions in the DAL 168 | #so we present methods with defaults as overloads. 169 | if self.separate_defaults is True: 170 | member_functions_derived = member_functions_derived + self.derive_functions(member_func) 171 | 172 | for derived_func in member_functions_derived: 173 | #---- short name for urls ---- 174 | lines.append("
\n") 175 | 176 | short_name = "" 177 | 178 | if len(derived_func["return_type"]) is not 0: 179 | short_name = "####" + self.wrap_text(derived_func["return_type"],self.type_colour) + " " +self.wrap_text(derived_func["short_name"], self.function_name_colour) + "(" 180 | else: 181 | short_name = "####" + derived_func["short_name"] + "(" 182 | 183 | last_param = None 184 | 185 | if len(derived_func['params']) is not 0: 186 | last_param = derived_func['params'][-1] 187 | 188 | #generate parameters for the name of this function 189 | for param in derived_func['params']: 190 | text = "" 191 | 192 | if param['type'] is not None: 193 | text = text + " " + self.wrap_text(param['type'], self.type_colour) 194 | 195 | text = text + " " + param['name'] 196 | 197 | if param is not last_param: 198 | short_name = short_name + text +", " 199 | else: 200 | short_name = short_name + text 201 | 202 | lines.append(short_name + ")\n") 203 | #----------------------------- 204 | 205 | #---- description ---- 206 | if len(derived_func['description']) is not 0: 207 | lines.append("#####Description\n") 208 | lines.append(' '.join(derived_func['description']) + "\n") 209 | #----------------------------- 210 | 211 | #---- parameters ---- 212 | if len(derived_func['params']) is not 0: 213 | lines.append("#####Parameters\n") 214 | 215 | for param in derived_func['params']: 216 | lines.append(self.gen_param_text(param) + "\n") 217 | #----------------------------- 218 | 219 | #---- returns ---- 220 | if len(derived_func['returns']) is not 0: 221 | lines.append("#####Returns\n") 222 | lines.append(derived_func['returns'] + "\n") 223 | #----------------------------- 224 | 225 | #---- examples ---- 226 | if len(derived_func['examples']) is not 0: 227 | lines.append("#####Example\n") 228 | lines.append("```cpp\n") 229 | lines.append(derived_func['examples']) 230 | lines.append("```\n") 231 | #----------------------------- 232 | 233 | #---- notes ---- 234 | if len(derived_func['notes']) is not 0: 235 | lines.append("\n!!! note\n") 236 | lines.append(" " + derived_func['notes'].replace('\n','\n ')) 237 | lines.append('\n\n') 238 | #----------------------------- 239 | 240 | lines.append("____\n") 241 | 242 | return lines 243 | -------------------------------------------------------------------------------- /utils/python/doc_gen/system_utils.py: -------------------------------------------------------------------------------- 1 | import json, shutil, zipfile, urllib, os, fnmatch 2 | 3 | class SystemUtils: 4 | 5 | folder_filter = ["ble", "ble-nrf51822", "mbed-classic","nrf51-sdk"] 6 | 7 | ### 8 | # reads a file and returns a list of lines 9 | # 10 | # @param path the path where the file is located 11 | # 12 | # @return the list of lines representing the file. 13 | ### 14 | def read(self, path, plain=False): 15 | if plain: 16 | return self.__read_plain(path) 17 | print "Opening: " + path + " \n" 18 | with open(path, 'r') as file: 19 | return file.readlines() 20 | 21 | def __read_plain(self, path): 22 | print "Opening: " + path + " \n" 23 | with open(path, 'r') as file: 24 | return file.read() 25 | 26 | ### 27 | # writes a given set of lines to a path. 28 | # 29 | # @param path the path where the file is located 30 | # @param lines the lines to write 31 | ### 32 | def write(self, path, lines): 33 | print "Writing to: " + path + " \n" 34 | with open(path, 'w') as file: 35 | file.writelines(lines) 36 | 37 | #http://stackoverflow.com/questions/2186525/use-a-glob-to-find-files-recursively-in-python 38 | def find_files(self, directory, pattern): 39 | 40 | print("DIR:") 41 | for root, dirs, files in os.walk(directory): 42 | if any(dir in root for dir in self.folder_filter): 43 | continue 44 | 45 | for basename in files: 46 | if fnmatch.fnmatch(basename, pattern): 47 | filename = os.path.join(root, basename) 48 | yield filename 49 | 50 | ### 51 | # removes files from a folder. 52 | ### 53 | def clean_dir(self, dir): 54 | for root, dirs, files in os.walk(dir): 55 | for f in files: 56 | os.unlink(os.path.join(root, f)) 57 | for d in dirs: 58 | shutil.rmtree(os.path.join(root, d)) 59 | 60 | ### 61 | # this files from one location to another 62 | ### 63 | def copy_files(self, from_dir, to_dir, pattern): 64 | 65 | 66 | files = self.find_files(from_dir, pattern) 67 | 68 | print("FILES!!!! ") 69 | for file in files: 70 | print file 71 | shutil.copy(file,to_dir) 72 | 73 | def mk_dir(self, path): 74 | if not os.path.exists(path): 75 | os.makedirs(path) 76 | 77 | def copytree(self, src, dst, symlinks=False, ignore=None): 78 | if not os.path.exists(dst): 79 | os.makedirs(dst) 80 | for item in os.listdir(src): 81 | s = os.path.join(src, item) 82 | d = os.path.join(dst, item) 83 | if os.path.isdir(s): 84 | self.copytree(s, d, symlinks, ignore) 85 | else: 86 | if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1: 87 | shutil.copy2(s, d) 88 | 89 | def __add_version_info(self,version_string, extract_location): 90 | content_path = extract_location + "js/base.js" 91 | lines = self.read(content_path) 92 | html_string = '

Warning

You are viewing documentation for ' + version_string + '

' 93 | lines[0]= '$(document).ready(function() { $(\'div[role="main"]\').prepend("' + html_string + '") });' 94 | self.write(content_path, lines) 95 | 96 | def validate_version(self, working_dir, module_paths, extract_location): 97 | import yaml 98 | 99 | module_string = "/module.json" 100 | mkdocs_yml = yaml.load(self.read("./mkdocs.yml", plain=True)) 101 | 102 | module_strings = [] 103 | 104 | for current_path in module_paths: 105 | module_strings = module_strings + [json.loads(self.read(current_path + module_string, plain=True))["version"]] 106 | 107 | if module_strings[1:] != module_strings[:-1]: 108 | raise Exception("Version mismatch exception! microbit-dal and microbit are not compatible versions.") 109 | 110 | module_string = "v" + str(module_strings[0]) 111 | 112 | if mkdocs_yml["versioning"]["runtime"] != module_string: 113 | #capture old site, save in docs/historic/versionNumber 114 | zip_dest = working_dir + "/" + str(mkdocs_yml["versioning"]["runtime"]) + ".zip" 115 | 116 | extract_folder = extract_location+ "/" + mkdocs_yml["versioning"]["runtime"]+"/" 117 | 118 | urllib.urlretrieve("https://github.com/lancaster-university/microbit-docs/archive/gh-pages.zip", zip_dest) 119 | 120 | zip_ref = zipfile.ZipFile(zip_dest) 121 | 122 | #obtain the archive prepended name 123 | archive_name = working_dir + "/" + zip_ref.namelist()[0] 124 | 125 | zip_ref.extractall(working_dir) 126 | zip_ref.close() 127 | 128 | self.copytree(archive_name, extract_folder) 129 | 130 | self.__add_version_info(mkdocs_yml["versioning"]["runtime"], extract_folder) 131 | 132 | self.clean_dir(archive_name) 133 | 134 | mkdocs_yml["versioning"]["runtime"] = module_string 135 | 136 | with open("./mkdocs.yml", "w") as f: 137 | yaml.dump(mkdocs_yml, f, default_flow_style=False ) 138 | -------------------------------------------------------------------------------- /utils/targets.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"codal-arduino-uno", 4 | "info":"This target specifies the arduino uno which is driven by an atmega328p.", 5 | "device_url":"https://store.arduino.cc/arduino-uno-rev3", 6 | "url":"https://github.com/lancaster-university/codal-arduino-uno", 7 | "branch":"master", 8 | "type":"git" 9 | }, 10 | { 11 | "name":"codal-circuit-playground", 12 | "info":"This target specifies the circuit playground which is driven by a SAMD21.", 13 | "device_url":"https://www.adafruit.com/product/3333", 14 | "url":"https://github.com/lancaster-university/codal-circuit-playground", 15 | "branch":"master", 16 | "type":"git" 17 | }, 18 | { 19 | "name":"codal-microbit", 20 | "info":"This target specifies the microbit, which uses the nordic NRF51822.", 21 | "device_url":"https://microbit.org", 22 | "url":"https://github.com/lancaster-university/codal-microbit", 23 | "test_ignore":true, 24 | "branch":"codal-microbit-mbed", 25 | "type":"git" 26 | }, 27 | { 28 | "name":"codal-huzzah", 29 | "info":"This target specifies the HUZZAH which is driven by a ESP8266.", 30 | "device_url":"https://www.adafruit.com/product/3405", 31 | "url":"https://github.com/lancaster-university/codal-huzzah", 32 | "test_ignore":true, 33 | "branch":"master", 34 | "type":"git" 35 | }, 36 | { 37 | "name":"codal-brainpad", 38 | "info":"This target specifies the BRAINPAD which is driven by a STM32f.", 39 | "device_url":"https://brainpad.com", 40 | "url":"https://github.com/lancaster-university/codal-brainpad", 41 | "branch":"master", 42 | "type":"git" 43 | }, 44 | { 45 | "name":"codal-microbit-next", 46 | "info":"version 1.4 revision of the BBC micro:bit.", 47 | "device_url":"https://www.microbit.org", 48 | "url":"https://github.com/microbit-foundation/codal-microbit-next", 49 | "test_ignore":true, 50 | "branch":"nrf52833-mbedos", 51 | "type":"git" 52 | }, 53 | { 54 | "name":"codal-ble-nano", 55 | "info":"This target specifies the ble-nano by RedBear which is driven by a NRF52.", 56 | "device_url":"https://redbear.cc/product/ble-nano-kit-2.html", 57 | "url":"https://github.com/lancaster-university/codal-ble-nano", 58 | "branch":"master", 59 | "type":"git" 60 | }, 61 | { 62 | "name":"codal-stm32-iot-node", 63 | "info":"This target specifies the STM32 IoT Node board which is driven by a STM32L475.", 64 | "device_url":"http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html", 65 | "url":"https://github.com/LabAixBidouille-STM32/codal-stm32-iot-node", 66 | "test_ignore":true, 67 | "branch":"master", 68 | "type":"git" 69 | }, 70 | { 71 | "name":"codal-big-brainpad", 72 | "info":"This target specifies the stm32f401re (The big brain pad).", 73 | "device_url":"", 74 | "url":"https://github.com/lancaster-university/codal-big-brainpad", 75 | "branch":"master", 76 | "type":"git", 77 | "test_ignore":true 78 | }, 79 | { 80 | "name":"codal-mkr1300", 81 | "info":"This target specifies the arduino mkr1300 variant.", 82 | "device_url":"", 83 | "url":"https://github.com/ElectronicCats/codal-mkr1300", 84 | "branch":"master", 85 | "type":"git", 86 | "test_ignore":true 87 | }, 88 | { 89 | "name":"codal-jacdac-feather", 90 | "info":"This target specifies the jacdac-feather board based on the stmf103", 91 | "device_url":"", 92 | "url":"https://github.com/lancaster-university/codal-jacdac-feather", 93 | "branch":"master", 94 | "type":"git", 95 | "test_ignore":true 96 | }, 97 | { 98 | "name":"codal-itsybitsy-m4", 99 | "info":"This target specifies the adafruit itsybitsy board.", 100 | "device_url":"", 101 | "url":"https://github.com/lancaster-university/codal-itsybitsy-m4", 102 | "branch":"master", 103 | "type":"git" 104 | } 105 | ] 106 | -------------------------------------------------------------------------------- /utils/uf2conv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import struct 5 | import subprocess 6 | import re 7 | import os 8 | import os.path 9 | import argparse 10 | 11 | UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" 12 | UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected 13 | UF2_MAGIC_END = 0x0AB16F30 # Ditto 14 | 15 | INFO_FILE = "/INFO_UF2.TXT" 16 | 17 | appstartaddr = 0x2000 18 | 19 | def isUF2(buf): 20 | w = struct.unpack(" 476: 39 | assert False, "Invalid UF2 data size at " + ptr 40 | newaddr = hd[3] 41 | if curraddr == None: 42 | appstartaddr = newaddr 43 | curraddr = newaddr 44 | padding = newaddr - curraddr 45 | if padding < 0: 46 | assert False, "Block out of order at " + ptr 47 | if padding > 10*1024*1024: 48 | assert False, "More than 10M of padding needed at " + ptr 49 | if padding % 4 != 0: 50 | assert False, "Non-word padding size at " + ptr 51 | while padding > 0: 52 | padding -= 4 53 | outp += "\x00\x00\x00\x00" 54 | outp += block[32 : 32 + datalen] 55 | curraddr = newaddr + datalen 56 | return outp 57 | 58 | def convertToUF2(fileContent): 59 | datapadding = "" 60 | while len(datapadding) < 512 - 256 - 32 - 4: 61 | datapadding += "\x00\x00\x00\x00" 62 | numblocks = (len(fileContent) + 255) / 256 63 | outp = "" 64 | for blockno in range(0, numblocks): 65 | ptr = 256 * blockno 66 | chunk = fileContent[ptr:ptr + 256] 67 | hd = struct.pack("= 3 and words[1] == "2" and words[2] == "FAT": 84 | drives.append(words[0]) 85 | else: 86 | rootpath = "/media" 87 | if sys.platform == "darwin": 88 | rootpath = "/Volumes" 89 | elif sys.platform == "linux": 90 | tmp = rootpath + "/" + os.environ["USER"] 91 | if os.path.isdir(tmp): 92 | rootpath = tmp 93 | for d in os.listdir(rootpath): 94 | drives.append(os.path.join(rootpath, d)) 95 | 96 | def hasInfo(d): 97 | try: 98 | return os.path.isfile(d + INFO_FILE) 99 | except: 100 | return False 101 | 102 | return filter(hasInfo, drives) 103 | 104 | def boardID(path): 105 | with open(path + INFO_FILE, mode='r') as file: 106 | fileContent = file.read() 107 | return re.search("Board-ID: ([^\r\n]*)", fileContent).group(1) 108 | 109 | def listdrives(): 110 | for d in getdrives(): 111 | print d, boardID(d) 112 | 113 | def writeFile(name, buf): 114 | with open(name, "wb") as f: 115 | f.write(buf) 116 | print "Wrote %d bytes to %s." % (len(buf), name) 117 | 118 | def main(): 119 | global appstartaddr 120 | def error(msg): 121 | print msg 122 | sys.exit(1) 123 | parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') 124 | parser.add_argument('input', metavar='INPUT', type=str, nargs='?', 125 | help='input file (BIN or UF2)') 126 | parser.add_argument('-b' , '--base', dest='base', type=str, 127 | default="0x2000", 128 | help='set base address of application (default: 0x2000)') 129 | parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, 130 | help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') 131 | parser.add_argument('-d' , '--device', dest="device_path", 132 | help='select a device path to flash') 133 | parser.add_argument('-l' , '--list', action='store_true', 134 | help='list connected devices') 135 | parser.add_argument('-c' , '--convert', action='store_true', 136 | help='do not flash, just convert') 137 | args = parser.parse_args() 138 | appstartaddr = int(args.base, 0) 139 | if args.list: 140 | listdrives() 141 | else: 142 | if not args.input: 143 | error("Need input file") 144 | with open(args.input, mode='rb') as file: 145 | inpbuf = file.read() 146 | fromUF2 = isUF2(inpbuf) 147 | ext = "uf2" 148 | if fromUF2: 149 | outbuf = convertFromUF2(inpbuf) 150 | ext = "bin" 151 | else: 152 | outbuf = convertToUF2(inpbuf) 153 | print "Converting to %s, output size: %d, start address: 0x%x" % (ext, len(outbuf), appstartaddr) 154 | 155 | if args.convert: 156 | drives = [] 157 | if args.output == None: 158 | args.output = "flash." + ext 159 | else: 160 | drives = getdrives() 161 | 162 | if args.output: 163 | writeFile(args.output, outbuf) 164 | else: 165 | if len(drives) == 0: 166 | error("No drive to deploy.") 167 | for d in drives: 168 | print "Flashing %s (%s)" % (d, boardID(d)) 169 | writeFile(outbuf, d + "/NEW.UF2") 170 | 171 | if __name__ == "__main__": 172 | main() 173 | --------------------------------------------------------------------------------