Initial public release of WII5 Buoy firmware
Firmware for an autonomous wave-measurement buoy (ATmega2560-based WII5 v2 board). Reads wave motion from a Sparton AHRS-M1/M2 IMU, samples GPS and battery state, and reports back over Iridium SBD satellite telemetry. Originally developed 2012-2024. This is the first public release. Code, documentation, and field-tested operating modes (Capture, Sleep, Position, ManualTest, SelfTest, LowBattery) are licensed under Apache 2.0 — see LICENSE and NOTICE. See README.md for an overview and build instructions, CONTRIBUTING.md for how to contribute, and DEPLOYMENTS.md for the field-deployment log.
This commit is contained in:
+327
@@ -0,0 +1,327 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright (c) 2012-2024 Scott Penrose <scottp@dd.com.au> and WII5 Buoy contributors
|
||||
//
|
||||
// This file is part of WII5 Buoy firmware.
|
||||
// See LICENSE for full terms.
|
||||
|
||||
/**
|
||||
* @file WII5Sh3dIO.cpp
|
||||
* @brief I/O abstraction: buttons, LEDs, and the IO loop tick.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
TODO 2024 - Check this is only valid IO for Buttons and LEDs
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h> //assumes Arduino IDE v1.0 or greater
|
||||
#include "WII5Sh3dIO.h"
|
||||
#include "WII5Sh3dConsole.h"
|
||||
#include <PushButton.h> // Include the PushButton library
|
||||
#include <elapsedMillis.h>
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
||||
*/
|
||||
|
||||
// TODO Can we use NUM_PINS
|
||||
#define LED_MAX 100
|
||||
#define BUTTON_MAX 100
|
||||
|
||||
void WII5Sh3dIO::begin(uint8_t led1, uint8_t led2, uint8_t btn1, uint8_t btn2) {
|
||||
begin(led1, led2, 0, 0, btn1, btn2, 0, 0);
|
||||
}
|
||||
|
||||
// Quick method to save buttons before begin
|
||||
void WII5Sh3dIO::preButton(PushButton* btn1, PushButton* btn2, PushButton* btn3, PushButton* btn4) {
|
||||
button1 = btn1;
|
||||
button2 = btn2;
|
||||
button3 = btn3;
|
||||
button4 = btn4;
|
||||
}
|
||||
|
||||
void WII5Sh3dIO::begin(uint8_t led1, uint8_t led2, uint8_t led3, uint8_t led4, uint8_t btn1, uint8_t btn2, uint8_t btn3, uint8_t btn4) {
|
||||
console.log(LOG_DEBUG, F("LEDS: %d,%d,%d,%d BUTTONS: %d,%d,%d,%d"), int(led1), int(led2), int(led3), int(led4), int(btn1), int(btn2), int(btn3), int(btn4));
|
||||
if (_begin)
|
||||
return;
|
||||
_begin = true;
|
||||
|
||||
if (led1 > 0 && led1 < LED_MAX) {
|
||||
led1_pin = led1;
|
||||
pinMode(led1_pin, OUTPUT);
|
||||
}
|
||||
if (led2 > 0 && led2 < LED_MAX) {
|
||||
led2_pin = led2;
|
||||
pinMode(led2_pin, OUTPUT);
|
||||
}
|
||||
if (led3 > 0 && led3 < LED_MAX) {
|
||||
led3_pin = led2;
|
||||
pinMode(led3_pin, OUTPUT);
|
||||
}
|
||||
if (led4 > 0 && led4 < LED_MAX) {
|
||||
led4_pin = led2;
|
||||
pinMode(led4_pin, OUTPUT);
|
||||
}
|
||||
|
||||
if (btn1 > 0 && btn1 < BUTTON_MAX) {
|
||||
pinMode(btn1, INPUT_PULLUP);
|
||||
if (!button1)
|
||||
button1 = new PushButton(btn1);
|
||||
button1_pin = btn1;
|
||||
// TODO
|
||||
button1_activelow = true;
|
||||
button1->setActiveLogic(LOW);
|
||||
}
|
||||
|
||||
if (btn2 > 0 && btn2 < BUTTON_MAX) {
|
||||
pinMode(btn2, INPUT_PULLUP);
|
||||
if (!button2)
|
||||
button2 = new PushButton(btn2);
|
||||
button2->setActiveLogic(LOW);
|
||||
button2_pin = btn2;
|
||||
button2_activelow = true;
|
||||
}
|
||||
|
||||
if (btn3 > 0 && btn3 < BUTTON_MAX) {
|
||||
pinMode(btn3, INPUT_PULLUP);
|
||||
if (!button3)
|
||||
button3 = new PushButton(btn3);
|
||||
button3_pin = btn3;
|
||||
button3_activelow = true;
|
||||
button3->setActiveLogic(LOW);
|
||||
}
|
||||
|
||||
if (btn4 > 0 && btn4 < BUTTON_MAX) {
|
||||
pinMode(btn4, INPUT_PULLUP);
|
||||
if (!button4)
|
||||
button4 = new PushButton(btn4);
|
||||
button4_pin = btn4;
|
||||
button4_activelow = true;
|
||||
button4->setActiveLogic(LOW);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void WII5Sh3dIO::loop() {
|
||||
if (lastLedLoop > 100) {
|
||||
if (led1_pin > 0) {
|
||||
// Max time and not default mode
|
||||
if ((led1_max > 0) && (led1_mode != led1_default) && (led1_timeon > led1_max))
|
||||
led1Set(led1_default);
|
||||
if (!updateLED(led1_pin, led1_mode, led1_state)) {
|
||||
led1Set(led1_default);
|
||||
}
|
||||
led1_state++;
|
||||
}
|
||||
if (led2_pin > 0) {
|
||||
if ((led2_max > 0) && (led2_mode != led2_default) && (led2_timeon > led2_max))
|
||||
led2Set(led2_default);
|
||||
if (!updateLED(led2_pin, led2_mode, led2_state)) {
|
||||
led2Set(led2_default);
|
||||
}
|
||||
led2_state++;
|
||||
}
|
||||
if (led3_pin > 0) {
|
||||
if ((led3_max > 0) && (led3_mode != led3_default) && (led3_timeon > led3_max))
|
||||
led3Set(led3_default);
|
||||
if (!updateLED(led3_pin, led3_mode, led3_state)) {
|
||||
led3Set(led3_default);
|
||||
}
|
||||
led3_state++;
|
||||
}
|
||||
if (led4_pin > 0) {
|
||||
if ((led4_max > 0) && (led4_mode != led4_default) && (led4_timeon > led4_max))
|
||||
led4Set(led4_default);
|
||||
if (!updateLED(led4_pin, led4_mode, led4_state)) {
|
||||
led4Set(led4_default);
|
||||
}
|
||||
led4_state++;
|
||||
}
|
||||
lastLedLoop = 0;
|
||||
}
|
||||
|
||||
if (button1)
|
||||
button1->update();
|
||||
if (button2)
|
||||
button2->update();
|
||||
if (button3)
|
||||
button3->update();
|
||||
if (button4)
|
||||
button4->update();
|
||||
}
|
||||
|
||||
// Return 0 - nothing, or button number, 1,2,3
|
||||
// TODO - Improve the performance of this to be tiny, so it does not have to be run every singel 8 seconds
|
||||
uint8_t WII5Sh3dIO::buttonSleepCheck() {
|
||||
if (button1) {
|
||||
// pinMode(button1_pin, button1_activelow ? INPUT_PULLUP : INPUT);
|
||||
if (digitalRead(button1_pin) == (button1_activelow ? LOW : HIGH)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (button2) {
|
||||
// pinMode(button2_pin, button2_activelow ? INPUT_PULLUP : INPUT);
|
||||
if (digitalRead(button2_pin) == (button2_activelow ? LOW : HIGH)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO - Consider adding automatic getting Temperature at timed internval (except for blocking issue)
|
||||
// TODO - Consider adding ability to read ALL sensors, not just one
|
||||
|
||||
void WII5Sh3dIO::sleep() {
|
||||
// TODO - Toun off 18B20
|
||||
// TODO - Turn off GPS
|
||||
// TODO - Turn off LED (which may mean make them float/pull high)
|
||||
|
||||
// TODO - Make sure the LEDs are actually off
|
||||
// digitalWrite(LED1, HIGH);
|
||||
// digitalWrite(LED2, HIGH);
|
||||
}
|
||||
|
||||
void WII5Sh3dIO::wake() {
|
||||
}
|
||||
|
||||
#define inverted false
|
||||
|
||||
// Called once per 100ms
|
||||
bool WII5Sh3dIO::updateLED(uint8_t pin, uint8_t mode, uint8_t state) {
|
||||
// console.log(LOG_INFO, F("Updating LED %d, %d, %d"), pin, mode, state);
|
||||
switch (mode) {
|
||||
case LED_OFF: // Off
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_ON: // On
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
break;
|
||||
case LED_SLOW: // Slow
|
||||
if ((state % 4) == 0)
|
||||
digitalWrite(pin, !digitalRead(pin));
|
||||
break;
|
||||
case LED_FAST: // Fast
|
||||
if ((state % 2) == 0)
|
||||
digitalWrite(pin, !digitalRead(pin));
|
||||
break;
|
||||
case LED_SHORT: // Short - on for a short period
|
||||
if ((state % 6) == 0)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_DOUBLE: // Double - 2 short, long off
|
||||
if ( ((state % 8) == 0) || ((state % 8) == 2) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_TRIPPLE: // Trpple - 3 short, long off
|
||||
if ( ((state % 12) == 0) || ((state % 12) == 2) || ((state % 12) == 4) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_SHORT_LONG: // Long - very slow long on and off
|
||||
if ((state % 12) == 0)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_DOUBLE_LONG:
|
||||
if ( ((state % 16) == 0) || ((state % 16) == 2) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_TRIPPLE_LONG:
|
||||
if ( ((state % 20) == 0) || ((state % 20) == 2) || ((state % 20) == 4) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
|
||||
case LED_SHORT_GAP: // Long - very slow long on and off
|
||||
if ((state % 12) == 0)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_DOUBLE_GAP:
|
||||
if ( ((state % 48) == 0) || ((state % 48) == 2) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_TRIPPLE_GAP:
|
||||
if ( ((state % 50) == 0) || ((state % 50) == 2) || ((state % 50) == 4) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
|
||||
case LED_ONE:
|
||||
if ((state % 12) == 0)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_TWO:
|
||||
if ( ((state % 16) == 0) || ((state % 16) == 2) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_THREE:
|
||||
if ( ((state % 20) == 0) || ((state % 20) == 2) || ((state % 20) == 4) )
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
break;
|
||||
case LED_FOUR:
|
||||
// TODO Simplify
|
||||
break;
|
||||
case LED_FIVE:
|
||||
break;
|
||||
case LED_SIX:
|
||||
break;
|
||||
case LED_SEVEN:
|
||||
break;
|
||||
case LED_EIGHT:
|
||||
break;
|
||||
case LED_NINE:
|
||||
break;
|
||||
case LED_TEN:
|
||||
break;
|
||||
case LED_ONCE:
|
||||
if (state < 10)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else if (state < 20)
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
// TODO seemed to be just one long beep
|
||||
case LED_TWICE:
|
||||
if (state < 10)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else if (state < 20)
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
else if (state < 30)
|
||||
digitalWrite(pin, inverted ? LOW : HIGH);
|
||||
else if (state < 40)
|
||||
digitalWrite(pin, inverted ? HIGH : LOW);
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WII5Sh3dIO sh3dNodeIO;
|
||||
Reference in New Issue
Block a user