Files
WII5Firmware/WII5Sh3dIO.cpp
T
scottp 295abb37ee 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.
2026-05-07 16:27:18 +10:00

328 lines
8.4 KiB
C++

// 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;