From dbd2b12f3e8145d70af2b2f2b94c219fc4c74a92 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Wed, 24 Mar 2021 16:47:32 -0400 Subject: [PATCH] Update examples, tools, migrate to GitHub actions Signed-off-by: Sara Damiano --- .github/workflows/build_documentation.yaml | 109 +++ .github/workflows/build_examples.yaml | 84 +++ .github/workflows/changelog_reminder.yaml | 18 + .github/workflows/prepare_release.yaml | 72 ++ .github/workflows/verify_library_json.yaml | 31 + ChangeLog.md | 75 ++ VERSION | 1 + .../.travis.yml_archive | 1 + .../build-install-doxygen.sh | 12 +- .../copy-doc-sources.sh | 0 .../deploy-documentation.sh | 0 .../generate-documentation.sh | 2 +- .../install-current-doxygen.sh | 0 docs/Doxyfile | 2 +- ...mlSections.py => fixXmlExampleSections.py} | 31 +- examples/d_simple_logger/d_simple_logger.ino | 29 +- examples/e_continuous_measurement/ReadMe.md | 18 + .../e_continuous_measurement.ino | 220 ++++++ library.json | 2 +- library.properties | 2 +- tools/TestCommands/TestCommands.ino | 651 ++++++++++++++++++ tools/TestWarmUp/TestWarmUp.ino | 156 +++++ tools/powerOn/powerOn.ino | 14 + 23 files changed, 1495 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/build_documentation.yaml create mode 100644 .github/workflows/build_examples.yaml create mode 100644 .github/workflows/changelog_reminder.yaml create mode 100644 .github/workflows/prepare_release.yaml create mode 100644 .github/workflows/verify_library_json.yaml create mode 100644 ChangeLog.md create mode 100644 VERSION rename .travis.yml => continuous_integration/.travis.yml_archive (99%) rename {travis => continuous_integration}/build-install-doxygen.sh (68%) rename {travis => continuous_integration}/copy-doc-sources.sh (100%) rename {travis => continuous_integration}/deploy-documentation.sh (100%) rename {travis => continuous_integration}/generate-documentation.sh (98%) rename {travis => continuous_integration}/install-current-doxygen.sh (100%) rename docs/{fixXmlSections.py => fixXmlExampleSections.py} (54%) create mode 100644 examples/e_continuous_measurement/ReadMe.md create mode 100644 examples/e_continuous_measurement/e_continuous_measurement.ino create mode 100644 tools/TestCommands/TestCommands.ino create mode 100644 tools/TestWarmUp/TestWarmUp.ino create mode 100644 tools/powerOn/powerOn.ino diff --git a/.github/workflows/build_documentation.yaml b/.github/workflows/build_documentation.yaml new file mode 100644 index 0000000..17623de --- /dev/null +++ b/.github/workflows/build_documentation.yaml @@ -0,0 +1,109 @@ +name: Build and Publish Documentation + +on: + # Trigger the workflow on push or pull request, + # but only for the main branch + push: + branches: + - master + # Also trigger on page_build, as well as release created events + page_build: + release: + types: # This configuration does not affect the page_build event above + - created + +env: + DOXYGEN_VERSION: Release_1_8_20 + +jobs: + build: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'ci skip')" + + steps: + # check out the Arduino-SDI-12 repo + - uses: actions/checkout@v2 + with: + path: code_docs/Arduino-SDI-12 + + - name: Restore or Cache pip + uses: actions/cache@v2.1.4 + id: cache_pip + with: + path: ~/.cache/pip + # if requirements.txt hasn't changed, then it will be a "cache hit" and pip will be restored + # if requirements.txt HAS changed, it will be a "cache miss" and a new cache of pip will be created if the job completes successfully + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: ${{ runner.os }}-pip- + + - name: Restore or Cache PlatformIO and Libraries + uses: actions/cache@v2.1.4 + id: cache_pio + with: + path: ~/.platformio + # if nothing in the lock files has changed, then it will be a "cache hit" + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + + - name: Set up Python + uses: actions/setup-python@v2 + + # This should be pulled from cache, if there's not a new version + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + # Install *all* the dependencies! + # We're including the dependencies just so the includes can follow in the doxygen pre-processor + - name: Install the dependencies at global level + run: | + echo "::debug::Installing greygnome/EnableInterrupt" + pio lib -g install greygnome/EnableInterrupt + + - name: Update Libraries from Cache + run: pio lib -g update + + - name: Install GraphViz (dot) + run: sudo apt-get -y install graphviz + + - name: Restore or Cache Doxygen + id: cache_doxygen + uses: actions/cache@v2.1.4 + with: + path: doxygen-src + key: ${{ runner.os }}-doxygen-${{ env.DOXYGEN_VERSION }} + + - name: Clone and build doxygen + if: steps.cache_doxygen.outputs.cache-hit != 'true' + env: + TRAVIS_BUILD_DIR: ${{ github.workspace }} + run: | + cd ${{ github.workspace }}/code_docs/ModularSensors/ + chmod +x continuous_integration/build-install-doxygen.sh + sh continuous_integration/build-install-doxygen.sh + + # This should be pulled from cache, if there's not a new version + - name: Install Pygments and other m.css requirements + run: pip3 install jinja2 Pygments beautifulsoup4 + + # check out my fork of m.css, for processing Doxygen output + - name: Checkout m.css + uses: actions/checkout@v2 + with: + # Repository name with owner. For example, actions/checkout + repository: SRGDamia1/m.css + path: code_docs/m.css + + - name: Generate all the documentation + env: + TRAVIS_BUILD_DIR: ${{ github.workspace }} + run: | + cd ${{ github.workspace }}/code_docs/ModularSensors/ + chmod +x continuous_integration/generate-documentation.sh + sh continuous_integration/generate-documentation.sh + + - name: Deploy to github pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ${{ github.workspace }}/code_docs/ModularSensorsDoxygen/m.css diff --git a/.github/workflows/build_examples.yaml b/.github/workflows/build_examples.yaml new file mode 100644 index 0000000..06a2c1e --- /dev/null +++ b/.github/workflows/build_examples.yaml @@ -0,0 +1,84 @@ +name: Build Examples + +# Triggers the workflow on push or pull request events +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'ci skip')" + + strategy: + matrix: + example: + [ + examples/a_wild_card/, + examples/b_address_change/, + examples/c_check_all_addresses/, + examples/d_simple_logger/, + examples/e_simple_parsing/, + examples/f_basic_data_request/, + examples/g_terminal_window/, + examples/h_SDI-12_slave_implementation/, + examples/i_SDI-12_interface/, + examples/j_external_pcint_library/, + examples/k_concurrent_logger/, + ] + + steps: + - uses: actions/checkout@v2 + + - name: Set variables + run: | + if [[ -z "${GITHUB_HEAD_REF}" ]]; then + echo "::debug::Push to commit ${GITHUB_SHA}" + echo "LIBRARY_INSTALL_SOURCE=https://github.com/${GITHUB_REPOSITORY}.git#${GITHUB_SHA}" >> $GITHUB_ENV + else + echo "::debug::Pull Request from the ${GITHUB_HEAD_REF} branch" + echo "LIBRARY_INSTALL_SOURCE=https://github.com/${GITHUB_REPOSITORY}.git#${GITHUB_HEAD_REF}" >> $GITHUB_ENV + fi + + - name: Restore or Cache pip + uses: actions/cache@v2.1.4 + with: + path: ~/.cache/pip + # if requirements.txt hasn't changed, then it will be a "cache hit" and pip will be restored + # if requirements.txt HAS changed, it will be a "cache miss" and a new cache of pip will be created if the job completes successfully + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: ${{ runner.os }}-pip- + + - name: Restore or Cache PlatformIO and Libraries + uses: actions/cache@v2.1.4 + with: + path: ~/.platformio + # if nothing in the lock files has changed, then it will be a "cache hit" and pip will be restored + # otherwise, it will be a "cache miss" and a new cache of libraries will be created if the job completes successfully + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + + - name: Set up Python + uses: actions/setup-python@v2 + + # This should be pulled from cache, if there's not a new version + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + - name: Run PlatformIO + if: ${{ matrix.example != 'k_concurrent_logger'}} + env: + PLATFORMIO_CI_SRC: ${{ matrix.example }} + run: | + platformio lib --global update + echo "${{ env.LIBRARY_INSTALL_SOURCE }}" + platformio ci --board=mayfly --board=feather32u4 --board=adafruit_feather_m0 --board=uno --board=megaatmega2560 --board=huzzah --board=featheresp32 + + - name: Run PlatformIO + if: ${{ matrix.example == 'k_concurrent_logger'}} + env: + PLATFORMIO_CI_SRC: ${{ matrix.example }} + run: | + platformio lib --global update + echo "${{ env.LIBRARY_INSTALL_SOURCE }}" + pio lib --global install EnableInterrupt + platformio ci --board=mayfly --board=feather32u4 --board=adafruit_feather_m0 --board=uno --board=megaatmega2560 \ No newline at end of file diff --git a/.github/workflows/changelog_reminder.yaml b/.github/workflows/changelog_reminder.yaml new file mode 100644 index 0000000..172868b --- /dev/null +++ b/.github/workflows/changelog_reminder.yaml @@ -0,0 +1,18 @@ +on: pull_request +name: Changelog Reminder +jobs: + remind: + name: Changelog Reminder + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token + + - name: Changelog Reminder + uses: peterjgrainger/action-changelog-reminder@v1.3.0 + with: + changelog_regex: '/ChangeLog\/.*\/*.md' + customPrMessage: 'Please add your changes to the change log!' + env: + GITHUB_TOKEN: ${{ secrets.SARA_PUSH_TOKEN }} diff --git a/.github/workflows/prepare_release.yaml b/.github/workflows/prepare_release.yaml new file mode 100644 index 0000000..d000dab --- /dev/null +++ b/.github/workflows/prepare_release.yaml @@ -0,0 +1,72 @@ +on: + push: + branches: + - master + # Sequence of patterns matched against refs/tags + paths: + - 'VERSION' # Push events when the VERSION file changes + workflow_dispatch: + +name: Prepare a new release + +env: + PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }} + +jobs: + release: + name: Prepare a new release + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set variables + run: | + echo "::debug::Get the current version number" + VER=$(cat VERSION) + echo "VERSION=$VER" >> $GITHUB_ENV + + - name: Restore or Cache pip + uses: actions/cache@v2.1.4 + with: + path: ~/.cache/pip + # if requirements.txt hasn't changed, then it will be a "cache hit" and pip will be restored + # if requirements.txt HAS changed, it will be a "cache miss" and a new cache of pip will be created if the job completes successfully + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: ${{ runner.os }}-pip- + + - name: Set up Python + uses: actions/setup-python@v2 + + # This should be pulled from cache, if there's not a new version + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + - name: Get notes + id: generate_notes + uses: anmarkoulis/commitizen-changelog-reader@master + with: + # NOTE: Need to add the refs/tags to work with the generate notes action + tag_name: ${{ format('refs/tags/{0}', env.VERSION) }} + changelog: ChangeLog.md + + # Create a new release + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.VERSION }} + release_name: ${{ env.VERSION }} + draft: false + prerelease: false + body: ${{join(fromJson(steps.generate_notes.outputs.notes).notes, '')}} + + # Publish the new release to the pio package manager + - name: Publish release to PIO + id: publish-pio + run: pio package publish diff --git a/.github/workflows/verify_library_json.yaml b/.github/workflows/verify_library_json.yaml new file mode 100644 index 0000000..31fd049 --- /dev/null +++ b/.github/workflows/verify_library_json.yaml @@ -0,0 +1,31 @@ +name: Verify JSON structure for library manifest + +# Triggers the workflow on push or pull request events +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'ci skip')" + + steps: + - uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v1.4.4 + + - name: Cache Node.js modules + uses: actions/cache@v2.1.4 + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.OS }}-node- + ${{ runner.OS }}- + + - name: install jsonlint + run: npm install -g jsonlint + + - name: run jsonlint + run: jsonlint -q library.json diff --git a/ChangeLog.md b/ChangeLog.md new file mode 100644 index 0000000..32a3f29 --- /dev/null +++ b/ChangeLog.md @@ -0,0 +1,75 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +**** + +## v2.1.3 (2021-03-24) [Patches for ATTiny](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v2.1.1) + +### Improvements +- Migrate from Travis to GitHub actions + +## v2.1.1 (2020-08-20) [Patches for ATTiny](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v2.1.1) + +### Bug Fixes +- fixes for the timer and pre-scaler for the ATTiny, courtesy of @gabbas1 + +## v2.1.0 (2020-07-10) [Library Rename and ESP support](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v2.1.0) + +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3939731.svg)](https://doi.org/10.5281/zenodo.3939731) + +**To comply with requirements for inclusion in the Arduino IDE, the word Arduino has been removed from the name of this library!** The repository name is unchanged. + +### New Features +- Adds support for Espressif ESP8266 and ESP32 +- Add option of adding a delay before sending a command to allow the sensor to wake. Take advantage of this by calling the function ```sendCommand(command, extraWakeTime)```. This may resolve issues with some Campbell sensors that would not previous communicate with this library. See https://www.envirodiy.org/topic/campbell-scientific-cs-215-sdi-12-communication-issues-w-mayfly/#post-14103 +- Adds Doxygen (Javadoc) style comments to **ALL** members of the library. The generated documentation is available at https://envirodiy.github.io/Arduino-SDI-12/. + +## v1.3.6 (2019-08-29) [Fixed extra compiler warnings](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.3.6) + +### Bug Fixes +- A very minor update to fix compiler warnings found when using -Wextra in addition to -Wall. + +## v1.3.5 (2019-07-01) [Removed SAMD Tone Conflict](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.3.5) + +### Improvements +- SAMD boards will no longer have a conflict with the Tone functions in the Arduino core. AVR boards will still conflict. If you need to use Tone and SDI-12 together for some reason on an AVR boards, you must use the "delayBase" branch. +- Examples were also updated and given platformio.ini files. + +## v1.3.4 (2019-10-29) [Timer class](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.3.4) + +### Improvements +- Made the timer changes into a compiled class. + +Maintaining interrupt control for SAMD processors as there are no interrupt vectors to be in conflict. Because the pin mode changes from input to output and back, allowing another library to control interrupts doesn't work. + +## v1.3.3 (2018-05-11) [Unset prescalers](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.3.3) + +### Improvements +- Now unsetting timer prescalers and setting the isActive pointer to NULL in both the end and the destructor functions. +- Also some clean-up of the examples. + +## v1.3.1 (2018-04-06) [Added processor timer for greater stability](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.3.1) + +### New Features +- Changed the incoming data ISR to use a processor timer, this makes the reception more stable, especially when the ISR is controlled by an external library. This also creates some conflicts with other libraries that use Timer2. + +### Improvements +- Made changes to the write functions to use the timer to reduce the amount of time that all system interrupts are off. +- Forcing all SDI-12 objects to use the same buffer to reduce ram usage. + +## v1.1.0 (2018-03-15) [Better integration inside other libraries](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.1.0) + +### Improvements +- Added notes and an empty constructor/populated begin method to allow this library to be more easily called inside of other libraries. + +## v1.0.6 (2018-03-09) [Fixed timeout values](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.0.6) + +### Bug Fixes +- Fixes the time-out values for the ParseInt and ParseFloat to be -9999. This was the intended behavior all along, but at some point those functions changed in the stream library and the identically named functions within SDI-12 intended to "hide" the stream functions ceased to be called. + +## v1.0.1 (2017-05-16) [Initial Release](https://github.com/EnviroDIY/Arduino-SDI-12/releases/tag/v1.0.1) + +The first "official" release of this interrupt-based SDI-12 library for AVR and SAMD Arduino boards. \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..557fefc --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +v2.1.3 \ No newline at end of file diff --git a/.travis.yml b/continuous_integration/.travis.yml_archive similarity index 99% rename from .travis.yml rename to continuous_integration/.travis.yml_archive index 21d5789..f84a321 100644 --- a/.travis.yml +++ b/continuous_integration/.travis.yml_archive @@ -146,6 +146,7 @@ jobs: - name: "i_SDI-12_interface" env: - PLATFORMIO_CI_SRC=examples/i_SDI-12_interface/i_SDI-12_interface.ino + - name: "j_external_pcint_library" env: - PLATFORMIO_CI_SRC=examples/j_external_pcint_library/j_external_pcint_library.ino diff --git a/travis/build-install-doxygen.sh b/continuous_integration/build-install-doxygen.sh similarity index 68% rename from travis/build-install-doxygen.sh rename to continuous_integration/build-install-doxygen.sh index 50d05fc..1129871 100644 --- a/travis/build-install-doxygen.sh +++ b/continuous_integration/build-install-doxygen.sh @@ -3,13 +3,23 @@ # Exit with nonzero exit code if anything fails set -e +# install all the dependencies for make for Doxygen +sudo apt-get update +sudo apt-get -y install build-essential +sudo apt-get -y install flex +sudo apt-get -y install bison +sudo apt-get -y install texlive-base +sudo apt-get -y install texlive-latex-extra +sudo apt-get -y install texlive-fonts-extra +sudo apt-get -y install texlive-fonts-recommended + cd $TRAVIS_BUILD_DIR if [ ! -f $TRAVIS_BUILD_DIR/doxygen-src/build/bin/doxygen ]; then # Build instructions from: https://www.stack.nl/~dimitri/doxygen/download.html echo "Cloning doxygen repository..." - git clone https://github.com/doxygen/doxygen.git doxygen-src + git clone https://github.com/doxygen/doxygen.git doxygen-src --branch $DOXYGEN_VERSION --depth 1 cd doxygen-src diff --git a/travis/copy-doc-sources.sh b/continuous_integration/copy-doc-sources.sh similarity index 100% rename from travis/copy-doc-sources.sh rename to continuous_integration/copy-doc-sources.sh diff --git a/travis/deploy-documentation.sh b/continuous_integration/deploy-documentation.sh similarity index 100% rename from travis/deploy-documentation.sh rename to continuous_integration/deploy-documentation.sh diff --git a/travis/generate-documentation.sh b/continuous_integration/generate-documentation.sh similarity index 98% rename from travis/generate-documentation.sh rename to continuous_integration/generate-documentation.sh index f3b6753..7402c0d 100644 --- a/travis/generate-documentation.sh +++ b/continuous_integration/generate-documentation.sh @@ -28,6 +28,6 @@ echo 'Generating Doxygen code documentation...' $TRAVIS_BUILD_DIR/doxygen-src/build/bin/doxygen Doxyfile 2>&1 | tee doxygen.log echo 'Fixing errant xml section names in examples as generated by Doxygen...' -python fixXmlSections.py +python fixXmlExampleSections.py python $TRAVIS_BUILD_DIR/code_docs/m.css/documentation/doxygen.py "mcss-conf.py" --no-doxygen --output mcss.log --templates "$TRAVIS_BUILD_DIR/code_docs/m.css/documentation/templates/EnviroDIY" --debug > mcss-doxy-output.log diff --git a/travis/install-current-doxygen.sh b/continuous_integration/install-current-doxygen.sh similarity index 100% rename from travis/install-current-doxygen.sh rename to continuous_integration/install-current-doxygen.sh diff --git a/docs/Doxyfile b/docs/Doxyfile index 633b560..2167b1e 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SDI-12 for Arduino" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 2.1.2 +PROJECT_NUMBER = 2.1.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/docs/fixXmlSections.py b/docs/fixXmlExampleSections.py similarity index 54% rename from docs/fixXmlSections.py rename to docs/fixXmlExampleSections.py index f8c3439..539bdc8 100644 --- a/docs/fixXmlSections.py +++ b/docs/fixXmlExampleSections.py @@ -12,25 +12,14 @@ abs_file_path = os.path.abspath(os.path.realpath(abs_file_path)) # print("XML Directory: {}".format(fileDir)) -output_file = "examples.dox" -read_mes = [ - # '../Arduino-SDI-12Doxygen/xml_8ino-example.xml', - "../../Arduino-SDI-12Doxygen/xml/a_wild_card_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/b_address_change_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/c_check_all_addresses_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/d_simple_logger_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/e_simple_parsing_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/f_basic_data_request_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/g_terminal_window_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/h_SDI-12_slave_implementation_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/i_SDI-12_interface_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/j_external_pcint_library_8ino-example.xml", - "../../Arduino-SDI-12Doxygen/xml/k_concurrent_logger_8ino-example.xml", +all_files = [ + f + for f in os.listdir(abs_file_path) + if os.path.isfile(os.path.join(abs_file_path, f)) and f.endswith("8ino-example.xml") ] -all_files = [f for f in os.listdir(abs_file_path) if os.path.isfile(os.path.join(abs_file_path, f))] for filename in all_files: - # print(filename) + print(filename) tree = ET.parse(os.path.join(abs_file_path, filename)) root = tree.getroot() @@ -58,6 +47,12 @@ if needs_to_be_fixed: tree.write(os.path.join(abs_file_path, filename + "_fixed")) - os.rename(os.path.join(abs_file_path, filename), os.path.join(abs_file_path, filename + "_original")) - os.rename(os.path.join(abs_file_path, filename + "_fixed"), os.path.join(abs_file_path, filename)) + os.rename( + os.path.join(abs_file_path, filename), + os.path.join(abs_file_path, filename + "_original"), + ) + os.rename( + os.path.join(abs_file_path, filename + "_fixed"), + os.path.join(abs_file_path, filename), + ) # print() diff --git a/examples/d_simple_logger/d_simple_logger.ino b/examples/d_simple_logger/d_simple_logger.ino index 80b2c4d..61375f4 100644 --- a/examples/d_simple_logger/d_simple_logger.ino +++ b/examples/d_simple_logger/d_simple_logger.ino @@ -232,7 +232,7 @@ void setup() { // Quickly Scan the Address Space Serial.println("Scanning all addresses, please wait..."); - Serial.println("Protocol Version, Sensor Address, Sensor Vendor, Sensor Model, " + Serial.println("Sensor Address, Protocol Version, Sensor Vendor, Sensor Model, " "Sensor Version, Sensor ID"); for (byte i = 0; i < 62; i++) { @@ -254,23 +254,28 @@ void setup() { } Serial.println(); - Serial.println("Time Elapsed (s), Est Measurement Time (s), Number Measurements, " - "Real Measurement Time (ms), Measurement 1, Measurement 2, ... etc."); + Serial.println( + "Time Elapsed (s), Sensor Address, Est Measurement Time (s), Number Measurements, " + "Real Measurement Time (ms), Measurement 1, Measurement 2, ... etc."); Serial.println( "-------------------------------------------------------------------------------"); } void loop() { - // measure one at a time - for (byte i = 0; i < 62; i++) { - char addr = decToChar(i); - if (isActive[i]) { - Serial.print(millis() / 1000); - Serial.print(", "); - takeMeasurement(addr); - Serial.println(); + String commands[] = {"", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; + for (uint8_t a = 0; a < 3; a++) { + // measure one at a time + for (byte i = 0; i < 62; i++) { + char addr = decToChar(i); + if (isActive[i]) { + // Serial.print(millis() / 1000); + Serial.print(millis()); + Serial.print(", "); + takeMeasurement(addr, commands[a]); + Serial.println(); + } } } - delay(10000); // wait ten seconds between measurement attempts. + delay(10000L); // wait ten seconds between measurement attempts. } diff --git a/examples/e_continuous_measurement/ReadMe.md b/examples/e_continuous_measurement/ReadMe.md new file mode 100644 index 0000000..43653d2 --- /dev/null +++ b/examples/e_continuous_measurement/ReadMe.md @@ -0,0 +1,18 @@ +[//]: # ( @page example_e_page Example E: Check all Addresses for Active Sensors and Start Continuous Measurements ) +## Example E: Check all Addresses for Active Sensors and Start Continuous Measurements + +This is a simple demonstration of the SDI-12 library for Arduino. + +It discovers the address of all sensors active on a single bus and takes continuous measurements from them. + +Every SDI-12 device is different in the time it takes to take a measurement, and the amount of data it returns. This sketch will not serve every sensor type, but it will likely be helpful in getting you started. + +Each sensor should have a unique address already - if not, multiple sensors may respond simultaneously to the same request and the output will not be readable by the Arduino. + +To address a sensor, please see Example B: b_address_change.ino + +[//]: # ( @section e_continuous_measurement_pio PlatformIO Configuration ) + +[//]: # ( @include{lineno} e_continuous_measurement/platformio.ini ) + +[//]: # ( @section e_continuous_measurement_code The Complete Example ) diff --git a/examples/e_continuous_measurement/e_continuous_measurement.ino b/examples/e_continuous_measurement/e_continuous_measurement.ino new file mode 100644 index 0000000..d3be64d --- /dev/null +++ b/examples/e_continuous_measurement/e_continuous_measurement.ino @@ -0,0 +1,220 @@ +/** + * @file d_simple_logger.ino + * @copyright (c) 2013-2020 Stroud Water Research Center (SWRC) + * and the EnviroDIY Development Team + * This example is published under the BSD-3 license. + * @author Kevin M.Smith + * @date August 2013 + * + * @brief Example D: Check all Addresses for Active Sensors and Log Data + * + * This is a simple demonstration of the SDI-12 library for Arduino. + * + * It discovers the address of all sensors active on a single bus and takes continuous + * measurements from them. + */ + +#include + +#define SERIAL_BAUD 115200 /*!< The baud rate for the output serial port */ +#define DATA_PIN 7 /*!< The pin of the SDI-12 data bus */ +#define POWER_PIN 22 /*!< The sensor power pin (or -1 if not switching power) */ + +/** Define the SDI-12 bus */ +SDI12 mySDI12(DATA_PIN); + +// keeps track of active addresses +bool isActive[64] = { + 0, +}; + +uint8_t numSensors = 0; + + +/** + * @brief converts allowable address characters ('0'-'9', 'a'-'z', 'A'-'Z') to a + * decimal number between 0 and 61 (inclusive) to cover the 62 possible + * addresses. + */ +byte charToDec(char i) { + if ((i >= '0') && (i <= '9')) return i - '0'; + if ((i >= 'a') && (i <= 'z')) return i - 'a' + 10; + if ((i >= 'A') && (i <= 'Z')) + return i - 'A' + 36; + else + return i; +} + +/** + * @brief maps a decimal number between 0 and 61 (inclusive) to allowable + * address characters '0'-'9', 'a'-'z', 'A'-'Z', + * + * THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. + */ +char decToChar(byte i) { + if (i < 10) return i + '0'; + if ((i >= 10) && (i < 36)) return i + 'a' - 10; + if ((i >= 36) && (i <= 62)) + return i + 'A' - 36; + else + return i; +} + +/** + * @brief gets identification information from a sensor, and prints it to the serial + * port + * + * @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'. + */ +void printInfo(char i) { + String command = ""; + command += (char)i; + command += "I!"; + mySDI12.sendCommand(command); + delay(100); + + String sdiResponse = mySDI12.readStringUntil('\n'); + sdiResponse.trim(); + // allccccccccmmmmmmvvvxxx...xx + Serial.print(sdiResponse.substring(0, 1)); // address + Serial.print(", "); + Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number + Serial.print(", "); + Serial.print(sdiResponse.substring(3, 11)); // vendor id + Serial.print(", "); + Serial.print(sdiResponse.substring(11, 17)); // sensor model + Serial.print(", "); + Serial.print(sdiResponse.substring(17, 20)); // sensor version + Serial.print(", "); + Serial.print(sdiResponse.substring(20)); // sensor id + Serial.print(", "); +} + +bool getContinuousResults(char i, int resultsExpected) { + uint8_t resultsReceived = 0; + uint8_t cmd_number = 0; + while (resultsReceived < resultsExpected && cmd_number <= 9) { + String command = ""; + // in this example we will only take the 'DO' measurement + command = ""; + command += i; + command += "R"; + command += cmd_number; + command += "!"; // SDI-12 command to get data [address][D][dataOption][!] + mySDI12.sendCommand(command); + + uint32_t start = millis(); + while (mySDI12.available() < 3 && (millis() - start) < 1500) {} + mySDI12.read(); // ignore the repeated SDI12 address + char c = mySDI12.peek(); // check if there's a '+' and toss if so + if (c == '+') { mySDI12.read(); } + + while (mySDI12.available()) { + char c = mySDI12.peek(); + if (c == '-' || (c >= '0' && c <= '9') || c == '.') { + float result = mySDI12.parseFloat(SKIP_NONE); + Serial.print(String(result, 10)); + if (result != -9999) { resultsReceived++; } + } else if (c == '+') { + mySDI12.read(); + Serial.print(", "); + } else { + mySDI12.read(); + } + delay(10); // 1 character ~ 7.5ms + } + if (resultsReceived < resultsExpected) { Serial.print(", "); } + cmd_number++; + } + mySDI12.clearBuffer(); + + return resultsReceived == resultsExpected; +} + +// this checks for activity at a particular address +// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z' +boolean checkActive(char i) { + String myCommand = ""; + myCommand = ""; + myCommand += (char)i; // sends basic 'acknowledge' command [address][!] + myCommand += "!"; + + for (int j = 0; j < 3; j++) { // goes through three rapid contact attempts + mySDI12.sendCommand(myCommand); + delay(100); + if (mySDI12.available()) { // If we here anything, assume we have an active sensor + mySDI12.clearBuffer(); + return true; + } + } + mySDI12.clearBuffer(); + return false; +} + + +void setup() { + Serial.begin(SERIAL_BAUD); + while (!Serial) + ; + + Serial.println("Opening SDI-12 bus..."); + mySDI12.begin(); + delay(500); // allow things to settle + + Serial.println("Timeout value: "); + Serial.println(mySDI12.TIMEOUT); + + // Power the sensors; + if (POWER_PIN > 0) { + Serial.println("Powering up sensors..."); + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); + delay(200); + } + + // Quickly Scan the Address Space + Serial.println("Scanning all addresses, please wait..."); + Serial.println("Sensor Address, Protocol Version, Sensor Vendor, Sensor Model, " + "Sensor Version, Sensor ID"); + + for (byte i = 0; i < 62; i++) { + char addr = decToChar(i); + if (checkActive(addr)) { + numSensors++; + isActive[i] = 1; + printInfo(addr); + Serial.println(); + } + } + Serial.print("Total number of sensors found: "); + Serial.println(numSensors); + + if (numSensors == 0) { + Serial.println( + "No sensors found, please check connections and restart the Arduino."); + while (true) { delay(10); } // do nothing forever + } + + Serial.println(); + Serial.println( + "Time Elapsed (s), Sensor Address, Est Measurement Time (s), Number Measurements, " + "Real Measurement Time (ms), Measurement 1, Measurement 2, ... etc."); + Serial.println( + "-------------------------------------------------------------------------------"); +} + +void loop() { + // measure one at a time + for (byte i = 0; i < 62; i++) { + char addr = decToChar(i); + if (isActive[i]) { + // Serial.print(millis() / 1000); + Serial.print(millis()); + Serial.print(", "); + getContinuousResults(addr, 4); + Serial.println(); + } + } + + delay(5000L); // wait ten seconds between measurement attempts. +} diff --git a/library.json b/library.json index 2175b78..ffad197 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "SDI-12", - "version": "2.1.2", + "version": "2.1.3", "keywords": "SDI-12, sdi12, communication, bus, sensor, Decagon", "description": "An Arduino library for SDI-12 communication with a wide variety of environmental sensors.", "repository": { diff --git a/library.properties b/library.properties index 4116a8e..c5b7c28 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SDI-12 -version=2.1.2 +version=2.1.3 author=Kevin M. Smith , Shannon Hicks maintainer=Sara Damiano sentence=An Arduino library for SDI-12 communication with a wide variety of environmental sensors. diff --git a/tools/TestCommands/TestCommands.ino b/tools/TestCommands/TestCommands.ino new file mode 100644 index 0000000..9b5f447 --- /dev/null +++ b/tools/TestCommands/TestCommands.ino @@ -0,0 +1,651 @@ +/** + * @file d_simple_logger.ino + * @copyright (c) 2013-2020 Stroud Water Research Center (SWRC) + * and the EnviroDIY Development Team + * This example is published under the BSD-3 license. + * @author Kevin M.Smith + * @date August 2013 + * + * @brief Example D: Check all Addresses for Active Sensors and Log Data + * + * This is a simple demonstration of the SDI-12 library for Arduino. + * + * It discovers the address of all sensors active on a single bus and takes measurements + * from them. + * + * Every SDI-12 device is different in the time it takes to take a + * measurement, and the amount of data it returns. This sketch will not serve every + * sensor type, but it will likely be helpful in getting you started. + * + * Each sensor should have a unique address already - if not, multiple sensors may + * respond simultaenously to the same request and the output will not be readable by the + * Arduino. + * + * To address a sensor, please see Example B: b_address_change.ino + */ + +#include + +#define SERIAL_BAUD 115200 /*!< The baud rate for the output serial port */ +#define DATA_PIN 7 /*!< The pin of the SDI-12 data bus */ +#define POWER_PIN 22 /*!< The sensor power pin (or -1 if not switching power) */ +#define FIRST_ADDRESS 0 +#define LAST_ADDRESS 1 // 62 +#define WAKE_DELAY 0 /*!< The extra time needed for the board to wake. */ +#define COMMANDS_TO_TEST \ + 10 /*!< The number of measurement commands to test, between 1 and 10. */ + +/** Define the SDI-12 bus */ +SDI12 mySDI12(DATA_PIN); + +/// variable that alternates output type back and forth between parsed and raw +boolean flip = 0; + +String commands[] = {"2", "2", "2", "2", "2", "2", "2", "2", "", "1", "3", "4", "5", "6", "7", "8", "9"}; + +// keeps track of active addresses +bool isActive[LAST_ADDRESS - FIRST_ADDRESS] = { + 0, +}; + +// keeps track of the wait time for each active addresses +uint8_t waitTime[LAST_ADDRESS - FIRST_ADDRESS] = { + 0, +}; + +// keeps track of the time each sensor was started +uint32_t millisStarted[LAST_ADDRESS - FIRST_ADDRESS] = { + 0, +}; + +// keeps track of the time each sensor will be ready +uint32_t millisReady[LAST_ADDRESS - FIRST_ADDRESS] = { + 0, +}; + +// keeps track of the number of results expected +uint8_t returnedResults[LAST_ADDRESS - FIRST_ADDRESS] = { + 0, +}; + + +String prev_result[LAST_ADDRESS - FIRST_ADDRESS] = { + "", +}; +String this_result[LAST_ADDRESS - FIRST_ADDRESS] = { + "", +}; +uint8_t numSensors = 0; + + +/** + * @brief converts allowable address characters ('0'-'9', 'a'-'z', 'A'-'Z') to a + * decimal number between 0 and 61 (inclusive) to cover the 62 possible + * addresses. + */ +byte charToDec(char i) { + if ((i >= '0') && (i <= '9')) return i - '0'; + if ((i >= 'a') && (i <= 'z')) return i - 'a' + 10; + if ((i >= 'A') && (i <= 'Z')) + return i - 'A' + 36; + else + return i; +} + +/** + * @brief maps a decimal number between 0 and 61 (inclusive) to allowable + * address characters '0'-'9', 'a'-'z', 'A'-'Z', + * + * THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. + */ +char decToChar(byte i) { + if (i < 10) return i + '0'; + if ((i >= 10) && (i < 36)) return i + 'a' - 10; + if ((i >= 36) && (i <= 62)) + return i + 'A' - 36; + else + return i; +} + +/** + * @brief gets identification information from a sensor, and prints it to the serial + * port + * + * @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'. + */ +void printInfo(char i, bool printCommands = true) { + String command = ""; + command += (char)i; + command += "I!"; + mySDI12.sendCommand(command, WAKE_DELAY); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + delay(100); + + String sdiResponse = mySDI12.readStringUntil('\n'); + sdiResponse.trim(); + // allccccccccmmmmmmvvvxxx...xx + if (printCommands) { + Serial.print("<<<"); + Serial.println(sdiResponse); + } + + Serial.print("Address: "); + Serial.print(sdiResponse.substring(0, 1)); // address + Serial.print(", SDI-12 Version: "); + Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number + Serial.print(", Vendor ID: "); + Serial.print(sdiResponse.substring(3, 11)); // vendor id + Serial.print(", Sensor Model: "); + Serial.print(sdiResponse.substring(11, 17)); // sensor model + Serial.print(", Sensor Version: "); + Serial.print(sdiResponse.substring(17, 20)); // sensor version + Serial.print(", Sensor ID: "); + Serial.print(sdiResponse.substring(20)); // sensor id + Serial.println(); +} + +bool getResults(char i, int resultsExpected, bool printCommands = true) { + uint8_t resultsReceived = 0; + uint8_t cmd_number = 0; + // while (resultsReceived < resultsExpected && cmd_number <= 9) { + while (resultsReceived < resultsExpected && cmd_number <= 1) { + String command = ""; + // in this example we will only take the 'DO' measurement + command = ""; + command += i; + command += "D"; + command += cmd_number; + command += "!"; // SDI-12 command to get data [address][D][dataOption][!] + mySDI12.sendCommand(command, WAKE_DELAY); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + + uint32_t start = millis(); + while (mySDI12.available() < 3 && (millis() - start) < 1500) {} + if (printCommands) { + Serial.print("<<<"); + Serial.write(mySDI12.read()); // ignore the repeated SDI12 address + } else { + mySDI12.read(); + } + + while (mySDI12.available()) { + char c = mySDI12.peek(); + if (c == '-' || (c >= '0' && c <= '9') || c == '.') { + float result = mySDI12.parseFloat(SKIP_NONE); + Serial.print(String(result, 10)); + if (result != -9999) { resultsReceived++; } + } else if (c >= 0 && c != '\r' && c != '\n') { + Serial.write(mySDI12.read()); + } else { + mySDI12.read(); + } + delay(10); // 1 character ~ 7.5ms + } + if (printCommands) { + Serial.print("Total Results Received: "); + Serial.print(resultsReceived); + Serial.print(", Remaining: "); + Serial.println(resultsExpected - resultsReceived); + } + if (!resultsReceived) { break; } // don't do another loop if we got nothing + cmd_number++; + } + mySDI12.clearBuffer(); + + return resultsReceived == resultsExpected; +} + +String getStringResults(char i, int resultsExpected, bool printCommands = true) { + uint8_t resultsReceived = 0; + uint8_t cmd_number = 0; + String str_result = ""; + while (resultsReceived < resultsExpected && cmd_number <= 9) { + // while (resultsReceived < resultsExpected && cmd_number <= 1) { + String command = ""; + // in this example we will only take the 'DO' measurement + command = ""; + command += i; + command += "D"; + command += cmd_number; + command += "!"; // SDI-12 command to get data [address][D][dataOption][!] + mySDI12.sendCommand(command, WAKE_DELAY); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + + uint32_t start = millis(); + while (mySDI12.available() < 3 && (millis() - start) < 150) {} + if (printCommands) { + Serial.print("<<<"); + Serial.write(mySDI12.read()); // ignore the repeated SDI12 address + } else { + mySDI12.read(); + } + + while (mySDI12.available()) { + char c = mySDI12.peek(); + if (c == '-' || (c >= '0' && c <= '9') || c == '.') { + float result = mySDI12.parseFloat(SKIP_NONE); + str_result += String(result, 8); + if (printCommands) { Serial.print(String(result, 8)); } + if (result != -9999) { resultsReceived++; } + } else if (c >= 0 && c != '\r' && c != '\n') { + str_result += String(c); + if (printCommands) { + Serial.write(mySDI12.read()); + } else { + mySDI12.read(); + } + } else { + mySDI12.read(); + } + delay(10); // 1 character ~ 7.5ms + } + if (printCommands) { + Serial.print("\nTotal Results Received: "); + Serial.print(resultsReceived); + Serial.print(", Remaining: "); + Serial.println(resultsExpected - resultsReceived); + } + if (!resultsReceived) { break; } // don't do another loop if we got nothing + cmd_number++; + } + mySDI12.clearBuffer(); + + return str_result; +} + +bool getContinuousResults(char i, int resultsExpected, bool printCommands = true) { + uint8_t resultsReceived = 0; + uint8_t cmd_number = 0; + while (resultsReceived < resultsExpected && cmd_number <= 9) { + String command = ""; + // in this example we will only take the 'DO' measurement + command = ""; + command += i; + command += "R"; + command += cmd_number; + command += "!"; // SDI-12 command to get data [address][D][dataOption][!] + mySDI12.sendCommand(command, WAKE_DELAY); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + + uint32_t start = millis(); + while (mySDI12.available() < 3 && (millis() - start) < 1500) {} + if (printCommands) { + Serial.print("<<<"); + Serial.write(mySDI12.read()); // ignore the repeated SDI12 address + } + + while (mySDI12.available()) { + char c = mySDI12.peek(); + if (c == '-' || (c >= '0' && c <= '9') || c == '.') { + float result = mySDI12.parseFloat(SKIP_NONE); + Serial.print(String(result, 10)); + if (result != -9999) { resultsReceived++; } + } else if (c >= 0 && c != '\r' && c != '\n') { + Serial.write(mySDI12.read()); + } else { + mySDI12.read(); + } + delay(10); // 1 character ~ 7.5ms + } + if (printCommands) { + Serial.print("Total Results Received: "); + Serial.print(resultsReceived); + Serial.print(", Remaining: "); + Serial.println(resultsExpected - resultsReceived); + } + if (!resultsReceived) { break; } // don't do another loop if we got nothing + cmd_number++; + } + mySDI12.clearBuffer(); + + return resultsReceived == resultsExpected; +} + +int startConcurrentMeasurement(char i, String meas_type = "", + bool printCommands = true) { + String command = ""; + command += i; + command += "C"; + command += meas_type; + command += "!"; // SDI-12 concurrent measurement command format [address]['C'][!] + mySDI12.sendCommand(command, WAKE_DELAY); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + delay(100); + + // wait for acknowlegement with format [address][ttt (3 char, seconds)][number of + // measurments available, 0-9] + String sdiResponse = mySDI12.readStringUntil('\n'); + sdiResponse.trim(); + if (printCommands) { + Serial.print("<<<"); + Serial.println(sdiResponse); + } + mySDI12.clearBuffer(); + + // find out how long we have to wait (in seconds). + uint8_t wait = sdiResponse.substring(1, 4).toInt(); + if (printCommands) { + Serial.print("wait: "); + Serial.print(wait); + Serial.print(", "); + } + + // Set up the number of results to expect + int numResults = sdiResponse.substring(4).toInt(); + if (printCommands) { + Serial.print("Number Results: "); + Serial.println(numResults); + } + + uint8_t sensorNum = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. + waitTime[sensorNum] = wait; + millisStarted[sensorNum] = millis(); + if (wait == 0) { + millisReady[sensorNum] = millis(); + } else { + millisReady[sensorNum] = millis() + (wait + 1 * 1000); + } + returnedResults[sensorNum] = numResults; + + return numResults; +} + +String takeMeasurement(char i, String meas_type = "", bool printCommands = true) { + String command = ""; + command += i; + command += "M"; + command += meas_type; + command += "!"; // SDI-12 measurement command format [address]['M'][!] + mySDI12.sendCommand(command, WAKE_DELAY); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + delay(100); + + // wait for acknowlegement with format [address][ttt (3 char, seconds)][number of + // measurments available, 0-9] + String sdiResponse = mySDI12.readStringUntil('\n'); + sdiResponse.trim(); + if (printCommands) { + Serial.print("<<<"); + Serial.println(sdiResponse); + } + + // find out how long we have to wait (in seconds). + uint8_t wait = sdiResponse.substring(1, 4).toInt(); + if (printCommands) { + Serial.print("Wait: "); + Serial.print(wait); + Serial.print(", "); + } + + // Set up the number of results to expect + int numResults = sdiResponse.substring(4).toInt(); + if (printCommands) { + Serial.print("Number Results: "); + Serial.println(numResults); + } + // if (numResults==0){return false;} + if (numResults == 0) { return ""; } + + unsigned long timerStart = millis(); + while ((millis() - timerStart) < ((uint16_t)1000 * (wait + 1))) { + if (mySDI12.available()) // sensor can interrupt us to let us know it is done early + { + unsigned long measTime = millis() - timerStart; + if (printCommands) { + Serial.print("<<<"); + Serial.println(mySDI12.readStringUntil('\n')); + // mySDI12.clearBuffer(); + } + Serial.print("Completed after "); + Serial.print(measTime); + Serial.println(" ms"); + break; + } + } + // Wait for anything else and clear it out + delay(30); + mySDI12.clearBuffer(); + + // return getResults(i, numResults,printCommands); + String res= getStringResults(i, numResults, printCommands); + Serial.print("Result: "); + Serial.println(res); + return res; +} + +// this checks for activity at a particular address +// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z' +boolean checkActive(char i, int8_t numPings = 3, bool printCommands = false) { + String command = ""; + command += (char)i; // sends basic 'acknowledge' command [address][!] + command += "!"; + + for (int j = 0; j < numPings; j++) { // goes through three rapid contact attempts + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + mySDI12.sendCommand(command, WAKE_DELAY); + delay(100); + if (mySDI12.available()) { // If we here anything, assume we have an active sensor + if (printCommands) { + Serial.print("<<<"); + while (mySDI12.available()) { + Serial.write(mySDI12.read()); + delay(10); + } + } else { + mySDI12.clearBuffer(); + } + return true; + } + } + mySDI12.clearBuffer(); + return false; +} + + +void setup() { + Serial.begin(SERIAL_BAUD); + while (!Serial) + ; + + Serial.println("Opening SDI-12 bus..."); + mySDI12.begin(); + delay(500); // allow things to settle + + Serial.println("Timeout value: "); + Serial.println(mySDI12.TIMEOUT); + + // Power the sensors; + if (POWER_PIN > 0) { + Serial.println("Powering down sensors..."); + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, LOW); + delay(2500L); + } + + // Power the sensors; + if (POWER_PIN > 0) { + Serial.println("Powering up sensors..."); + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); + delay(10000L); + // delay(125); + } + + // Quickly Scan the Address Space + Serial.println("Scanning all addresses, please wait..."); + + for (byte i = FIRST_ADDRESS; i < LAST_ADDRESS; i++) { + char addr = decToChar(i); + Serial.print("i: "); + Serial.print(i); + Serial.print(", addr: "); + Serial.print(addr); + Serial.print(", rev: "); + Serial.print(charToDec(addr)); + if (checkActive(addr, 5, true)) { + numSensors++; + isActive[i] = 1; + Serial.println(", +"); + printInfo(addr); + } else { + Serial.println(", -"); + } + } + Serial.print("Total number of sensors found: "); + Serial.println(numSensors); + + if (numSensors == 0) { + Serial.println( + "No sensors found, please check connections and restart the Arduino."); + while (true) { delay(10); } // do nothing forever + } + + Serial.println(); + Serial.println("-------------------------------------------------------------------" + "------------"); + + delay(1000); +} + +void loop() { + flip = !flip; // flip the switch between concurrent and not + // flip = 1; + // flip = 0; + uint32_t start = millis(); + Serial.print("Flip: "); + Serial.println(flip); + + // // Power the sensors; + // if (POWER_PIN > 0) { + // Serial.println("Powering down sensors..."); + // pinMode(POWER_PIN, OUTPUT); + // digitalWrite(POWER_PIN, LOW); + // delay(5000L); + // } + + // // Power the sensors; + // if (POWER_PIN > 0) { + // Serial.println("Powering up sensors..."); + // pinMode(POWER_PIN, OUTPUT); + // digitalWrite(POWER_PIN, HIGH); + // delay(125); + // } + + if (flip) { + // measure one at a time + for (byte i = FIRST_ADDRESS; i < LAST_ADDRESS; i++) { + char addr = decToChar(i); + if (isActive[i]) { + for (uint8_t a = 0; a < COMMANDS_TO_TEST; a++) { + Serial.print("Command "); + Serial.println(commands[a]); + this_result[i] = takeMeasurement(addr, commands[a], false); + } + // getContinuousResults(addr, 3); + Serial.println(); + } + } + Serial.print("Total Time for Individual Measurements: "); + Serial.println(millis() - start); + } else { + for (uint8_t a = 0; a < COMMANDS_TO_TEST; a++) { + Serial.print("Command "); + Serial.println(commands[a]); + uint8_t min_wait = 127; + uint8_t max_wait = 0; + uint32_t for_start = millis(); + // start all sensors measuring concurrently + for (byte i = FIRST_ADDRESS; i < LAST_ADDRESS; i++) { + char addr = decToChar(i); + if (isActive[i]) { startConcurrentMeasurement(addr, commands[a], false); } + if (waitTime[i] < min_wait) { min_wait = waitTime[i]; } + if (waitTime[i] > max_wait) { max_wait = waitTime[i]; } + } + min_wait = max(0, (min_wait - 1) / 2); + max_wait = max(1, max_wait + 1); + // Serial.print("minimum expected wait: "); + // Serial.println(min_wait); + // Serial.print("maximum expected wait: "); + // Serial.println(max_wait); + + + uint8_t numReadingsRecorded = 0; + delay(min_wait * 1000); + while (millis() - for_start < max_wait * 1000 && + numReadingsRecorded < numSensors) { + // get all readings + for (byte i = FIRST_ADDRESS; i < LAST_ADDRESS; i++) { + uint32_t timeWaited = millis() - millisStarted[i]; + if (this_result[i] != "") { prev_result[i] = this_result[i]; } + + char addr = decToChar(i); + if (isActive[i]) { + // if (millis() > millisReady[i]) { + // if (millis() > millisStarted[i] + a) { + if (returnedResults[i] > 0) { + this_result[i] = getStringResults(addr, returnedResults[i], false); + // if (this_result[i] != "") { + // Serial.print("timeWaited: "); + // Serial.print(timeWaited); + // Serial.print(", This result: "); + // Serial.println(this_result[i]); + // Serial.print(" , prev result: "); + // Serial.println(prev_result[i]); + // } else { + // Serial.print("timeWaited: "); + // Serial.println(timeWaited); + // } + // this_result = getResults(addr, returnedResults[i]); + // Serial.print("Got results from "); + // Serial.print(numReadingsRecorded); + // Serial.print(" of "); + // Serial.print(numSensors); + // Serial.println(" sensors"); + } + if (this_result[i] != prev_result[i] && this_result[i] != "") { + numReadingsRecorded++; + Serial.print("Time Waited: "); + Serial.println(timeWaited); + Serial.print("Result: "); + Serial.println(this_result[i]); + } + // } else { + // Serial.print("Result from "); + // Serial.print(addr); + // Serial.print(" won't be ready for "); + // Serial.print(millisReady[i] - millis()); + // Serial.println(" ms "); + // } + } + } + } + } + Serial.print("Total Time for Concurrent Measurements: "); + Serial.println(millis() - start); + } + + Serial.println("-------------------------------------------------------------------" + "------------"); + // delay(1000); // wait ten seconds between measurement attempts. +} diff --git a/tools/TestWarmUp/TestWarmUp.ino b/tools/TestWarmUp/TestWarmUp.ino new file mode 100644 index 0000000..072339d --- /dev/null +++ b/tools/TestWarmUp/TestWarmUp.ino @@ -0,0 +1,156 @@ +/** + * @file d_simple_logger.ino + * @copyright (c) 2013-2020 Stroud Water Research Center (SWRC) + * and the EnviroDIY Development Team + * This example is published under the BSD-3 license. + * @author Sara Damiano + * @date March 2021 + */ + +#include + +#define SERIAL_BAUD 115200 /*!< The baud rate for the output serial port */ +#define DATA_PIN 7 /*!< The pin of the SDI-12 data bus */ +#define SENSOR_ADDRESS '0' /*!< The address of the SDI-12 sensor */ +#define POWER_PIN 22 /*!< The sensor power pin (or -1 if not switching power) */ + +/** Define the SDI-12 bus */ +SDI12 mySDI12(DATA_PIN); +int32_t wake_delay = 0; /*!< The time for the board to wake after a line break. */ +int32_t increment_wake = 10; /*!< The time to lengthen waits between reps. */ +int32_t power_delay = 5400; /*!< The time for the board to wake after power on. */ +int32_t increment_power = 50; /*!< The time to lengthen waits between reps. */ +int32_t max_power_delay = 10000L; /*!< The max time to test wake after power on. */ + +/** + * @brief gets identification information from a sensor, and prints it to the serial + * port + * + * @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'. + */ +bool printInfo(char i, bool printCommands = true) { + String command = ""; + command += (char)i; + command += "I!"; + mySDI12.sendCommand(command, wake_delay); + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + delay(100); + + String sdiResponse = mySDI12.readStringUntil('\n'); + sdiResponse.trim(); + // allccccccccmmmmmmvvvxxx...xx + if (printCommands) { + Serial.print("<<<"); + Serial.println(sdiResponse); + } + + Serial.print("Address: "); + Serial.print(sdiResponse.substring(0, 1)); // address + Serial.print(", SDI-12 Version: "); + Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number + Serial.print(", Vendor ID: "); + Serial.print(sdiResponse.substring(3, 11)); // vendor id + Serial.print(", Sensor Model: "); + Serial.print(sdiResponse.substring(11, 17)); // sensor model + Serial.print(", Sensor Version: "); + Serial.print(sdiResponse.substring(17, 20)); // sensor version + Serial.print(", Sensor ID: "); + Serial.print(sdiResponse.substring(20)); // sensor id + Serial.println(); + + if (sdiResponse.length() < 3) { return false; }; + return true; +} + +// this checks for activity at a particular address +// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z' +boolean checkActive(char i, int8_t numPings = 3, bool printCommands = false) { + String command = ""; + command += (char)i; // sends basic 'acknowledge' command [address][!] + command += "!"; + + for (int j = 0; j < numPings; j++) { // goes through three rapid contact attempts + if (printCommands) { + Serial.print(">>>"); + Serial.println(command); + } + mySDI12.sendCommand(command, wake_delay); + delay(100); + if (mySDI12.available()) { // If we here anything, assume we have an active sensor + if (printCommands) { + Serial.print("<<<"); + while (mySDI12.available()) { + Serial.write(mySDI12.read()); + delay(10); + } + } else { + mySDI12.clearBuffer(); + } + return true; + } + } + mySDI12.clearBuffer(); + return false; +} + + +void setup() { + Serial.begin(SERIAL_BAUD); + while (!Serial) + ; + + Serial.println("Opening SDI-12 bus..."); + mySDI12.begin(); + delay(500); // allow things to settle + + Serial.println("Timeout value: "); + Serial.println(mySDI12.TIMEOUT); +} + +void loop() { + // Power the sensors; + if (POWER_PIN > 0) { + Serial.println("Powering down sensors..."); + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, LOW); + delay(2500L); + } + + // Power the sensors; + if (POWER_PIN > 0) { + Serial.println("Powering up sensors..."); + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); + delay(power_delay); + } + + if (checkActive(SENSOR_ADDRESS, 5, true)) { + Serial.print("Got response after "); + Serial.print(power_delay); + Serial.print("ms after power with "); + Serial.print(wake_delay); + Serial.println("ms with wake delay"); + if (printInfo(SENSOR_ADDRESS, true)) { + // if we got sensor info, stop + while (1) + ; + } + } else { + Serial.print("No response after "); + Serial.print(power_delay); + Serial.print("ms after power with "); + Serial.print(wake_delay); + Serial.println("ms with wake delay"); + } + Serial.println("-------------------------------------------------------------------" + "------------"); + if (power_delay > max_power_delay) { + power_delay = 0; + wake_delay = wake_delay + increment_wake; + } else { + power_delay = power_delay + increment_power; + } +} diff --git a/tools/powerOn/powerOn.ino b/tools/powerOn/powerOn.ino new file mode 100644 index 0000000..ae244ae --- /dev/null +++ b/tools/powerOn/powerOn.ino @@ -0,0 +1,14 @@ +#include + +int8_t powerPin = 22; + +void setup() { + pinMode(powerPin, OUTPUT); + digitalWrite(powerPin, HIGH); + pinMode(A5, OUTPUT); + digitalWrite(A5, HIGH); + pinMode(10, OUTPUT); + digitalWrite(10, HIGH); +} + +void loop() {}