diff --git a/.gitignore b/.gitignore index b2e64cd5..bac35db9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ *.o *.so +#vscode host dependent file +firmware/.vscode/c_cpp_properties.json + # Packages # *.7z *.dmg @@ -14,7 +17,6 @@ *.jar *.rar *.tar -*.zip # Logs and databases # *.log @@ -25,3 +27,7 @@ .DS_Store .DS_Store? ._* + +/firmware/lora-e5/Debug + +/Debug \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..7c538c6e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 NYU FloodSense + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 3afab35d..05c58a25 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ -This repository is updated for TTN v3 download this library and also remove the old lmic library from arduino libraries and download the latest library from [here](https://github.com/mcci-catena/arduino-lmic) -# FloodSense Sensor Technical Documentation -[This repository](https://github.com/floodsense/floodsense_sensor) contains the source code for the Floodsense sensor which uses ultrasonic sensor technology to detect floods and send the data over LoRa using LoRaWAN protocol. [Here](https://github.com/floodsense/sensor_experiments) is the experiments repo containing technical documentation, analysis and additional support related to this library. +# FloodSense Sensor Library +[This](https://github.com/floodsense/floodsense_sensor) repository contains the source code for the FloodSense sensor which captures real-time street-level flood information and sends the flood data over LoRa using LoRaWAN protocol. [Here](https://github.com/floodsense/sensor_experiments) is a link to the sensor experiments repo containing experimental results, analysis and additional source code and support related to this library. **Table of Contents:** @@ -523,7 +522,7 @@ On the latest 1.3.2 version of the Adafruit's Sleepy_dog library, a strange rese ; // Wait for it to take #else SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; - // Due to a hardware bug on the SAMD21, the SysTick interrupts become + // Due to a hardware bug on the SAMD21, the SysTick interrupts become // active before the flash has powered up from sleep, causing a hard fault. // To prevent this the SysTick interrupts are disabled before entering sleep mode. SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; // Disable SysTick interrupts @@ -535,7 +534,7 @@ On the latest 1.3.2 version of the Adafruit's Sleepy_dog library, a strange rese #if (SAMD20_SERIES || SAMD21_SERIES) SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; // Enable SysTick interrupts #endif - + // Code resumes here on wake (WDT early warning interrupt). // Bug: the return value assumes the WDT has run its course; // incorrect if the device woke due to an external interrupt. diff --git a/examples/basic_sensormodes/basic_sensormodes.ino b/examples/basic_sensormodes/basic_sensormodes.ino index abe23e1d..34e6639c 100644 --- a/examples/basic_sensormodes/basic_sensormodes.ino +++ b/examples/basic_sensormodes/basic_sensormodes.ino @@ -44,7 +44,7 @@ void setup() { setup_maxbotix(2, 150, 5); // sensor mode 2(Median), 150ms sampling rate (time between readings), 5 readings per measurement setup_featherWing(); // set up SD card and RTC. Sets date and time everytime compiled. - lmicsetup(300); // uplink frequency 300 seconds - controls duty cycle + lmicsetup(30); // uplink frequency 300 seconds - controls duty cycle } void loop() { diff --git a/hardware/img/closeup.png b/hardware/img/closeup.png new file mode 100644 index 00000000..4f4cfcac Binary files /dev/null and b/hardware/img/closeup.png differ diff --git a/hardware/img/pole-mount.png b/hardware/img/pole-mount.png new file mode 100644 index 00000000..c0e6cb7c Binary files /dev/null and b/hardware/img/pole-mount.png differ diff --git a/hardware/img/signpost-mount.png b/hardware/img/signpost-mount.png new file mode 100644 index 00000000..b9636a21 Binary files /dev/null and b/hardware/img/signpost-mount.png differ diff --git a/hardware/readme.md b/hardware/readme.md new file mode 100644 index 00000000..37d630be --- /dev/null +++ b/hardware/readme.md @@ -0,0 +1,19 @@ + +# Mounting hardware +The FloodNet sensor uses readily available hardware for mounting to a variety of street infrastructure. The sensor alone weighs **0.5lb** and the complete assembly including mounting hardware weighs **3lbs**. The typical mounting condition consists of the sensor itself bolted to the underside of a 1 5/8" aluminum strut channel. Aluminum was chosen to reduce the overall load on the cantilever. The 3D printed solar panel is bolted to the top of the strut channel and can be rotated for optimizing sunlight pickup. The mounting hardware can adapt to various conditions. + +

+ +

+ +The most common mounting option is bolted to a U-channel at **>10ft** from the ground. See image below. + +

+ +

+ +The sensor can be mounted to light poles of varying diameter using 300lb steel strapping. The ultrasonic sensors used to detect flood depth typically have a maximum range of 16ft but 32ft models can be added. Light pole mounting on the light overhang would likely require 32ft ultrasonic sensors. See image below for a vertical light mount scenario. + +

+ +

\ No newline at end of file diff --git a/img/add-library.png b/img/add-library.png index 000c6493..6091f21a 100644 Binary files a/img/add-library.png and b/img/add-library.png differ diff --git a/img/assembled-mcu.jpg b/img/assembled-mcu.jpg index f37bc036..4a358b11 100644 Binary files a/img/assembled-mcu.jpg and b/img/assembled-mcu.jpg differ diff --git a/img/components.png b/img/components.png index 08735204..073e5176 100644 Binary files a/img/components.png and b/img/components.png differ diff --git a/img/deployment-render.png b/img/deployment-render.png index b48661ad..a713e32a 100644 Binary files a/img/deployment-render.png and b/img/deployment-render.png differ diff --git a/img/design-data-comparison.png b/img/design-data-comparison.png index 02a3b29c..d5b154d7 100644 Binary files a/img/design-data-comparison.png and b/img/design-data-comparison.png differ diff --git a/img/drilling.jpg b/img/drilling.jpg index 4e1c8b71..fbe80d5b 100644 Binary files a/img/drilling.jpg and b/img/drilling.jpg differ diff --git a/img/final-withoutbatt.jpg b/img/final-withoutbatt.jpg index 0bd90b87..688ade2a 100644 Binary files a/img/final-withoutbatt.jpg and b/img/final-withoutbatt.jpg differ diff --git a/img/fritzingcircuit.png b/img/fritzingcircuit.png index 2da1bf27..8c183b65 100644 Binary files a/img/fritzingcircuit.png and b/img/fritzingcircuit.png differ diff --git a/img/gland-bottom.jpg b/img/gland-bottom.jpg index 4845fa17..aca586ff 100644 Binary files a/img/gland-bottom.jpg and b/img/gland-bottom.jpg differ diff --git a/img/lora-timing.png b/img/lora-timing.png index 11bd8b34..65f00f8b 100644 Binary files a/img/lora-timing.png and b/img/lora-timing.png differ diff --git a/img/low-power-profile.png b/img/low-power-profile.png index 78ad7b82..1eb76b3e 100644 Binary files a/img/low-power-profile.png and b/img/low-power-profile.png differ diff --git a/img/mcu-components.jpg b/img/mcu-components.jpg new file mode 100644 index 00000000..6585e006 Binary files /dev/null and b/img/mcu-components.jpg differ diff --git a/img/modes_cm.png b/img/modes_cm.png index 5293f06b..5046757b 100644 Binary files a/img/modes_cm.png and b/img/modes_cm.png differ diff --git a/img/mounted-mcu-us.jpg b/img/mounted-mcu-us.jpg index cb7fee2f..164daa69 100644 Binary files a/img/mounted-mcu-us.jpg and b/img/mounted-mcu-us.jpg differ diff --git a/img/mountedv2.jpg b/img/mountedv2.jpg index 38e65fda..609e7d99 100644 Binary files a/img/mountedv2.jpg and b/img/mountedv2.jpg differ diff --git a/img/mounting-seperate-solarboard.jpg b/img/mounting-seperate-solarboard.jpg index 998cf188..edbc5ff6 100644 Binary files a/img/mounting-seperate-solarboard.jpg and b/img/mounting-seperate-solarboard.jpg differ diff --git a/img/panel-mounted.jpg b/img/panel-mounted.jpg index 52b13a51..62fbb503 100644 Binary files a/img/panel-mounted.jpg and b/img/panel-mounted.jpg differ diff --git a/img/single-core-wireas-antenna.jpg b/img/single-core-wireas-antenna.jpg index d5957e4f..49cae88e 100644 Binary files a/img/single-core-wireas-antenna.jpg and b/img/single-core-wireas-antenna.jpg differ diff --git a/img/solar-panel-waterproofed.jpg b/img/solar-panel-waterproofed.jpg index 7a2f0a7d..c57be4d0 100644 Binary files a/img/solar-panel-waterproofed.jpg and b/img/solar-panel-waterproofed.jpg differ diff --git a/img/solar-panel-withboard.jpg b/img/solar-panel-withboard.jpg index e2aeaa6e..33b4622c 100644 Binary files a/img/solar-panel-withboard.jpg and b/img/solar-panel-withboard.jpg differ diff --git a/img/solar-shield-design.jpg b/img/solar-shield-design.jpg index ad2b6e9e..068813bd 100644 Binary files a/img/solar-shield-design.jpg and b/img/solar-shield-design.jpg differ diff --git a/quality-control/hardware/QC-build-quality-v01.md b/quality-control/hardware/QC-build-quality-v01.md index e8448f86..c5574f68 100644 --- a/quality-control/hardware/QC-build-quality-v01.md +++ b/quality-control/hardware/QC-build-quality-v01.md @@ -89,7 +89,7 @@ All the solder joints shall be covered with heat shrink so that there is no expo ##### No melted wires -It is pretty common mistake to over heat the wires while joing two wires using solder. Try not to apply too much heat. Tan them individually before joining. The melted wires can short-circuit and potentially damage the circuitry. +It is pretty common mistake to over heat the wires while joing two wires using solder. Try not to apply too much heat. Tin them individually before joining. The melted wires can short-circuit and potentially damage the circuitry. ## References diff --git a/src/featherwing.cpp b/src/featherwing.cpp deleted file mode 100644 index 523423dd..00000000 --- a/src/featherwing.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "sensorcfg.h" -#include "featherwing.h" - -// File name -char name[] = "TSTLOG.TXT"; -int SD_ERROR = 0; -// file system object -SdFat sd; -SdFile file; -// create Serial stream -ArduinoOutStream cout(Serial); - -char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; -int calibration_const_sec = 5; -RTC_PCF8523 rtc; - -void setup_featherWing(void) { - - //RTC init - if (! rtc.begin()) { - Serial.println("Couldn't find RTC"); - Serial.flush(); - abort(); - } - - if (! rtc.initialized() || rtc.lostPower()) { - Serial.println("RTC is NOT initialized, let's set the time!"); - // When time needs to be set on a new device, or after a power loss, the - // following line sets the RTC to the date & time this sketch was compiled - rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); - // This line sets the RTC with an explicit date & time, for example to set - // January 21, 2014 at 3am you would call: - // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); - // - // Note: allow 2 seconds after inserting battery or applying external power - // without battery before calling adjust(). This gives the PCF8523's - // crystal oscillator time to stabilize. If you call adjust() very quickly - // after the RTC is powered, lostPower() may still return true. - } - - // When time needs to be re-set on a previously configured device, the - // following line sets the RTC to the date & time this sketch was compiled - rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); - // This line sets the RTC with an explicit date & time, for example to set - // January 21, 2014 at 3am you would call: - // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); - -} - -String get_timestamp(void){ - DateTime now = rtc.now(); - String custom_timestamp_calibrated = String(now.year(), DEC) + String('-') + String(now.month(), DEC)+ String('-') + String(now.day(), DEC)+ String(' ') + String(now.hour(), DEC)+ String(':') + String(now.minute(), DEC) + String(':') + String(now.second(), DEC); - return custom_timestamp_calibrated; -} - -void writeToSDCard(String StringtobeWritten) { - //add time stamp to every sd card write - String timestamp = get_timestamp(); - StringtobeWritten = timestamp + String(',') +StringtobeWritten ; - char buffchar[StringtobeWritten.length() + 1]; - StringtobeWritten.toCharArray(buffchar, StringtobeWritten.length() + 1); - digitalWrite(8, HIGH); - if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { - // set the SD_ERROR flag high; - SD_ERROR = 1; - Serial.println("SD Initialization Failed."); - } - else - { - ofstream sdout(name, ios::out | ios::app); - if (!sdout) - { - Serial.println("SD Card Open Failed."); - SD_ERROR = 1; - } - else { - sdout << buffchar << endl; - // close the stream - sdout.close(); - SD_ERROR = 0; - } - } - digitalWrite(8, LOW); -} diff --git a/src/featherwing.h b/src/featherwing.h deleted file mode 100644 index e11272bd..00000000 --- a/src/featherwing.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef FEATHERWING_H -#define FEATHERWING_H - -// SD CARD -#include - -void writeToSDCard(String StringtobeWritten); - -//RTC -#include "RTClib.h" - -void setup_featherWing(void); -String get_timestamp(void); - -#endif diff --git a/src/floodsensor/.vscode/arduino.json b/src/floodsensor/.vscode/arduino.json new file mode 100644 index 00000000..512e89a2 --- /dev/null +++ b/src/floodsensor/.vscode/arduino.json @@ -0,0 +1,6 @@ +{ + "configuration": "LORAWAN_REGION=9,LORAWAN_CLASS=0,LORAWAN_DEVEUI=0,LORAWAN_NETMODE=0,LORAWAN_ADR=0,LORAWAN_UPLINKMODE=1,LORAWAN_Net_Reserve=0,LORAWAN_AT_SUPPORT=0,LORAWAN_RGB=1,LORAWAN_DebugLevel=0", + "board": "CubeCell:CubeCell:CubeCell-BoardPlus", + "port": "/dev/tty.usbserial-0001", + "sketch": "floodsensor.ino" +} \ No newline at end of file diff --git a/src/floodsensor/.vscode/c_cpp_properties.json b/src/floodsensor/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..e803b6e8 --- /dev/null +++ b/src/floodsensor/.vscode/c_cpp_properties.json @@ -0,0 +1,525 @@ +{ + "version": 4, + "configurations": [ + { + "name": "Arduino", + "compilerPath": "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/bin/arm-none-eabi-g++", + "compilerArgs": [ + "-mcpu=cortex-m0plus", + "-mthumb", + "-w", + "-Wall" + ], + "intelliSenseMode": "gcc-x64", + "includePath": [ + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/board/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/board/src/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/board/inc/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/device/sx126x/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/lora/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/lora/system/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/lora/system/crypto/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/port/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/port/include/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/projects/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/projects/PSoC4/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/cores/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/Serial/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/Wire/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/SPI/", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/variants/CubeCell-BoardPlus", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/libraries/LoRa/src", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/libraries/LoraWan102/src", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/libraries/EEPROM", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/libraries/RGB/src", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/libraries/DISPLAY/src", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/arm-none-eabi/include/c++/8.3.1", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/arm-none-eabi/include/c++/8.3.1/arm-none-eabi", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/arm-none-eabi/include/c++/8.3.1/backward", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/lib/gcc/arm-none-eabi/8.3.1/include", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/lib/gcc/arm-none-eabi/8.3.1/include-fixed", + "/Users/cm3580/Library/Arduino15/packages/CubeCell/tools/gcc-arm-none-eabi/8-2019-q3/arm-none-eabi/include" + ], + "forcedInclude": [ + "/Users/cm3580/Library/Arduino15/packages/CubeCell/hardware/CubeCell/1.3.0/cores/asr650x/Arduino.h" + ], + "cStandard": "c11", + "cppStandard": "c++11", + "defines": [ + "REGION_US915", + "CubeCell_BoardPlus", + "ARDUINO=10819", + "ACTIVE_REGION=LORAMAC_REGION_US915", + "LORAWAN_DEVEUI_AUTO=0", + "LORAWAN_CLASS=CLASS_A", + "LORAWAN_NETMODE=true", + "LORAWAN_ADR=true", + "LORAWAN_UPLINKMODE=false", + "LORAWAN_NET_RESERVE=false", + "AT_SUPPORT=1", + "LoraWan_RGB=1", + "LoRaWAN_DEBUG_LEVEL=0", + "SOFT_SE", + "CY_CORE_ID=0", + "CONFIG_LORA_USE_TCXO", + "CONFIG_MANUFACTURER=\"ASR\"", + "CONFIG_DEVICE_MODEL=\"6501\"", + "CONFIG_VERSION=\"v4.0\"", + "ARDUINO_ARCH_ASR650X", + "__asr650x__", + "__ASR6502__", + "F_CPU=48000000L", + "__DBL_MIN_EXP__=(-1021)", + "__HQ_FBIT__=15", + "__FLT32X_MAX_EXP__=1024", + "__cpp_attributes=200809", + "__UINT_LEAST16_MAX__=0xffff", + "__ARM_SIZEOF_WCHAR_T=4", + "__ATOMIC_ACQUIRE=2", + "__SFRACT_IBIT__=0", + "__FLT_MIN__=1.1754943508222875e-38F", + "__GCC_IEC_559_COMPLEX=0", + "__cpp_aggregate_nsdmi=201304", + "__UFRACT_MAX__=0XFFFFP-16UR", + "__UINT_LEAST8_TYPE__=unsigned char", + "__DQ_FBIT__=63", + "__INTMAX_C(c)=c ## LL", + "__ULFRACT_FBIT__=32", + "__SACCUM_EPSILON__=0x1P-7HK", + "__CHAR_BIT__=8", + "__USQ_IBIT__=0", + "__UINT8_MAX__=0xff", + "__ACCUM_FBIT__=15", + "__WINT_MAX__=0xffffffffU", + "__FLT32_MIN_EXP__=(-125)", + "__cpp_static_assert=200410", + "__USFRACT_FBIT__=8", + "__ORDER_LITTLE_ENDIAN__=1234", + "__SIZE_MAX__=0xffffffffU", + "__ARM_ARCH_ISA_ARM=1", + "__WCHAR_MAX__=0xffffffffU", + "__LACCUM_IBIT__=32", + "__DBL_DENORM_MIN__=double(4.9406564584124654e-324L)", + "__GCC_ATOMIC_CHAR_LOCK_FREE=1", + "__GCC_IEC_559=0", + "__FLT32X_DECIMAL_DIG__=17", + "__FLT_EVAL_METHOD__=0", + "__cpp_binary_literals=201304", + "__LLACCUM_MAX__=0X7FFFFFFFFFFFFFFFP-31LLK", + "__FLT64_DECIMAL_DIG__=17", + "__GCC_ATOMIC_CHAR32_T_LOCK_FREE=1", + "__FRACT_FBIT__=15", + "__cpp_variadic_templates=200704", + "__UINT_FAST64_MAX__=0xffffffffffffffffULL", + "__SIG_ATOMIC_TYPE__=int", + "__UACCUM_FBIT__=16", + "__DBL_MIN_10_EXP__=(-307)", + "__FINITE_MATH_ONLY__=0", + "__ARMEL__=1", + "__cpp_variable_templates=201304", + "__LFRACT_IBIT__=0", + "__GNUC_PATCHLEVEL__=1", + "__FLT32_HAS_DENORM__=1", + "__LFRACT_MAX__=0X7FFFFFFFP-31LR", + "__UINT_FAST8_MAX__=0xffffffffU", + "__has_include(STR)=__has_include__(STR)", + "__DEC64_MAX_EXP__=385", + "__INT8_C(c)=c", + "__INT_LEAST8_WIDTH__=8", + "__UINT_LEAST64_MAX__=0xffffffffffffffffULL", + "__SA_FBIT__=15", + "__SHRT_MAX__=0x7fff", + "__LDBL_MAX__=1.7976931348623157e+308L", + "__FRACT_MAX__=0X7FFFP-15R", + "__UFRACT_FBIT__=16", + "__UFRACT_MIN__=0.0UR", + "__UINT_LEAST8_MAX__=0xff", + "__GCC_ATOMIC_BOOL_LOCK_FREE=1", + "__UINTMAX_TYPE__=long long unsigned int", + "__LLFRACT_EPSILON__=0x1P-63LLR", + "__DEC32_EPSILON__=1E-6DF", + "__FLT_EVAL_METHOD_TS_18661_3__=0", + "__CHAR_UNSIGNED__=1", + "__UINT32_MAX__=0xffffffffUL", + "__GXX_EXPERIMENTAL_CXX0X__=1", + "__ULFRACT_MAX__=0XFFFFFFFFP-32ULR", + "__TA_IBIT__=64", + "__LDBL_MAX_EXP__=1024", + "__WINT_MIN__=0U", + "__INT_LEAST16_WIDTH__=16", + "__ULLFRACT_MIN__=0.0ULLR", + "__SCHAR_MAX__=0x7f", + "__WCHAR_MIN__=0U", + "__INT64_C(c)=c ## LL", + "__DBL_DIG__=15", + "__GCC_ATOMIC_POINTER_LOCK_FREE=1", + "__LLACCUM_MIN__=(-0X1P31LLK-0X1P31LLK)", + "__SIZEOF_INT__=4", + "__SIZEOF_POINTER__=4", + "__GCC_ATOMIC_CHAR16_T_LOCK_FREE=1", + "__USACCUM_IBIT__=8", + "__USER_LABEL_PREFIX__", + "__STDC_HOSTED__=1", + "__LDBL_HAS_INFINITY__=1", + "__LFRACT_MIN__=(-0.5LR-0.5LR)", + "__HA_IBIT__=8", + "__FLT32_DIG__=6", + "__TQ_IBIT__=0", + "__FLT_EPSILON__=1.1920928955078125e-7F", + "__APCS_32__=1", + "__GXX_WEAK__=1", + "__SHRT_WIDTH__=16", + "__USFRACT_IBIT__=0", + "__LDBL_MIN__=2.2250738585072014e-308L", + "__FRACT_MIN__=(-0.5R-0.5R)", + "__DEC32_MAX__=9.999999E96DF", + "__cpp_threadsafe_static_init=200806", + "__DA_IBIT__=32", + "__ARM_SIZEOF_MINIMAL_ENUM=1", + "__FLT32X_HAS_INFINITY__=1", + "__INT32_MAX__=0x7fffffffL", + "__UQQ_FBIT__=8", + "__INT_WIDTH__=32", + "__SIZEOF_LONG__=4", + "__UACCUM_MAX__=0XFFFFFFFFP-16UK", + "__UINT16_C(c)=c", + "__PTRDIFF_WIDTH__=32", + "__DECIMAL_DIG__=17", + "__LFRACT_EPSILON__=0x1P-31LR", + "__FLT64_EPSILON__=2.2204460492503131e-16F64", + "__ULFRACT_MIN__=0.0ULR", + "__INTMAX_WIDTH__=64", + "__FLT64_MIN_EXP__=(-1021)", + "__has_include_next(STR)=__has_include_next__(STR)", + "__LDBL_HAS_QUIET_NAN__=1", + "__ULACCUM_IBIT__=32", + "__FLT64_MANT_DIG__=53", + "__UACCUM_EPSILON__=0x1P-16UK", + "__GNUC__=8", + "__ULLACCUM_MAX__=0XFFFFFFFFFFFFFFFFP-32ULLK", + "__GXX_RTTI=1", + "__cpp_delegating_constructors=200604", + "__HQ_IBIT__=0", + "__FLT_HAS_DENORM__=1", + "__SIZEOF_LONG_DOUBLE__=8", + "__BIGGEST_ALIGNMENT__=8", + "__STDC_UTF_16__=1", + "__FLT64_MAX_10_EXP__=308", + "__GNUC_STDC_INLINE__=1", + "__DQ_IBIT__=0", + "__FLT32_HAS_INFINITY__=1", + "__DBL_MAX__=double(1.7976931348623157e+308L)", + "__ULFRACT_IBIT__=0", + "__cpp_raw_strings=200710", + "__INT_FAST32_MAX__=0x7fffffff", + "__DBL_HAS_INFINITY__=1", + "__ACCUM_IBIT__=16", + "__DEC32_MIN_EXP__=(-94)", + "__THUMB_INTERWORK__=1", + "__INTPTR_WIDTH__=32", + "__LACCUM_MAX__=0X7FFFFFFFFFFFFFFFP-31LK", + "__FLT32X_HAS_DENORM__=1", + "__INT_FAST16_TYPE__=int", + "__LDBL_HAS_DENORM__=1", + "__cplusplus=201402L", + "__cpp_ref_qualifiers=200710", + "__DEC128_MAX__=9.999999999999999999999999999999999E6144DL", + "__INT_LEAST32_MAX__=0x7fffffffL", + "__ARM_PCS=1", + "__DEC32_MIN__=1E-95DF", + "__ACCUM_MAX__=0X7FFFFFFFP-15K", + "__DEPRECATED=1", + "__cpp_rvalue_references=200610", + "__DBL_MAX_EXP__=1024", + "__USACCUM_EPSILON__=0x1P-8UHK", + "__WCHAR_WIDTH__=32", + "__FLT32_MAX__=3.4028234663852886e+38F32", + "__DEC128_EPSILON__=1E-33DL", + "__SFRACT_MAX__=0X7FP-7HR", + "__FRACT_IBIT__=0", + "__PTRDIFF_MAX__=0x7fffffff", + "__UACCUM_MIN__=0.0UK", + "__UACCUM_IBIT__=16", + "__FLT32_HAS_QUIET_NAN__=1", + "__GNUG__=8", + "__LONG_LONG_MAX__=0x7fffffffffffffffLL", + "__SIZEOF_SIZE_T__=4", + "__ULACCUM_MAX__=0XFFFFFFFFFFFFFFFFP-32ULK", + "__cpp_rvalue_reference=200610", + "__cpp_nsdmi=200809", + "__SIZEOF_WINT_T__=4", + "__LONG_LONG_WIDTH__=64", + "__cpp_initializer_lists=200806", + "__FLT32_MAX_EXP__=128", + "__SA_IBIT__=16", + "__ULLACCUM_MIN__=0.0ULLK", + "__cpp_hex_float=201603", + "__GXX_ABI_VERSION=1013", + "__UTA_FBIT__=64", + "__SOFTFP__=1", + "__FLT_MIN_EXP__=(-125)", + "__USFRACT_MAX__=0XFFP-8UHR", + "__UFRACT_IBIT__=0", + "__cpp_lambdas=200907", + "__INT_FAST64_TYPE__=long long int", + "__FLT64_DENORM_MIN__=4.9406564584124654e-324F64", + "__DBL_MIN__=double(2.2250738585072014e-308L)", + "__FLT32X_EPSILON__=2.2204460492503131e-16F32x", + "__LACCUM_MIN__=(-0X1P31LK-0X1P31LK)", + "__ULLACCUM_FBIT__=32", + "__GXX_TYPEINFO_EQUALITY_INLINE=0", + "__FLT64_MIN_10_EXP__=(-307)", + "__ULLFRACT_EPSILON__=0x1P-64ULLR", + "__USES_INITFINI__=1", + "__DEC128_MIN__=1E-6143DL", + "__REGISTER_PREFIX__", + "__UINT16_MAX__=0xffff", + "__DBL_HAS_DENORM__=1", + "__ACCUM_MIN__=(-0X1P15K-0X1P15K)", + "__SQ_IBIT__=0", + "__FLT32_MIN__=1.1754943508222875e-38F32", + "__UINT8_TYPE__=unsigned char", + "__UHA_FBIT__=8", + "__NO_INLINE__=1", + "__SFRACT_MIN__=(-0.5HR-0.5HR)", + "__UTQ_FBIT__=128", + "__FLT_MANT_DIG__=24", + "__LDBL_DECIMAL_DIG__=17", + "__VERSION__=\"8.3.1 20190703 (release) [gcc-8-branch revision 273027]\"", + "__UINT64_C(c)=c ## ULL", + "__ULLFRACT_FBIT__=64", + "__cpp_unicode_characters=200704", + "__FRACT_EPSILON__=0x1P-15R", + "__ULACCUM_MIN__=0.0ULK", + "__UDA_FBIT__=32", + "__cpp_decltype_auto=201304", + "__LLACCUM_EPSILON__=0x1P-31LLK", + "__GCC_ATOMIC_INT_LOCK_FREE=1", + "__FLT32_MANT_DIG__=24", + "__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__", + "__USFRACT_MIN__=0.0UHR", + "__ULLACCUM_IBIT__=32", + "__UQQ_IBIT__=0", + "__SCHAR_WIDTH__=8", + "__INT32_C(c)=c ## L", + "__DEC64_EPSILON__=1E-15DD", + "__ORDER_PDP_ENDIAN__=3412", + "__DEC128_MIN_EXP__=(-6142)", + "__UHQ_FBIT__=16", + "__LLACCUM_FBIT__=31", + "__FLT32_MAX_10_EXP__=38", + "__INT_FAST32_TYPE__=int", + "__UINT_LEAST16_TYPE__=short unsigned int", + "__INT16_MAX__=0x7fff", + "__cpp_rtti=199711", + "__SIZE_TYPE__=unsigned int", + "__UINT64_MAX__=0xffffffffffffffffULL", + "__UDQ_FBIT__=64", + "__INT8_TYPE__=signed char", + "__cpp_digit_separators=201309", + "__ELF__=1", + "__ULFRACT_EPSILON__=0x1P-32ULR", + "__LLFRACT_FBIT__=63", + "__FLT_RADIX__=2", + "__INT_LEAST16_TYPE__=short int", + "__LDBL_EPSILON__=2.2204460492503131e-16L", + "__UINTMAX_C(c)=c ## ULL", + "__SACCUM_MAX__=0X7FFFP-7HK", + "__SIG_ATOMIC_MAX__=0x7fffffff", + "__GCC_ATOMIC_WCHAR_T_LOCK_FREE=1", + "__VFP_FP__=1", + "__SIZEOF_PTRDIFF_T__=4", + "__FLT32X_MANT_DIG__=53", + "__LACCUM_EPSILON__=0x1P-31LK", + "__FLT32X_MIN_EXP__=(-1021)", + "__DEC32_SUBNORMAL_MIN__=0.000001E-95DF", + "__INT_FAST16_MAX__=0x7fffffff", + "__FLT64_DIG__=15", + "__UINT_FAST32_MAX__=0xffffffffU", + "__UINT_LEAST64_TYPE__=long long unsigned int", + "__USACCUM_MAX__=0XFFFFP-8UHK", + "__SFRACT_EPSILON__=0x1P-7HR", + "__FLT_HAS_QUIET_NAN__=1", + "__FLT_MAX_10_EXP__=38", + "__LONG_MAX__=0x7fffffffL", + "__DEC128_SUBNORMAL_MIN__=0.000000000000000000000000000000001E-6143DL", + "__FLT_HAS_INFINITY__=1", + "__cpp_unicode_literals=200710", + "__USA_FBIT__=16", + "__UINT_FAST16_TYPE__=unsigned int", + "__DEC64_MAX__=9.999999999999999E384DD", + "__ARM_32BIT_STATE=1", + "__INT_FAST32_WIDTH__=32", + "__CHAR16_TYPE__=short unsigned int", + "__PRAGMA_REDEFINE_EXTNAME=1", + "__SIZE_WIDTH__=32", + "__INT_LEAST16_MAX__=0x7fff", + "__DEC64_MANT_DIG__=16", + "__INT64_MAX__=0x7fffffffffffffffLL", + "__UINT_LEAST32_MAX__=0xffffffffUL", + "__SACCUM_FBIT__=7", + "__FLT32_DENORM_MIN__=1.4012984643248171e-45F32", + "__GCC_ATOMIC_LONG_LOCK_FREE=1", + "__SIG_ATOMIC_WIDTH__=32", + "__INT_LEAST64_TYPE__=long long int", + "__INT16_TYPE__=short int", + "__INT_LEAST8_TYPE__=signed char", + "__SQ_FBIT__=31", + "__DEC32_MAX_EXP__=97", + "__ARM_ARCH_ISA_THUMB=1", + "__INT_FAST8_MAX__=0x7fffffff", + "__ARM_ARCH=4", + "__INTPTR_MAX__=0x7fffffff", + "__cpp_sized_deallocation=201309", + "__QQ_FBIT__=7", + "__cpp_range_based_for=200907", + "__UTA_IBIT__=64", + "__FLT64_HAS_QUIET_NAN__=1", + "__FLT32_MIN_10_EXP__=(-37)", + "__EXCEPTIONS=1", + "__LDBL_MANT_DIG__=53", + "__SFRACT_FBIT__=7", + "__SACCUM_MIN__=(-0X1P7HK-0X1P7HK)", + "__DBL_HAS_QUIET_NAN__=1", + "__FLT64_HAS_INFINITY__=1", + "__SIG_ATOMIC_MIN__=(-__SIG_ATOMIC_MAX__ - 1)", + "__cpp_return_type_deduction=201304", + "__INTPTR_TYPE__=int", + "__UINT16_TYPE__=short unsigned int", + "__WCHAR_TYPE__=unsigned int", + "__SIZEOF_FLOAT__=4", + "__USQ_FBIT__=32", + "__UINTPTR_MAX__=0xffffffffU", + "__INT_FAST64_WIDTH__=64", + "__DEC64_MIN_EXP__=(-382)", + "__cpp_decltype=200707", + "__FLT32_DECIMAL_DIG__=9", + "__INT_FAST64_MAX__=0x7fffffffffffffffLL", + "__GCC_ATOMIC_TEST_AND_SET_TRUEVAL=1", + "__FLT_DIG__=6", + "__UINT_FAST64_TYPE__=long long unsigned int", + "__INT_MAX__=0x7fffffff", + "__LACCUM_FBIT__=31", + "__USACCUM_MIN__=0.0UHK", + "__UHA_IBIT__=8", + "__INT64_TYPE__=long long int", + "__FLT_MAX_EXP__=128", + "__UTQ_IBIT__=0", + "__DBL_MANT_DIG__=53", + "__cpp_inheriting_constructors=201511", + "__INT_LEAST64_MAX__=0x7fffffffffffffffLL", + "__DEC64_MIN__=1E-383DD", + "__WINT_TYPE__=unsigned int", + "__UINT_LEAST32_TYPE__=long unsigned int", + "__SIZEOF_SHORT__=2", + "__ULLFRACT_IBIT__=0", + "__LDBL_MIN_EXP__=(-1021)", + "__arm__=1", + "__FLT64_MAX__=1.7976931348623157e+308F64", + "__UDA_IBIT__=32", + "__WINT_WIDTH__=32", + "__INT_LEAST8_MAX__=0x7f", + "__FLT32X_MAX_10_EXP__=308", + "__LFRACT_FBIT__=31", + "__WCHAR_UNSIGNED__=1", + "__LDBL_MAX_10_EXP__=308", + "__ATOMIC_RELAXED=0", + "__DBL_EPSILON__=double(2.2204460492503131e-16L)", + "__UINT8_C(c)=c", + "__FLT64_MAX_EXP__=1024", + "__INT_LEAST32_TYPE__=long int", + "__SIZEOF_WCHAR_T__=4", + "__LLFRACT_MAX__=0X7FFFFFFFFFFFFFFFP-63LLR", + "__TQ_FBIT__=127", + "__INT_FAST8_TYPE__=int", + "__ULLACCUM_EPSILON__=0x1P-32ULLK", + "__UHQ_IBIT__=0", + "__ARM_FEATURE_COPROC=1", + "__LLACCUM_IBIT__=32", + "__FLT64_HAS_DENORM__=1", + "__FLT32_EPSILON__=1.1920928955078125e-7F32", + "__DBL_DECIMAL_DIG__=17", + "__STDC_UTF_32__=1", + "__INT_FAST8_WIDTH__=32", + "__DEC_EVAL_METHOD__=2", + "__FLT32X_MAX__=1.7976931348623157e+308F32x", + "__TA_FBIT__=63", + "__UDQ_IBIT__=0", + "__ORDER_BIG_ENDIAN__=4321", + "__cpp_runtime_arrays=198712", + "__UINT64_TYPE__=long long unsigned int", + "__ACCUM_EPSILON__=0x1P-15K", + "__UINT32_C(c)=c ## UL", + "__INTMAX_MAX__=0x7fffffffffffffffLL", + "__cpp_alias_templates=200704", + "__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__", + "__FLT_DENORM_MIN__=1.4012984643248171e-45F", + "__LLFRACT_IBIT__=0", + "__INT8_MAX__=0x7f", + "__LONG_WIDTH__=32", + "__UINT_FAST32_TYPE__=unsigned int", + "__CHAR32_TYPE__=long unsigned int", + "__FLT_MAX__=3.4028234663852886e+38F", + "__cpp_constexpr=201304", + "__USACCUM_FBIT__=8", + "__INT32_TYPE__=long int", + "__SIZEOF_DOUBLE__=8", + "__cpp_exceptions=199711", + "__FLT_MIN_10_EXP__=(-37)", + "__UFRACT_EPSILON__=0x1P-16UR", + "__FLT64_MIN__=2.2250738585072014e-308F64", + "__INT_LEAST32_WIDTH__=32", + "__INTMAX_TYPE__=long long int", + "__DEC128_MAX_EXP__=6145", + "__FLT32X_HAS_QUIET_NAN__=1", + "__ATOMIC_CONSUME=1", + "__GNUC_MINOR__=3", + "__INT_FAST16_WIDTH__=32", + "__UINTMAX_MAX__=0xffffffffffffffffULL", + "__DEC32_MANT_DIG__=7", + "__FLT32X_DENORM_MIN__=4.9406564584124654e-324F32x", + "__HA_FBIT__=7", + "__DBL_MAX_10_EXP__=308", + "__LDBL_DENORM_MIN__=4.9406564584124654e-324L", + "__INT16_C(c)=c", + "__cpp_generic_lambdas=201304", + "__STDC__=1", + "__ARM_ARCH_4T__=1", + "__FLT32X_DIG__=15", + "__PTRDIFF_TYPE__=int", + "__LLFRACT_MIN__=(-0.5LLR-0.5LLR)", + "__ATOMIC_SEQ_CST=5", + "__DA_FBIT__=31", + "__UINT32_TYPE__=long unsigned int", + "__FLT32X_MIN_10_EXP__=(-307)", + "__UINTPTR_TYPE__=unsigned int", + "__USA_IBIT__=16", + "__DEC64_SUBNORMAL_MIN__=0.000000000000001E-383DD", + "__ARM_EABI__=1", + "__DEC128_MANT_DIG__=34", + "__LDBL_MIN_10_EXP__=(-307)", + "__SIZEOF_LONG_LONG__=8", + "__ULACCUM_EPSILON__=0x1P-32ULK", + "__cpp_user_defined_literals=200809", + "__SACCUM_IBIT__=8", + "__GCC_ATOMIC_LLONG_LOCK_FREE=1", + "__FLT32X_MIN__=2.2250738585072014e-308F32x", + "__LDBL_DIG__=15", + "__FLT_DECIMAL_DIG__=9", + "__UINT_FAST16_MAX__=0xffffffffU", + "__GCC_ATOMIC_SHORT_LOCK_FREE=1", + "__INT_LEAST64_WIDTH__=64", + "__ULLFRACT_MAX__=0XFFFFFFFFFFFFFFFFP-64ULLR", + "__UINT_FAST8_TYPE__=unsigned int", + "__USFRACT_EPSILON__=0x1P-8UHR", + "__ULACCUM_FBIT__=32", + "__QQ_IBIT__=0", + "__cpp_init_captures=201304", + "__ATOMIC_ACQ_REL=4", + "__ATOMIC_RELEASE=3", + "USBCON" + ] + } + ] +} \ No newline at end of file diff --git a/src/Floodsense_sensor.h b/src/floodsensor/Floodsense_sensor.h similarity index 58% rename from src/Floodsense_sensor.h rename to src/floodsensor/Floodsense_sensor.h index e4eb9a4b..3ef14099 100644 --- a/src/Floodsense_sensor.h +++ b/src/floodsensor/Floodsense_sensor.h @@ -1,10 +1,13 @@ #ifndef _FLOODSENSE_SENSOR_H #define _FLOODSENSE_SENSOR_H + +/* This file contains all header files, a new sensor/module added shall be included here*/ + #include #include "functions.h" #include "lorawan.h" -#include "featherwing.h" #include "maxbotix.h" +#include "rg15.h" #endif diff --git a/src/floodsensor/floodsensor.ino b/src/floodsensor/floodsensor.ino new file mode 100644 index 00000000..d1b42eda --- /dev/null +++ b/src/floodsensor/floodsensor.ino @@ -0,0 +1,39 @@ + /* -------------------------------------------------------------------------------- + * This Example uses Maxbotix Ultrasonic Sensor and Heltec CuebeCell AB02 dev board + * to read the depth and send the distance and battery level over the + * LoRaWAN network. + * + * Connections: + * + * VEXT -> Maxbotix V+ + * GND -> Maxbotix GND + * RX2 -> Maxbotix Serial Pin (Pin 5: Serial output) + * GPIO 5 -> Maxbotix triggerPin (Pin 4: Ranging start/stop) + * + * -------------------------------------------------------------------------------- */ + +#include "Floodsense_sensor.h" + +#define USE_RG15 +#define USE_TIPPING_BUCKET + + +void setup() { + delay(3000); + Serial.begin(115200); + Serial.println("Starting"); + + #ifdef USE_MAXBOTIX + setup_maxbotix(2, 150, 7); // sensor mode 2(Median), 150ms sampling rate (time between readings), 7 readings per measurement + #endif + + #ifdef USE_RG15 + setup_RG15("Polling"); + #endif + + setup_lorawan(60); // uplink frequency 60 seconds - controls duty cycle +} + +void loop() { + lorawan_runloop_once(); +} diff --git a/src/floodsensor/functions.cpp b/src/floodsensor/functions.cpp new file mode 100644 index 00000000..c300db10 --- /dev/null +++ b/src/floodsensor/functions.cpp @@ -0,0 +1,61 @@ +#include "functions.h" + +void printHex2(unsigned v) { + v &= 0xff; + if (v < 16) + Serial.print('0'); + Serial.print(v, HEX); +} + +void swap(uint16_t *p, uint16_t *q) { + int t; + + t = *p; + *p = *q; + *q = t; +} + +void sort(uint16_t a[], size_t n) { + int i, j, temp; + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + if (a[j] < a[j + 1]) + swap(&a[j], &a[j + 1]); + } + } +} + +uint16_t mean(uint16_t readings_arr[], size_t n, unsigned int sensor_numberOfReadings){ + uint16_t readings_sum = 0; + for (int i=0; i max ){ + max = counter; + mode_ = readings_arr[i]; + } + } else + counter = 1; // reset counter. + } + return mode_; +} diff --git a/src/functions.h b/src/floodsensor/functions.h similarity index 100% rename from src/functions.h rename to src/floodsensor/functions.h diff --git a/src/floodsensor/lorawan.cpp b/src/floodsensor/lorawan.cpp new file mode 100644 index 00000000..5ed8d7ca --- /dev/null +++ b/src/floodsensor/lorawan.cpp @@ -0,0 +1,779 @@ +#include "lorawan.h" +#include "maxbotix.h" +#include "rg15.h" +#include "sensorcfg.h" +#include "ttncredentials.h" +#include +#ifndef INNERWDT_H +#ifdef __asr650x__ +#include "innerWdt.h" +#endif +#endif + +/*Sensor states*/ +#define SENSING_STATE 0x73 +#define RESET_STATE 0x72 +#define CFG_STATE 0x78 +char is_deployed; +char is_started; + +/* EEPROM params */ +const int selectionAddress = 8; // Single char (y/n) in ASCII +const int init_Address = 9; +const int newAppAddress = 12; // 12 to 19 +const int newAppKeyAddress = 21; // 21 to 37 +const int newDevEUIAddress = 40; +const int defaultAppEUIAddress = 50; // 50 to 57 +const int defaultAppKeyAddress = 58; // 58 to 73 +const int defaultDevEUIAddress = 75; // 75 to 82 +const int isDeployed = 90; +const int isStarted = 91; +/* + Semantic Versioning 2.0.0 Format: + MAJOR_VERSION.MINOR_VERSION.PATCH_VERSION +*/ +const int MAJOR_VERSION = 4; // incompatible changes +const int MINOR_VERSION = + 2; // add functionality in a backwards compatible manner +const int PATCH_VERSION = 0; // backwards compatible bug fixes + +/*flags*/ +bool autoFeed = false; // Watchdog timer +bool overTheAirActivation = 1; +bool loraWanAdr = true; +bool keepNet = false; +bool isTxConfirmed = 0; +unsigned int ERROR_FLAGS; + +/*SYS params*/ +uint8_t SENSOR_STATE; + +/* OTAA para*/ +uint8_t devEui[] = TTN_DEVEUI; +uint8_t appEui[] = TTN_APPEUI; +uint8_t appKey[] = TTN_APPKEY; +/* ABP para*/ +uint8_t nwkSKey[] = {}; +uint8_t appSKey[] = {}; +uint32_t devAddr = (uint32_t)0x0000; + +/*LoraWan channelsmask, default channels 0-7*/ +uint16_t userChannelsMask[6] = {0xFF00, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000}; // 0xFF00 from 00FF + +/*LoraWan region, override IDE defaults*/ +LoRaMacRegion_t loraWanRegion = LORAMAC_REGION_US915; + +/*LoraWan Class A*/ +DeviceClass_t loraWanClass = CLASS_A; + +/*LoRaWAN application data transmission duty cycle. value in [ms]. DEFAULT is + * 10 seconds*/ +uint32_t appTxDutyCycle = 10 * 1000; + +/*User defined variable - TX_INTERVAL, changes between states as needed. DEFAULT + * is 10 seconds*/ +uint16_t TX_INTERVAL = 10; +uint8_t appPort = 2; +uint8_t confirmedNbTrials = 4; +uint8_t lowpower = 1; + +/*Sensor specific variables*/ +uint16_t counter_rg15 = 0; +volatile static uint16_t tip_count; + +/****************************************************************************************** + + Functions + +*******************************************************************************************/ + +void ModifyDutyCycle(McpsIndication_t *mcpsIndication) { + unsigned long dutycycle = 0; + for (int i = 1; i < mcpsIndication->BufferSize; i++) { + dutycycle = (mcpsIndication->Buffer[i]) | (dutycycle << 8 * (i - 1)); + } + if (dutycycle != 0 && dutycycle < 1000) { + Serial.print("Current duty cycle is: "); + Serial.println(TX_INTERVAL); + // Changing Duty Cycle + TX_INTERVAL = dutycycle; + Serial.print("Updated dutycycle is: "); + Serial.println(TX_INTERVAL); + } else { + Serial.println("Dutycycle is the same."); + } +} + +void ModifySensorMode(McpsIndication_t *mcpsIndication) { + unsigned int sensorMode_ = 0; + sensorMode_ = (mcpsIndication->Buffer[3]) | (sensorMode_); + if (sensorMode_ > 0 && sensorMode_ <= 3) { + Serial.print("Current sensorMode is: "); + Serial.println(sensorMode); + // Changing Sensor Mode + sensorMode = sensorMode_; + Serial.print("Updated sensorMode is: "); + Serial.println(sensorMode); + } else { + Serial.println("Sensor Mode is the same."); + } +} + +void ModifySamplingRate(McpsIndication_t *mcpsIndication) { + unsigned int sampling_rate = 0; + sampling_rate = (mcpsIndication->Buffer[4]) | (sampling_rate); + sampling_rate = (mcpsIndication->Buffer[5]) | (sampling_rate << 8); + if (sampling_rate != 0) { + Serial.print("Current sensor sampling rate is: "); + Serial.println(sensor_sampling_rate); + // Changing Sensor Mode + sensor_sampling_rate = sampling_rate; + Serial.print("Updated sensor sampling rate is: "); + Serial.println(sensor_sampling_rate); + } else { + Serial.println("Sensor sampling rate is the same."); + } +} + +void ModifyNumberOfSamples(McpsIndication_t *mcpsIndication) { + unsigned int numb_readings = 0; + numb_readings = (mcpsIndication->Buffer[6]) | (numb_readings); + if (numb_readings != 0 && numb_readings < 20) { + Serial.print("Current number of readings per measurement: "); + Serial.println(sensor_numberOfReadings); + // Changing Sensor Mode + sensor_numberOfReadings = numb_readings; + Serial.print("Updated number of readings per measurement: "); + Serial.println(sensor_numberOfReadings); + } else { + Serial.println("Sensor number of readings per measurement is the same."); + } +} + +void ModifySensorSettings(McpsIndication_t *mcpsIndication) { + + switch (mcpsIndication->BufferSize) { + case 2: + ModifyDutyCycle(mcpsIndication); + break; + case 3: + ModifyDutyCycle(mcpsIndication); + break; + case 4: + ModifyDutyCycle(mcpsIndication); + ModifySensorMode(mcpsIndication); + break; + case 6: + ModifyDutyCycle(mcpsIndication); + ModifySensorMode(mcpsIndication); + ModifySamplingRate(mcpsIndication); + break; + case 7: + ModifyDutyCycle(mcpsIndication); + ModifySensorMode(mcpsIndication); + ModifySamplingRate(mcpsIndication); + ModifyNumberOfSamples(mcpsIndication); + break; + default: + // should never reach here + Serial.println("Invalid Sensor settings received."); + break; + } +} + +void ModifyKeys(McpsIndication_t *mcpsIndication) { + EEPROM.begin(512); + EEPROM.write(isDeployed, byte('y')); + for (int i = 0; i < 8; ++i) { + EEPROM.write(newAppAddress + i, + byte(mcpsIndication->Buffer[i + 1])); // big-endian + } + for (int i = 0; i < 8; ++i) { + EEPROM.write(newDevEUIAddress + i, + byte(mcpsIndication->Buffer[i + 9])); // big-endian + } + for (int i = 0; i < 16; ++i) { + EEPROM.write(newAppKeyAddress + i, + byte(mcpsIndication->Buffer[i + 17])); // big-endian + } + EEPROM.write(selectionAddress, byte('n')); // Save the choice to EEPROM + // restart + EEPROM.end(); + delay(500); +} + +void LoadNewKeys(void) { + bool foundNewAppEUI; + if (int(EEPROM.read(newAppAddress)) != 0) { + // check if first byte is a zero + foundNewAppEUI = true; + } else { + // all zeroes is default key + foundNewAppEUI = false; + } + if (foundNewAppEUI) { + // load new keys + Serial.print("New AppEUI found."); + for (int i = 0; i < 8; ++i) { + appEui[i] = (uint8_t)EEPROM.read(newAppAddress + i); // big-endian + Serial.print(appEui[i], HEX); + Serial.print(" "); + } + Serial.println(""); + Serial.println("New AppEUI loaded."); + + Serial.print("New AppKey found."); + for (int i = 0; i < 16; ++i) { + appKey[i] = (uint8_t)EEPROM.read(newAppKeyAddress + i); // big-endian + Serial.print(appKey[i], HEX); + Serial.print(" "); + } + Serial.println(""); + Serial.println("New AppKey loaded."); + + Serial.println("New DevEUI found."); + for (int i = 0; i < 8; ++i) { + devEui[i] = (uint8_t)EEPROM.read(newDevEUIAddress + i); // big-endian + Serial.print(devEui[i], HEX); + Serial.print(" "); + } + Serial.println(""); + Serial.println("New DevEUI loaded."); + } else { + Serial.println("Key is zeroes and not valid. Using the original AppEUI"); + // key is zeroes and not valid + EEPROM.write(selectionAddress, byte('y')); + } +} + +uint8_t get_current_sensor_state(void) { return SENSOR_STATE; } + +void InitStoreKeys(void) { + Serial.println("First time setup, Storing the original AppEUI..."); + EEPROM.write(selectionAddress, byte('y')); + EEPROM.write(init_Address, byte('y')); + // Save the default APPEUI in the Flash Memory + for (int i = 0; i < 8; ++i) { + EEPROM.write(defaultAppEUIAddress + i, byte(appEui[i])); // big-endian + } + for (int i = 0; i < 8; ++i) { + EEPROM.write(defaultDevEUIAddress + i, byte(devEui[i])); // big-endian + } + for (int i = 0; i < 16; ++i) { + EEPROM.write(defaultAppKeyAddress + i, byte(appKey[i])); // big-endian + } + Serial.println("Default Keys saved in the EEPROM."); +} + +void process_operation(McpsIndication_t *mcpsIndication) { + if ((char(mcpsIndication->Buffer[1]) == 's') && + (char(mcpsIndication->Buffer[2]) == 't') && + (char(mcpsIndication->Buffer[3]) == 'a') && + (char(mcpsIndication->Buffer[4]) == 'r') && + (char(mcpsIndication->Buffer[5]) == 't')) { + Serial.println("Start sensing, uplinks are Ultrasonic measurements...."); + if (is_deployed == 'y') { + // save that the sensor is deployed and started + EEPROM.begin(512); + EEPROM.write(isStarted, byte('y')); + Serial.println("Saved the sensor state. From now uplinks will be " + "readings even after reset....."); + EEPROM.end(); + } + SENSOR_STATE = SENSING_STATE; + appTxDutyCycle = TX_INTERVAL * 1000; + } else if ((char(mcpsIndication->Buffer[1]) == 's') && + (char(mcpsIndication->Buffer[2]) == 't') && + (char(mcpsIndication->Buffer[3]) == 'o') && + (char(mcpsIndication->Buffer[4]) == 'p')) { + Serial.println("Stop sensing, uplinks are sensor CFG packets."); + SENSOR_STATE = CFG_STATE; + appTxDutyCycle = 10 * 1000; + } else if ((char(mcpsIndication->Buffer[1]) == 'r') && + (char(mcpsIndication->Buffer[2]) == 'e') && + (char(mcpsIndication->Buffer[3]) == 's') && + (char(mcpsIndication->Buffer[4]) == 'e') && + (char(mcpsIndication->Buffer[5]) == 't')) { + Serial.println("Reset Sensor."); + SENSOR_STATE = RESET_STATE; + // resets after updating it's CFG + } else { + Serial.println("Invalid Operation"); + } +} + +void downLinkDataHandle(McpsIndication_t *mcpsIndication) { + Serial.printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n", + mcpsIndication->RxSlot ? "RXWIN2" : "RXWIN1", + mcpsIndication->BufferSize, mcpsIndication->Port); + Serial.print("+REV DATA:"); + for (uint8_t i = 0; i < mcpsIndication->BufferSize; i++) { + Serial.printf("%02X", mcpsIndication->Buffer[i]); + } + Serial.println(); + uint32_t color = mcpsIndication->Buffer[0] << 16 | + mcpsIndication->Buffer[1] << 8 | mcpsIndication->Buffer[2]; +#if (LoraWan_RGB == 1) + turnOnRGB(color, 5000); + turnOffRGB(); +#endif + // process received downlink + + switch (mcpsIndication->Buffer[0]) { + case 0x4D: + /* Sensor Mode Change + Packet format: + | oper | Duty Cycle in seconds | Sensor Mode | Sampling Rate | + Number of readings per measurement | | 0x4D | 2 bytes | 1 + byte | 2 bytes | 1 byte | + */ + ModifySensorSettings(mcpsIndication); + Serial.println("Successfully modified sensor settings."); + appTxDutyCycle = TX_INTERVAL * 1000; // update appTxDutyCycle + break; + case 0x41: + /* Sensor APP Change + Packet format: + | oper | AppEUI(big-endian) | DevEUI(big-endian) | + AppKEY(big-endian) | | 0x41 | 8 bytes | 8 + bytes | 16 bytes | + */ + Serial.println("\n\nAttempting to change TTN Application....."); + if (mcpsIndication->BufferSize == 33) // 33: 0x41, AppEUI, AppKey, DevEUI + { + // Modify AppEUI + ModifyKeys(mcpsIndication); + // Reset + innerWdtEnable(false); + delay(5000); // Wait until the MCU resets + } else { + Serial.println("Invalid Keys!"); + } + break; + case 0x4F: + /* + Sensor Operation control: Start/ Stop/ Reset + Start: measurement uplinks + Stop: cfg packet uplinks + Reset: reset using watchdog timer + */ + Serial.print("Sensor Operation Control ---> "); + process_operation(mcpsIndication); + break; + default: + Serial.println("Invalid downlink format!"); + break; + } +} + +uint16_t distance; +uint16_t batLevel; + +void prepareMaxbotixFrame() { + // Regular Uplink contains: Sensor Error Flags followed by Battery and then + // Sensor Data + + /* + |-------LoraWAN uplink packet format-----------------| + | Error flags | Battery Level | Ultrasonic reading | + | 1 byte | 2 bytes | 2 bytes | + + |-----Ultrasonic reading------| + | 2 bytes | + | high byte | low byte | + + |-------Battery Level-------| + | 2 bytes | + | high byte | low byte | + + |----------------------------------------------Error Flags + ------------------------------------------------------| | bit 7 | bit 6 + | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 | | Used + only for CFG update | | | | | | + | SD error flag | + */ + + byte lowbyte, highbyte, lowbat, highbat; + + // Regular Uplink Packet size + appDataSize = 5; + + // Maxbotix + distance = read_sensor_using_modes(sensorMode, sensor_sampling_rate, + sensor_numberOfReadings); + Serial.print("Distance = "); + Serial.print(distance); + Serial.println(" mm"); + + // Battery + batLevel = getBatteryVoltage(); /* get the BatteryVoltage in mV. */ + Serial.print("Battery Level = "); + Serial.print(batLevel); + Serial.println(" V"); + + // Payload + lowbat = lowByte(batLevel); + highbat = highByte(batLevel); + appData[0] = (unsigned char)ERROR_FLAGS; + appData[1] = (unsigned char)lowbat; // we're unsigned + appData[2] = (unsigned char)highbat; + lowbyte = lowByte(distance); + highbyte = highByte(distance); + appData[3] = (unsigned char)lowbyte; + appData[4] = (unsigned char)highbyte; +} + +void prepareRG15Frame(){ + if (counter_rg15 >= 1440){ + Serial.println("Resetting Counter...."); + counter_rg15 = 0; //reset every 24 hrs or 1440 minutes + } + if (counter_rg15==0){ + clearTotalAccRG15(); //clear ACK at every cycle including reset + } + Serial.print("Counter is: ");Serial.println(counter_rg15); + String polledString; + polledString = pollReadingFromRG15(); + polledString.trim(); + Serial.print("polled string: "); Serial.println(polledString); + char charBuffer[140]; + polledString.toCharArray(charBuffer, 140); + char delim[] = " "; + + char *ptr = strtok(charBuffer, delim); // Extract the first word + // Check if it is Acc + char *acc; + acc = strstr (charBuffer, "Acc"); + bool mmFound = false; + float readings_array_pg15[4]; + if (*acc == 'A' && *(acc + 1) == 'c' && *(acc + 2) == 'c') { + int cntr = 0; // measurements counter; 4 total if Acc in line + while (ptr != NULL) { + char *foundDot = strstr (ptr, "."); + if (foundDot != NULL) { + char *p = ptr; // char pointer + int ctr2 = 0; // char counter + char arr[6]; // arr to store reading + while (*p != NULL) { + arr[ctr2] = *p; + p++; + ctr2++; + } + readings_array_pg15[cntr] = atof(arr) * 100; // convert char array to readings and *100 to remove decimals + // Serial.println(readings_array_pg15[cntr]); + cntr = cntr + 1; + } + ptr = strtok (NULL, " "); // Iterate + if (!mmFound) { // Check units + if (*ptr == 'm' && *(ptr + 1) == 'm') { + mmFound = true; + } + } + } + } + appDataSize = 17; + int idx = 0; + // Serial.println("The readings are: "); + for (int i = 0; i < 4; i++) { + // Serial.println(readings_array_pg15[i]); + appData[4 * i] = byte((uint32_t)readings_array_pg15[i] & 0xFF); + // Serial.println(appData[4 * i]); + appData[4 * i + 1] = byte(((uint32_t)readings_array_pg15[i] >> 8) & 0xFF); + // Serial.println(appData[4 * i + 1]); + appData[4 * i + 2] = byte(((uint32_t)readings_array_pg15[i] >> 16) & 0xFF); + // Serial.println(appData[4 * i + 2]); + appData[4 * i + 3] = byte(((uint32_t)readings_array_pg15[i] >> 32) & 0xFF); + // Serial.println(appData[4 * i + 3]); + } + // Serial.println(); + if (mmFound) { + Serial.println("Units are mm."); + appData[16] = byte('m'); + } else { + Serial.println("Units are in."); + appData[16] = byte('i'); + } + counter_rg15++; +} + +void prepareTippingBucketFrame() { + Serial.print(tip_count); + Serial.println(" tips counted in last period"); + appDataSize = appDataSize +2; + tip_count = tip_count * 100; // milli mm_rain. In payload decoder, divide by 1000 to get rainfall in mm. + byte lowbyte, highbyte; + lowbyte = lowByte(tip_count); + highbyte = highByte(tip_count); + appData[17] = (unsigned char)lowbyte; + appData[18] = (unsigned char)highbyte; + tip_count = 0; +} + +/* Prepares the payload of the frame */ +static void prepareTxFrame(uint8_t port) { + /*appData size is LORAWAN_APP_DATA_MAX_SIZE which is defined in + "commissioning.h". appDataSize max value is LORAWAN_APP_DATA_MAX_SIZE. if + enabled AT, don't modify LORAWAN_APP_DATA_MAX_SIZE, it may cause system + hanging or failure. if disabled AT, LORAWAN_APP_DATA_MAX_SIZE can be + modified, the max value is reference to lorawan region and SF. for example, + if use REGION_CN470, the max value for different DR can be found in + MaxPayloadOfDatarateCN470 refer to DataratesCN470 and BandwidthsCN470 in + "RegionCN470.h". + */ + Serial.println("Preparing TX frame..."); + + // Error flags + ERROR_FLAGS = 0x00; + + switch (SENSOR_STATE) { + case SENSING_STATE: { +// // Cannot use Maxbotix AND other sensors as distance values would be overwritten +// #ifdef USE_MAXBOTIX +// prepareMaxbotixFrame(); +// #endif +// #ifdef USE_RG15 + prepareRG15Frame(); +// #endif + +// #ifdef USE_TIPPING_BUCKET + prepareTippingBucketFrame(); +// #endif + + break; + } + + case CFG_STATE: { + /* + CFG update uplink Format: + | Error Flag | sensor_sleep | sensor_agg | sensor_meas_delta + | sensor_reading_count | sensor_state | fw_ver | | 255 + (FF) | 2 bytes | 1 byte | 2 bytes | 1 + byte | 1 byte | 6 bytes | + + Sensor State: + | Start | Stop | Reset | + | 's' | 'x' | 'r' | + + */ + byte lowbyte, highbyte; + appDataSize = 11; + ERROR_FLAGS = 255; + appData[0] = (unsigned char)ERROR_FLAGS; + + // sensor_sleep + byte lowduty = lowByte(TX_INTERVAL); + byte highduty = highByte(TX_INTERVAL); + appData[1] = (unsigned char)lowduty; + appData[2] = (unsigned char)highduty; + + // sensor_agg + appData[3] = (unsigned char)sensorMode; + + // sensor_meas_delta + lowbyte = lowByte(sensor_sampling_rate); + highbyte = highByte(sensor_sampling_rate); + appData[4] = (unsigned char)lowbyte; + appData[5] = (unsigned char)highbyte; + + // sensor_reading_count + appData[6] = (unsigned char)sensor_numberOfReadings; + + // sensor_state + appData[7] = (unsigned char)get_current_sensor_state(); + + // firmware version + // Major + appData[8] = (unsigned char)MAJOR_VERSION; + // Minor + appData[9] = (unsigned char)MINOR_VERSION; + // Patch + appData[10] = (unsigned char)PATCH_VERSION; + + break; + } + + default: { + // should never reach here + SENSOR_STATE = SENSING_STATE; + break; + } + } +} + +TimerEvent_t joinTimeOut; // TTN join timeout counter + +void joinFailureDebug(void) { + Serial.println("Running Join Failure debug"); + EEPROM.begin(512); + EEPROM.write(selectionAddress, byte('y')); + Serial.println("Join Failed, loading defualt keys.."); + for (int i = 0; i < 8; i++) { + EEPROM.write(newAppAddress, byte(0)); + } + EEPROM.end(); +} + +void joinTimedOutEvent(void) { + joinFailureDebug(); + // reset the MCU + Serial.println( + "Join TimedOut, resetting the MCU will join default TTN Application.."); + innerWdtEnable(false); + delay(5000); // Wait until the MCU resets +} + +void ifJoinedTTN(void) { + // stop the Timer if it is running + if (joinTimeOut.IsRunning) { + TimerStop(&joinTimeOut); + Serial.println("joinTimeOut Timer is stopped"); + } +} + +void startJoiningTTN(void) { + // start the timer + Serial.println("Join TimeOut TimerEvent_t started."); + TimerInit(&joinTimeOut, joinTimedOutEvent); + TimerSetValue(&joinTimeOut, 30000); // 30 seconds + TimerStart(&joinTimeOut); + LoRaWAN.join(); +} + +void tipIncrease() { + tip_count++; +// delay(10); + Serial.println(tip_count); + delay(150); +} + +void setup_lorawan(unsigned int packet_interval) { + /* On reset check if sensor has been deployed. + + no + If deployed -> CFG_STATE + | yes + ^ + if started -> SENSOR_STATE is SENSING_STATE + + */ + PINMODE_INPUT_PULLDOWN(ADC1); + attachInterrupt(ADC1, tipIncrease, CHANGE); + TX_INTERVAL = packet_interval; + EEPROM.begin(512); + is_deployed = char(EEPROM.read(isDeployed)); + is_started = char(EEPROM.read(isStarted)); + EEPROM.end(); + Serial.println(F( + "Checking previously known sensor state and setting up dutycycle.....")); + if (is_deployed == 'y') { + Serial.println( + "\n\n========================================================="); + Serial.println("Sensor is deployed!\n"); + Serial.print("Reset cause CY_SYS_RESET_WDT: "); + Serial.println(CY_SYS_RES_CAUSE_REG & (CY_SYS_RESET_WDT)); // If True - 1 + Serial.print("Reset cause CY_SYS_RESET_PROTFAULT: "); + Serial.println(CY_SYS_RES_CAUSE_REG & + (CY_SYS_RESET_PROTFAULT)); // If true - 8 + Serial.print("Reset cause CY_SYS_RESET_SW: "); + Serial.println(CY_SYS_RES_CAUSE_REG & (CY_SYS_RESET_SW)); // If true - 16 + if (is_started == 'y') { // deployed and started + Serial.println("\nSensor is started! Uplinks are readings..."); + SENSOR_STATE = SENSING_STATE; + appTxDutyCycle = TX_INTERVAL * 1000; + } else { // deployed but not started + Serial.println( + "\nSensor is not started yet...! Uplinks are CFG packets..."); + SENSOR_STATE = CFG_STATE; + appTxDutyCycle = 10 * 1000; + } + Serial.println( + "=========================================================\n\n"); + } else { // not deployed + SENSOR_STATE = CFG_STATE; + appTxDutyCycle = 10 * 1000; + } + Serial.print(F("\n\nDutycycle is set to ")); + Serial.print(TX_INTERVAL); + Serial.println(F(" seconds.\n\n")); + Serial.println(F("Checking keys...")); + EEPROM.begin(512); + // Check init_ for 'y' or 'n' + char init_ = char(EEPROM.read(init_Address)); + char useOrigApp = char(EEPROM.read(selectionAddress)); + if (init_ == 'y') { + // already initialized and has a new key + if (useOrigApp == 'n' || useOrigApp == 'N') { + // Load new AppEUI + Serial.println("Already initialized and have new keys."); + LoadNewKeys(); + } else { + Serial.println("Using default Keys..."); + // check if any of them are zeroes and load from EEPROM if needed + for (int i = 0; i < 8; ++i) { + devEui[i] = (uint8_t)EEPROM.read(defaultDevEUIAddress + i); // big-endian + } + for (int i = 0; i < 8; ++i) { + appEui[i] = (uint8_t)EEPROM.read(defaultAppEUIAddress + i); // big-endian + } + for (int i = 0; i < 16; ++i) { + appKey[i] = (uint8_t)EEPROM.read(defaultAppKeyAddress + i); // big-endian + } + } + } else { + // First time setup, store default keys + InitStoreKeys(); + } + EEPROM.end(); + deviceState = DEVICE_STATE_INIT; + LoRaWAN.ifskipjoin(); // downlinks fail if this is not called! +} + +void lorawan_runloop_once(void) { + switch (deviceState) { + case DEVICE_STATE_INIT: { + printDevParam(); + LoRaWAN.init(loraWanClass, loraWanRegion); + deviceState = DEVICE_STATE_JOIN; + break; + } + case DEVICE_STATE_JOIN: { + startJoiningTTN(); // Contains LoRaWAN.join() with joinTimeOut Event + break; + } + case DEVICE_STATE_SEND: { + ifJoinedTTN(); // Runs only once on the first packet TX + prepareTxFrame(appPort); + // if CFG, sleep less time + LoRaWAN.send(); + deviceState = DEVICE_STATE_CYCLE; + break; + } + case DEVICE_STATE_CYCLE: { + // Schedule next packet transmission + txDutyCycleTime = appTxDutyCycle + randr(0, APP_TX_DUTYCYCLE_RND); + LoRaWAN.cycle(txDutyCycleTime); + // check if state is reset + if (SENSOR_STATE == RESET_STATE) { + // Reset + innerWdtEnable(false); + delay(5000); // Wait until the MCU resets + } + Serial.print("Going to sleep, next uplink in "); + Serial.print(TX_INTERVAL); + Serial.println(" s."); + deviceState = DEVICE_STATE_SLEEP; + break; + } + case DEVICE_STATE_SLEEP: { + CySysWdtDisable(); + LoRaWAN.sleep(); + break; + } + + default: { + deviceState = DEVICE_STATE_INIT; + break; + } + } +} diff --git a/src/floodsensor/lorawan.h b/src/floodsensor/lorawan.h new file mode 100644 index 00000000..28388900 --- /dev/null +++ b/src/floodsensor/lorawan.h @@ -0,0 +1,14 @@ +#ifndef LORAWAN_H +#define LORAWAN_H + +#pragma once + +#include "LoRaWan_APP.h" +#include + + + +void lorawan_runloop_once(void); +void setup_lorawan(unsigned int packet_interval); //seconds + +#endif diff --git a/src/floodsensor/maxbotix.cpp b/src/floodsensor/maxbotix.cpp new file mode 100644 index 00000000..aa765a5e --- /dev/null +++ b/src/floodsensor/maxbotix.cpp @@ -0,0 +1,107 @@ +#include "maxbotix.h" +#include "functions.h" +#include "sensorcfg.h" + +// Maxbotix Ultrasonic variables +uint16_t readings_arr[30] = {0}; +size_t n = *(&readings_arr + 1) - readings_arr; + +unsigned int sensorMode; +unsigned int sensor_sampling_rate; +unsigned int sensor_numberOfReadings; + +void setup_maxbotix(unsigned int mode=2, unsigned int sampling_rate=250 , unsigned int numberOfReadings=7) { + Serial.println("Setting up Maxbotix .... "); + pinMode(Vext, OUTPUT); + digitalWrite(Vext, HIGH); //power line: now off + pinMode(triggerPin, OUTPUT); + digitalWrite(triggerPin, LOW); //trigger line: now off + Serial1.begin(9600); + Serial.println("Sensor Settings:"); + sensorMode = mode; + Serial.print(" Sensor mode: "); + Serial.println(sensorMode); + sensor_sampling_rate = sampling_rate; + Serial.print(" Sensor sampling rate: "); + Serial.println(sensor_sampling_rate); + sensor_numberOfReadings = numberOfReadings; + Serial.print(" Number of readings per measurement: "); + Serial.println(sensor_numberOfReadings); +} + +uint16_t sensor_singleread(void) { + int distance = 0; + char serialbuffer[4]; + int index = 0; + char rc; + Serial1.flush(); + digitalWrite(triggerPin, HIGH); + delayMicroseconds(20); + digitalWrite(triggerPin, LOW); + delay(150); + boolean newData = false; + while (newData == false) { + if (Serial1.available()>0) + { + char rc = Serial1.read(); + if (rc == 'R') + { + while (index < 4) + { + if (Serial1.available()) + { + serialbuffer[index] = Serial1.read(); + index++; + } + } + } + distance = (serialbuffer[0] - '0') * 1000 + (serialbuffer[1] - '0') * 100 + (serialbuffer[2] - '0') * 10 + (serialbuffer[3] - '0'); + if (distance>=0){ // Max range readings + newData = true; + } + } + } + if (newData) { + Serial.print("distance: "); Serial.print(distance); Serial.println(" mm"); + } + return distance; +} + + +uint16_t read_sensor_using_modes(unsigned int sensorMode, unsigned int sensor_sampling_rate = 20, unsigned int sensor_numberOfReadings = 5) +{ + uint16_t distance = 0; + digitalWrite(Vext, LOW); + sensor_singleread(); + for (int i = 0; i < sensor_numberOfReadings + 1; i++) { + if (i>0){ //1st reading is R from "Maxbotix Corp" + readings_arr[i] = sensor_singleread(); + } + delay(sensor_sampling_rate); + } + digitalWrite(Vext, HIGH); + sort(readings_arr, n); + switch (sensorMode) { + case 1: + // Mean + distance = mean(readings_arr, n, sensor_numberOfReadings); + break; + case 2: + // Median + distance = median(readings_arr, n, sensor_numberOfReadings); + break; + case 3: + // Mode + distance = mode(readings_arr, n, sensor_numberOfReadings); + break; + default: + // Single Pulse-In single reading + distance = sensor_singleread(); + break; + } + Serial.println("Cleaning measurements array..."); + for (int i = 0; i < n; i++) { + readings_arr[i] = 0; + } + return distance; +} \ No newline at end of file diff --git a/src/maxbotix.h b/src/floodsensor/maxbotix.h similarity index 83% rename from src/maxbotix.h rename to src/floodsensor/maxbotix.h index 4e7188ca..d725988f 100644 --- a/src/maxbotix.h +++ b/src/floodsensor/maxbotix.h @@ -1,10 +1,9 @@ #ifndef MAXBOTIX_H #define MAXBOTIX_H -#include "Arduino.h" +#define triggerPin GPIO5 -#define readPin 11 -#define triggerPin 12 +#include void setup_maxbotix(unsigned int mode, unsigned int sampling_rate , unsigned int numberOfReadings); uint16_t read_sensor_using_modes(unsigned int sensorMode, unsigned int sensor_sampling_rate, unsigned int sensor_numberOfReadings); diff --git a/src/floodsensor/rg15.cpp b/src/floodsensor/rg15.cpp new file mode 100644 index 00000000..3566739c --- /dev/null +++ b/src/floodsensor/rg15.cpp @@ -0,0 +1,172 @@ +#include "rg15.h" +#include "sensorcfg.h" +/* + RG-15 Rain Sensor commands: + A Reads accumulation data + R Read all available data + K Restart the rain sensor + P Set to polling only mode (currenlty used) + C Set to continuous mode, where data is sent when accumulation changes (default) + H Force high resolution + L Force low resolution + I Force imperial + M Force metric (default) + S Revert to jumper configured values + O Reset the accumulation counter +*/ + +/* + RG-15 Possible Reset reasons: + Reset N N = Normal Power Up (default) + Reset M M = MCLR + Reset W W = Watchdog Timer Reset + Reset O O = Stack Overflow + Reset U U = Stack Underflow + Reset B B = Brownout (Low Voltage/disconnected) + Reset D D = Other +*/ + +String RG15_OP_MODE; +uint32_t MAX_COUNTER_RG15 = 1440; + +void sendCMDRG15(char cmd) { + Serial1.println(cmd); +} + +String getResponseRG15(uint TIME_OUT = 3000) { + String readSerial; + unsigned long startTime = millis(); + while (1) { + while (Serial1.available()) { + if (Serial1.available() > 0) { + char c = Serial1.read(); //gets one byte from serial buffer + readSerial += c; //makes the string readString + } + } + if (millis() - startTime > TIME_OUT) { + // Serial.println("Timedout"); + break; + } + } + return readSerial; +} + +void printResponseRG15(uint TIME_OUT = 3000) { + unsigned long startTime = millis(); + while (Serial1.available() > 0) { + if (Serial1.available() > 0) { + char c = Serial1.read(); //gets one byte from serial buffer + Serial.print(c); //makes the string readString + } + if (millis() - startTime > TIME_OUT) { + // Serial.println("Timedout"); + break; + } + } +} + +bool setModeTo(char m) { + bool modeSet = false; + String response; + Serial1.println(m); + response = getResponseRG15(3000); + if (response.length() > 0) { + response.toUpperCase(); + if (response.charAt(0) == m) { + Serial.print("Mode set successfully to: "); + Serial.println(RG15_OP_MODE); //always true + modeSet = true; + } + } + return modeSet; +} + +void clearTotalAccRG15(void) { + sendCMDRG15('O'); // Clear any previous Total Acc +} + +void hardResetRG15(void) { + sendCMDRG15('K'); // send Hard-reset command + String readSerial = getResponseRG15(10000); + Serial.println(readSerial); + clearTotalAccRG15(); // clear Total Acc +} + +void debugRG15(void) { // Hard reset and set mode to Polling + hardResetRG15(); + char m = RG15_OP_MODE.charAt(0); + bool modeSet = setModeTo(m); +} + +String readLastAvilableReading(void) { + String readSerial; + sendCMDRG15('R'); // get reading + readSerial = getResponseRG15(); + return readSerial; +} + +bool checkForErrors(String str) { + if (str.charAt(0) != 'A') { + Serial.println("Error Detected debugging..."); + return true; + } else { + Serial.println("No errors."); + return false; + } +} + +bool isEventDetected(String str) { + if (str.charAt(0) == ';' && str.indexOf("Event") > 0) { + Serial.println("Event detected by RG-15"); + return true; + } else { + return false; + } +} + +String pollReadingFromRG15(void) { + // Set mode to Polling + char m = RG15_OP_MODE.charAt(0); + bool modeSet = setModeTo(m); + // Poll last available reading + sendCMDRG15('R'); // get reading + String lastAvailReading = readLastAvilableReading(); + lastAvailReading.trim(); + // check if it is Event detected string + /* Event detected string format: + ;---------------------------------------- + Event + SW 1.000 2020.07.06 + */ + // Check for Event + bool eventDetected = isEventDetected(lastAvailReading); + if (eventDetected) { + // read again + lastAvailReading = readLastAvilableReading(); + lastAvailReading.trim(); + } + bool errorDetected = checkForErrors(lastAvailReading); + if (errorDetected) { + // debug and read again + debugRG15(); + + lastAvailReading = readLastAvilableReading(); + lastAvailReading.trim(); + } + return lastAvailReading; +} + +void setup_RG15(String mode = "Polling") { // Allowed strings: "P", "Polling", "C", "Continuous" + // get mode + RG15_OP_MODE = mode; + char m = RG15_OP_MODE.charAt(0); + // opens Serial1 port, sets data rate to 9600 bps + Serial1.begin(9600); + printResponseRG15(10000); + hardResetRG15(); + //Manual mode set + setModeTo(m); + // Check reset counter Max value + MAX_COUNTER_RG15 = 1440; //(24*60*1000)/TX_INTERVAL + Serial.print("the MAX_COUNTER_RG15 is: "); Serial.println(MAX_COUNTER_RG15); +} diff --git a/src/floodsensor/rg15.h b/src/floodsensor/rg15.h new file mode 100644 index 00000000..e5014074 --- /dev/null +++ b/src/floodsensor/rg15.h @@ -0,0 +1,12 @@ +#ifndef RG15_H +#define RG15_H + +#define bufferSize 144 + +#include + +void setup_RG15(String RG15_OP_MODE); // Allowed strings: "P", "Polling", "C", "Continuous" +String pollReadingFromRG15(void); +void clearTotalAccRG15(void); + +#endif \ No newline at end of file diff --git a/src/sensorcfg.h b/src/floodsensor/sensorcfg.h similarity index 60% rename from src/sensorcfg.h rename to src/floodsensor/sensorcfg.h index f138ace1..698db752 100644 --- a/src/sensorcfg.h +++ b/src/floodsensor/sensorcfg.h @@ -3,26 +3,28 @@ #pragma once +// ------------------- Sensors ------------------------- + +//#define USE_MAXBOTIX +// #define USE_RG15 +#define USE_TIPPING_BUCKET + // ------------------ Pins ------------------------- -#define VBATPIN A7 -#define cardSelect 10 // ---------------- Constants ---------------------- -// SD chip select pin -#define chipSelect 10 // ---------------- Variables ---------------------- // Duty cycle -extern unsigned int TX_INTERVAL; +extern uint32_t appTxDutyCycle; /* Sensor Operation Modes: - Mode 1: Mean - Mode 2: Median - Mode 3: Mode -*/ + Mode 1: Mean + Mode 2: Median + Mode 3: Mode + */ extern unsigned int sensorMode; // Time between the readings @@ -31,8 +33,11 @@ extern unsigned int sensor_sampling_rate; // Number of readings for a given sensor mode extern unsigned int sensor_numberOfReadings; -// ------------------- Error Flags ---------------------- +// Rg-15 Acc reset +// uint32_t MAX_COUNTER_RG15 = 1440; -extern int SD_ERROR; +extern String RG15_OP_MODE; //allowed: "P", "Polling", "C", "Continuous" + +// ------------------- Error Flags ---------------------- -#endif +#endif \ No newline at end of file diff --git a/src/ttncredentials.h b/src/floodsensor/ttncredentials.h similarity index 79% rename from src/ttncredentials.h rename to src/floodsensor/ttncredentials.h index 3383ddf2..f792d6b5 100644 --- a/src/ttncredentials.h +++ b/src/floodsensor/ttncredentials.h @@ -4,12 +4,12 @@ // Enter your keys here // This EUI must be in little-endian format For TTN issued EUIs the last bytes should be 0xD5, 0xB3, 0x70. -#define TTN_APPEUI { } +#define TTN_APPEUI {} // This should also be in little endian format -#define TTN_DEVEUI { } +#define TTN_DEVEUI {} // This key should be in big endian format -#define TTN_APPKEY { } +#define TTN_APPKEY {} #endif diff --git a/src/functions.cpp b/src/functions.cpp deleted file mode 100644 index 18247fb0..00000000 --- a/src/functions.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "functions.h" - -void printHex2(unsigned v) { - v &= 0xff; - if (v < 16) - Serial.print('0'); - Serial.print(v, HEX); -} - -void swap(uint16_t *p, uint16_t *q) { - int t; - - t = *p; - *p = *q; - *q = t; -} - -void sort(uint16_t a[], size_t n) { - int i, j, temp; - - for (i = 0; i < n - 1; i++) { - for (j = 0; j < n - i - 1; j++) { - if (a[j] < a[j + 1]) - swap(&a[j], &a[j + 1]); - } - } -} - -uint16_t mean(uint16_t readings_arr[], size_t n, unsigned int sensor_numberOfReadings){ - uint16_t readings_sum = 0; - for (int i=0; i max ){ - max = counter; - mode_ = readings_arr[i]; - } - } else - counter = 1; // reset counter. - } - return mode_; -} diff --git a/src/lmicpinmappings.h b/src/lmicpinmappings.h deleted file mode 100644 index b8e0e13e..00000000 --- a/src/lmicpinmappings.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef LMICPINMAPPINGS_H -#define LMICPINMAPPINGS_H - -#include "lorawan.h" - -// Pin mapping -// -// Adafruit BSPs are not consistent -- m0 express defs ARDUINO_SAMD_FEATHER_M0, -// m0 defs ADAFRUIT_FEATHER_M0 -// -#if defined(ARDUINO_SAMD_FEATHER_M0) || defined(ADAFRUIT_FEATHER_M0) -// Pin mapping for Adafruit Feather M0 LoRa, etc. -const lmic_pinmap lmic_pins = { - .nss = 8, - .rxtx = LMIC_UNUSED_PIN, - .rst = 4, - .dio = {3, 6, LMIC_UNUSED_PIN}, - .rxtx_rx_active = 0, - .rssi_cal = 8, // LBT cal for the Adafruit Feather M0 LoRa, in dB - .spi_freq = 8000000, -}; -#elif defined(ARDUINO_AVR_FEATHER32U4) -// Pin mapping for Adafruit Feather 32u4 LoRa, etc. -// Just like Feather M0 LoRa, but uses SPI at 1MHz; and that's only -// because MCCI doesn't have a test board; probably higher frequencies -// will work. -const lmic_pinmap lmic_pins = { - .nss = 8, - .rxtx = LMIC_UNUSED_PIN, - .rst = 4, - .dio = {7, 6, LMIC_UNUSED_PIN}, - .rxtx_rx_active = 0, - .rssi_cal = 8, // LBT cal for the Adafruit Feather 32U4 LoRa, in dB - .spi_freq = 1000000, -}; -#elif defined(ARDUINO_CATENA_4551) -// Pin mapping for Murata module / Catena 4551 -const lmic_pinmap lmic_pins = { - .nss = 7, - .rxtx = 29, - .rst = 8, - .dio = { - 25, // DIO0 (IRQ) is D25 - 26, // DIO1 is D26 - 27, // DIO2 is D27 - }, - .rxtx_rx_active = 1, - .rssi_cal = 10, - .spi_freq = 8000000 // 8MHz -}; -#else -# error "Unknown target" -#endif - -#endif diff --git a/src/lorawan.cpp b/src/lorawan.cpp deleted file mode 100644 index c7d2db6e..00000000 --- a/src/lorawan.cpp +++ /dev/null @@ -1,513 +0,0 @@ -#include "lorawan.h" -#include "featherwing.h" -#include "functions.h" -#include "sleep.h" -#include "lmicpinmappings.h" -#include "sensorcfg.h" -#include "maxbotix.h" -#include - -static osjob_t sendjob; - -unsigned int TX_INTERVAL; - -unsigned char cfg_packet[7]; -unsigned char lora_packet[5]; -bool TX_COMPLETED = false; - // Set to false on start and after sleep; is set to true when an uplink is successful -bool UPDATE_CONFIG = true; // Set to true at start and when there is a change in sensor cfg; used to send sensor cfg via uplink - -void os_getArtEui (u1_t* buf) { - memcpy_P(buf, APPEUI, 8); -} - -void os_getDevEui (u1_t* buf) { - memcpy_P(buf, DEVEUI, 8); -} - -void os_getDevKey (u1_t* buf) { - memcpy_P(buf, APPKEY, 16); -} - -void lmicsetup( unsigned int packet_interval = 300) { //Future setup variables - Serial.println(F("Setting up LoraWAN...")); - - digitalWrite(13, HIGH); - // LMIC init - os_init(); - // Reset the MAC state. Session and pending data transfers will be discarded. - LMIC_reset(); - - //LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); - // Disable link check validation (automatically enabled) - LMIC_setLinkCheckMode(0); - LMIC_setDrTxpow(DR_SF7, 14); - LMIC_selectSubBand(1); - digitalWrite(13, LOW); - Serial.println("Setup Ready!"); - TX_INTERVAL = packet_interval; - // Start job (sending automatically starts OTAA too) - Serial.println("Starting first job in setup"); - prepare_packet(); - do_send(&sendjob); -} - -void do_send(osjob_t* j) { - // Check if there is not a current TX/RX job running - if (LMIC.opmode & OP_TXRXPEND) { - Serial.println(F("OP_TXRXPEND, not sending")); - String do_sendstr1 = "OP_TXRXPEND, not sending"; - writeToSDCard(do_sendstr1); - } else { - // Prepare upstream data transmission at the next possible time. - int lmic_tx_retVAL; - if (UPDATE_CONFIG == true){ - lmic_tx_retVAL = LMIC_setTxData2(1, cfg_packet, sizeof(cfg_packet), 0); - } else { - lmic_tx_retVAL = LMIC_setTxData2(1, lora_packet, sizeof(lora_packet), 0); - } - String do_sendstr; - if (lmic_tx_retVAL == 0) { - Serial.println(F("Packet queued and lmic_tx_retVAL is 0.")); - } else { - do_sendstr = String ("Something is wrong: ") + String("Error number: ") + String(lmic_tx_retVAL); - Serial.println(do_sendstr); - writeToSDCard(do_sendstr); - } - } - // Next TX is scheduled after TX_COMPLETE event. -} - -void onEvent (ev_t ev) { - Serial.print(os_getTime()); - Serial.print(": "); - String event_ev; - switch (ev) { - case EV_SCAN_TIMEOUT: - Serial.println(F("EV_SCAN_TIMEOUT")); - event_ev = String(event_ev + "EV_SCAN_TIMEOUT"); - writeToSDCard(event_ev); - break; - case EV_BEACON_FOUND: - Serial.println(F("EV_BEACON_FOUND")); - event_ev = String(event_ev + "EV_BEACON_FOUND"); - writeToSDCard(event_ev); - break; - case EV_BEACON_MISSED: - Serial.println(F("EV_BEACON_MISSED")); - event_ev = String(event_ev + "EV_BEACON_MISSED"); - writeToSDCard(event_ev); - case EV_BEACON_TRACKED: - Serial.println(F("EV_BEACON_TRACKED")); - event_ev = String(event_ev + "EV_BEACON_TRACKED" ); - writeToSDCard(event_ev); - break; - case EV_JOINING: - Serial.println(F("EV_JOINING")); - event_ev = String(event_ev + "EV_JOINING"); - writeToSDCard(event_ev); - break; - case EV_JOINED: - Serial.println(F("EV_JOINED")); - event_ev = String(event_ev + "EV_JOINED" ); - writeToSDCard(event_ev); - { - u4_t netid = 0; - devaddr_t devaddr = 0; - u1_t nwkKey[16]; - u1_t artKey[16]; - LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey); - Serial.print("netid: "); - Serial.println(netid, DEC); - Serial.print("devaddr: "); - Serial.println(devaddr, HEX); - Serial.print("AppSKey: "); - for (size_t i = 0; i < sizeof(artKey); ++i) { - if (i != 0) - Serial.print("-"); - printHex2(artKey[i]); - } - Serial.println(""); - Serial.print("NwkSKey: "); - for (size_t i = 0; i < sizeof(nwkKey); ++i) { - if (i != 0) - Serial.print("-"); - printHex2(nwkKey[i]); - } - Serial.println(); - } - // Disable link check validation (automatically enabled - // during join, but because slow data rates change max TX - // size, we don't use it in this example. - LMIC_setLinkCheckMode(0); - break; - /* - || This event is defined but not used in the code. No - || point in wasting codespace on it. - || - || case EV_RFU1: - || Serial.println(F("EV_RFU1")); - || break; - */ - case EV_JOIN_FAILED: - Serial.println(F("EV_JOIN_FAILED")); - event_ev = String(event_ev + "EV_JOIN_FAILED"); - writeToSDCard(event_ev); - break; - case EV_REJOIN_FAILED: - Serial.println(F("EV_REJOIN_FAILED")); - event_ev = String(event_ev + "EV_REJOIN_FAILED" ); - writeToSDCard(event_ev); - break; - break; - case EV_TXCOMPLETE: - Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); - Serial.println(""); - Serial.println(""); - event_ev = String(event_ev + "EV_TXCOMPLETE (includes waiting for RX windows)"); - writeToSDCard(event_ev); - if (LMIC.txrxFlags & TXRX_ACK) - Serial.println(F("Received ack")); - event_ev = String("Received ack"); - writeToSDCard(event_ev); - UPDATE_CONFIG = false; - if (LMIC.dataLen) { - Serial.print(F("Received ")); - Serial.print(LMIC.dataLen); - Serial.print(" bytes of payload: 0x"); - for (int i = 0; i < LMIC.dataLen; i++) { - if (LMIC.frame[LMIC.dataBeg + i] < 0x10) { - Serial.print(F("0")); - } - Serial.print(LMIC.frame[LMIC.dataBeg + i], HEX); - } - Serial.println(); - process_received_downlink(); - } - TX_COMPLETED = true; - break; - case EV_LOST_TSYNC: - Serial.println(F("EV_LOST_TSYNC")); - event_ev = String(event_ev + "EV_LOST_TSYNC" ); - writeToSDCard(event_ev); - break; - case EV_RESET: - Serial.println(F("EV_RESET")); - event_ev = String(event_ev + "EV_RESET"); - writeToSDCard(event_ev); - break; - case EV_RXCOMPLETE: - // data received in ping slot - Serial.println(F("EV_RXCOMPLETE")); - event_ev = String(event_ev + "EV_RXCOMPLETE"); - writeToSDCard(event_ev); - break; - case EV_LINK_DEAD: - Serial.println(F("EV_LINK_DEAD")); - event_ev = String(event_ev + "EV_LINK_DEAD"); - writeToSDCard(event_ev); - break; - case EV_LINK_ALIVE: - Serial.println(F("EV_LINK_ALIVE")); - event_ev = String(event_ev + "EV_LINK_ALIVE"); - writeToSDCard(event_ev); - break; - /* - || This event is defined but not used in the code. No - || point in wasting codespace on it. - || - || case EV_SCAN_FOUND: - || Serial.println(F("EV_SCAN_FOUND")); - || break; - */ - case EV_TXSTART: - Serial.println(F("EV_TXSTART")); - event_ev = String(event_ev + "EV_TXSTART"); - writeToSDCard(event_ev); - break; - case EV_TXCANCELED: - Serial.println(F("EV_TXCANCELED")); - event_ev = String(event_ev + "EV_TXCANCELED"); - writeToSDCard(event_ev); - break; - case EV_RXSTART: - /* do not print anything -- it wrecks timing */ - break; - case EV_JOIN_TXCOMPLETE: - Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept")); - event_ev = String(event_ev + "EV_JOIN_TXCOMPLETE: no JoinAccept" ); - writeToSDCard(event_ev); - break; - default: - Serial.print(F("Unknown event: ")); - event_ev = String(event_ev + "Unknown event"); - Serial.println((unsigned) ev); - writeToSDCard(event_ev); - break; - } -} - -void update_TX_INTERVAL(unsigned long dutycycle){ - Serial.print("Current duty cycle is: "); - Serial.println(TX_INTERVAL); - String str_downlink = String("Current duty cycle is: ") + String(TX_INTERVAL); - writeToSDCard(str_downlink); - // Changing Duty Cycle - TX_INTERVAL = dutycycle; - Serial.print("Updated dutycycle is: "); - Serial.println(TX_INTERVAL); - str_downlink = String("Updated dutycycle is: ") + String(TX_INTERVAL); - writeToSDCard(str_downlink); -} - -void update_sensorMode(unsigned int sensorMode_){ - Serial.print("Current sensorMode is: "); - Serial.println(sensorMode); - String str_downlink = String("Current sensorMode is: ") + String(sensorMode); - writeToSDCard(str_downlink); - // Changing Sensor Mode - sensorMode = sensorMode_; - Serial.print("Updated sensorMode is: "); - Serial.println(sensorMode); - str_downlink = String("Updated sensorMode is: ") + String(sensorMode); - writeToSDCard(str_downlink); -} - -void update_sampling_rate(unsigned int sampling_rate){ - Serial.print("Current sensor sampling rate is: "); - Serial.println(sensor_sampling_rate); - String str_downlink = String("Current sensor sampling rate is: ") + String(sensor_sampling_rate); - writeToSDCard(str_downlink); - // Changing Sensor Mode - sensor_sampling_rate = sampling_rate; - Serial.print("Updated sensor sampling rate is: "); - Serial.println(sensor_sampling_rate); - str_downlink = String("Updated sensor sampling rate is: ") + String(sensor_sampling_rate); - writeToSDCard(str_downlink); -} - -void update_no_of_readings(unsigned int numb_readings){ - Serial.print("Current number of readings per measurement: "); - Serial.println(sensor_numberOfReadings); - String str_downlink = String("Current number of readings per measurement: ") + String(sensor_numberOfReadings); - writeToSDCard(str_downlink); - // Changing Sensor Mode - sensor_numberOfReadings = numb_readings; - Serial.print("Updated number of readings per measurement: "); - Serial.println(sensor_numberOfReadings); - str_downlink = String("Updated number of readings per measurement: ") + String(sensor_numberOfReadings); - writeToSDCard(str_downlink); -} - -void process_received_downlink(void) { - /* Downlink Packet format: - |Duty Cycle in seconds | Sensor Mode | Sampling Rate | Number of readings per measurement | - | 2 byte | 1 byte | 2 bytes | 1 bytes | - */ - // set UPDATE_CONFIG to true - UPDATE_CONFIG = true; - String str_downlink = String("Processing received downlink...."); - writeToSDCard(str_downlink); - unsigned int downlink_payload_size = LMIC.dataLen; - unsigned long dutycycle = 0; - unsigned int sensorMode_ = 0; - unsigned int sampling_rate = 0; - unsigned int numb_readings = 0; - - switch(downlink_payload_size){ - - case 1: case 2: - for (int i = 0; i < downlink_payload_size; i++) { - dutycycle = (LMIC.frame[LMIC.dataBeg + i]) | ( dutycycle << 8*i); - } - if (dutycycle!= 0){ - update_TX_INTERVAL(dutycycle); - } else{ - Serial.println("Dutycycle is the same."); - } - break; - - case 3: - for (int i = 0; i < 2; i++) { - dutycycle = (LMIC.frame[LMIC.dataBeg + i]) | ( dutycycle << 8*i); - } - if (dutycycle!= 0){ - update_TX_INTERVAL(dutycycle); - } else{ - Serial.println("Dutycycle is the same."); - } - - sensorMode_ = (LMIC.frame[LMIC.dataBeg + 2]) | ( sensorMode_ ); - if (sensorMode_!= 0 && sensorMode<=3 ){ - update_sensorMode(sensorMode_); - } else{ - Serial.println("Sensor Mode is the same."); - } - break; - - case 5: - for (int i = 0; i < 2; i++) { - dutycycle = (LMIC.frame[LMIC.dataBeg + i]) | ( dutycycle << 8*i); - } - if (dutycycle!= 0){ - update_TX_INTERVAL(dutycycle); - } else{ - Serial.println("Dutycycle is the same."); - } - sensorMode_ = (LMIC.frame[LMIC.dataBeg + 2]) | ( sensorMode_ ); - if (sensorMode_!= 0 && sensorMode<=3 ){ - update_sensorMode(sensorMode_); - } else{ - Serial.println("Sensor Mode is the same."); - } - sampling_rate = (LMIC.frame[LMIC.dataBeg + 3]) | ( sampling_rate ); - sampling_rate = (LMIC.frame[LMIC.dataBeg + 4]) | ( sampling_rate << 8); - if (sampling_rate!= 0 ){ - update_sampling_rate(sampling_rate); - } else{ - Serial.println("Sensor sampling rate is the same."); - } - break; - - case 6: - for (int i = 0; i < 2; i++) { - dutycycle = (LMIC.frame[LMIC.dataBeg + i]) | ( dutycycle << 8*i); - } - if (dutycycle!= 0){ - update_TX_INTERVAL(dutycycle); - } else{ - Serial.println("Dutycycle is the same."); - } - sensorMode_ = (LMIC.frame[LMIC.dataBeg + 2]) | ( sensorMode_ ); - if (sensorMode_!= 0 && sensorMode<=3 ){ - update_sensorMode(sensorMode_); - } else{ - Serial.println("Sensor Mode is the same."); - } - sampling_rate = (LMIC.frame[LMIC.dataBeg + 3]) | ( sampling_rate ); - sampling_rate = (LMIC.frame[LMIC.dataBeg + 4]) | ( sampling_rate << 8); - if (sampling_rate!= 0 ){ - update_sampling_rate(sampling_rate); - } else{ - Serial.println("Sensor sampling rate is the same."); - } - numb_readings = (LMIC.frame[LMIC.dataBeg + 5]) | ( numb_readings ); - if (numb_readings!= 0 && numb_readings<=20){ - update_no_of_readings(numb_readings); - } else{ - Serial.println("Sensor number of readings per measurement is the same."); - } - break; - } -} - -uint16_t distance; -// Measured Battery Level in mVolts -float measuredvbat; -uint16_t batlevel; -unsigned int ERROR_FLAGS; - -void prepare_packet(void) { - - byte lowbyte, highbyte, lowbat, highbat; - String packet_data; - // Error - ERROR_FLAGS = pow(2,0)* SD_ERROR; - - // Formatting payload - if (UPDATE_CONFIG == true){ - // Send Sensor Config via Uplink - /* - CFG update uplink Format: - | Error Flag | Sensor Mode | Sensor Sampling Rate | Sensor Number of Readings | - | 255 (FF) | 1 byte | 2 bytes | 1 bytes | - */ - ERROR_FLAGS = 255; - cfg_packet[0] = (unsigned char)ERROR_FLAGS; - packet_data = String("CFG Update via Uplink"); - writeToSDCard(packet_data); - byte lowduty = lowByte(TX_INTERVAL); - byte highduty = highByte(TX_INTERVAL); - cfg_packet[1] = (unsigned char)lowduty; - cfg_packet[2] = (unsigned char)highduty; - cfg_packet[3] = (unsigned char)sensorMode; - lowbyte = lowByte(sensor_sampling_rate); - highbyte = highByte(sensor_sampling_rate); - cfg_packet[4] = (unsigned char)lowbyte; - cfg_packet[5] = (unsigned char)highbyte; - cfg_packet[6] = (unsigned char)sensor_numberOfReadings; - } - else { - // Regular Uplink contains: Sensor Error Flags followed by Battery and then Sensor Data - - /* LoraWAN uplink packet format - | Error flags | Battery Level | Ultrasonic reading | - | 1 byte | 2 bytes | 2 bytes | - | Ultrasonic reading | - | 2 bytes | - | high byte | low byte | - | Battery Level | - | 2 bytes | - | high byte | low byte | - |------------------------------------------------------------ Error Flags ----------------------------------------------------------------| - | bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 | - | Used only for CFG update (all other bits are high) | | | | | | | SD error flag | - */ - - - - // Maxbotix - distance = read_sensor_using_modes(sensorMode, sensor_sampling_rate, sensor_numberOfReadings); - Serial.print("Distance = "); - Serial.print(distance); - Serial.println(" mm"); - packet_data = String("Distance in mm is: ") + String(distance); - writeToSDCard(packet_data); - - // Battery - measuredvbat = analogRead(VBATPIN); //Float - measuredvbat *= 2; // we divided by 2, so multiply back - measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage - measuredvbat /= 1024; // convert to voltage - Serial.print("VBat: " ); Serial.println(measuredvbat); - measuredvbat *= 1000; //make it milli volts to transmit - Serial.print("VBat in mVolts: " ); Serial.println(measuredvbat); - batlevel = measuredvbat; //Payload - packet_data = String("Battery Level in mVolts is: ") + String(batlevel); - writeToSDCard(packet_data); - - // Payload - lowbat = lowByte(batlevel); - highbat = highByte(batlevel); - lora_packet[0] = (unsigned char)ERROR_FLAGS; - packet_data = String("SD Error flag is: ") + String(SD_ERROR); - writeToSDCard(packet_data); - lora_packet[1] = (unsigned char)lowbat; //we're unsigned - lora_packet[2] = (unsigned char)highbat; - lowbyte = lowByte(distance); - highbyte = highByte(distance); - lora_packet[3] = (unsigned char)lowbyte; - lora_packet[4] = (unsigned char)highbyte; - } -} - -void lorawan_runloop_once() { - os_runloop_once(); - //&& TX_COMPLETED == true - //!(LMIC.opmode & OP_TXRXPEND) - if ( !os_queryTimeCriticalJobs(ms2osticksRound(8000) ) && TX_COMPLETED == true ) { - TX_COMPLETED = false; - // This means the previous TX is complete and also no Critical Jobs pending in LMIC - Serial.println("About to go to deep sleep and no critical jobs"); - //delay(30000); - gotodeepsleepnow(TX_INTERVAL); - Serial.println("Im awake and TX_COMPLETED is set to false"); - while(LMIC.opmode & OP_TXRXPEND){ - os_runloop_once(); - } - - //Prepare a packet in relaxed setiing - prepare_packet(); - os_setCallback(&sendjob, do_send); - } -} diff --git a/src/lorawan.h b/src/lorawan.h deleted file mode 100644 index b9088acf..00000000 --- a/src/lorawan.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef LORAWAN_H -#define LORAWAN_H - -#include -#include -#include -#include -#include "ttncredentials.h" - - -// This EUI must be in little-endian format -static const u1_t PROGMEM APPEUI[8] = TTN_APPEUI ; -// This should also be in little endian format -static const u1_t PROGMEM DEVEUI[8] = TTN_DEVEUI ; -// This key should be in big endian format -static const u1_t PROGMEM APPKEY[16] = TTN_APPKEY ; - -void os_getArtEui (u1_t* buf); -void os_getDevEui (u1_t* buf); -void os_getDevKey (u1_t* buf); - -void do_send(osjob_t* j); -void onEvent (ev_t ev); -void prepare_packet(void); -void lorawan_runloop_once(void); -void lmicsetup(unsigned int packet_interval); -void process_received_downlink(void); - -#endif diff --git a/src/maxbotix.cpp b/src/maxbotix.cpp deleted file mode 100644 index 632acb57..00000000 --- a/src/maxbotix.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "maxbotix.h" -#include "functions.h" -#include "sensorcfg.h" -#include "featherwing.h" - -// Maxbotix Ultrasonic variables -uint16_t readings_arr[20] = {0}; -size_t n = *(&readings_arr + 1) - readings_arr; - -unsigned int sensorMode; -unsigned int sensor_sampling_rate; -unsigned int sensor_numberOfReadings; - -void setup_maxbotix(unsigned int mode=2, unsigned int sampling_rate=250 , unsigned int numberOfReadings=5) { - String setup_mb; - Serial.println("Setting up Maxbotix .... "); - writeToSDCard(String("Setting up Maxbotix .... ")); - pinMode(triggerPin, OUTPUT); - digitalWrite(triggerPin, LOW); - Serial1.begin(9600); - Serial.println("Sensor Settings:"); - sensorMode = mode; - Serial.print(" Sensor mode: "); - Serial.println(sensorMode); - sensor_sampling_rate = sampling_rate; - Serial.print(" Sensor sampling rate: "); - Serial.println(sensor_sampling_rate); - sensor_numberOfReadings = numberOfReadings; - Serial.print(" Number of readings per measurement: "); - Serial.println(sensor_numberOfReadings); -} - -uint16_t sensor_singleread(void) { - uint16_t distance; - char buffer_RTT[6] = {}; - digitalWrite(triggerPin, HIGH); - delayMicroseconds(20); //Pin 4 ned to be pulled High for a minimum of 20 microseconds. - digitalWrite(triggerPin, LOW); - delay(150); - if (Serial1.available() > 0) { - do { - if (Serial1.read() == 'R') { - for (int i = 0; i < 5; i++) { - buffer_RTT[i] = Serial1.read(); - } - } - } while (buffer_RTT == NULL); - distance = (buffer_RTT[0] - '0') * 1000 + (buffer_RTT[1] - '0') * 100 + (buffer_RTT[2] - '0') * 10 + (buffer_RTT[3] - '0'); - Serial.print("distance: "); Serial.print(distance); Serial.println(" mm"); - } - return distance; -} - - -uint16_t read_sensor_using_modes(unsigned int sensorMode, unsigned int sensor_sampling_rate=20, unsigned int sensor_numberOfReadings=5) -{ - String readings_array_string = ""; - uint16_t distance = 0; - sensor_singleread(); // Ignore First read; First read in serial mode is incorrect - Serial.println("Reading sensor using modes, entering measurements into an array..."); - writeToSDCard("Reading sensor using modes, entering measurements into an array..."); - for(int i=0;i - -void gotodeepsleepnow(unsigned int sleep_time); - -#endif