blob: 0bbcb52332bb596a4c32e3160136082776cbacf3 (
plain)
- /// Mussel - a small library for Arduino to emulate a mussel biosensor
- ///
- /// SPDX-FileCopyrightText: 2025 Amal Mazrah <mazrah@ruc.dk>
- /// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
- /// SPDX-FileCopyrightText: 2025 Mennatullah Hatim Kassim <stud-mennatulla@ruc.dk>
- /// SPDX-FileCopyrightText: 2025 Noor Ahmad <noora@ruc.dk>
- /// SPDX-FileCopyrightText: 2025 Tanishka Suwalka <tanishkas@ruc.dk>
- /// SPDX-License-Identifier: GPL-3.0-or-later
- ///
- /// * v0.0.1
- /// * initial release to radicle
- ///
- /// @version 0.0.1
- /// @see <https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z2tFBF4gN7ziG9oXtUytVQNYe3VhQ/tree/Mussel/README.md>
- /// @see <https://moodle.ruc.dk/course/view.php?id=23504>
- #include "Mussel.h"
- #include "Arduino.h"
- /// Main constructor
- ///
- /// @param attitude behavioral profile as integer
- Mussel::Mussel(int attitude) {
- _attitude = attitude;
- }
- /// Constructor for attitudes using a pin
- ///
- /// @param attitude behavioral profile as integer
- /// @param pin Used pin as uint8_t
- Mussel::Mussel(int attitude, uint8_t pin) {
- _attitude = attitude;
- _pin = pin;
- }
- /// Constructor for attitudes using a pin and certain type of sensor
- ///
- /// @param attitude behavioral profile as integer
- /// @param pin Used pin as uint8_t
- /// @param type type of sensor as uint8_t
- Mussel::Mussel(int attitude, uint8_t pin, uint8_t type)
- #ifdef DHT_H
- : mussel_dht(pin, type)
- #endif
- {
- _attitude = attitude;
- _pin = pin;
- }
- /// Setup function
- void Mussel::begin() {
- switch(_attitude) {
- #ifdef DHT_H
- case 3:
- mussel_dht.begin();
- break;
- #endif
- case 4:
- // use INPUT_PULLDOWN to signal when the button is held down
- // (not PULLUP which signals when it is released)
- pinMode(_pin, INPUT_PULLDOWN);
- break;
- case 5:
- _boolState = HIGH;
- _count = 0;
- _time = 0;
- // Enable internal pull-up resistor for button
- pinMode(_pin, INPUT_PULLUP);
- break;
- case 6:
- _boolState = HIGH;
- break;
- }
- }
- /// Description of mussel
- ///
- /// @return name and attitude of mussel as String
- String Mussel::desc() {
- String _str;
- switch(_attitude) {
- case 1:
- _str = "closed 10 seconds every 50 seconds";
- break;
- case 2:
- _str = "closed 4 seconds every 8 seconds";
- break;
- case 3:
- _str = "closed when cold";
- break;
- case 4:
- _str = "closed when button is pushed";
- break;
- case 5:
- _str = "changes state when button is pushed";
- break;
- case 6:
- _str = "changes state on ON/OFF command";
- break;
- default:
- _str = "undefined [" + static_cast<String>(_attitude) + "]";
- break;
- }
- return _str;
- }
- /// Sensor reading
- ///
- /// * Values 0-99 is a measured relative mussel gape size
- /// * Values 100-254 are reserved for future use
- /// * Value 255 is an internal error
- ///
- /// @return relative gape size as value 0-255 encoded as byte
- byte Mussel::read() {
- byte _byte;
- switch(_attitude) {
- case 1:
- // 42 if current second modulo 60 is below 50, else 2
- _byte = static_cast<byte>(
- (static_cast<unsigned long>(millis() / 1000) % 60) < 50
- ? 42
- : 2);
- break;
- case 2:
- // 42 if current second modulo 12 is below 9, else 2
- _byte = static_cast<byte>(
- (static_cast<unsigned long>(millis() / 1000) % 12) < 9
- ? 42
- : 2);
- break;
- case 3:
- #ifdef DHT_H
- // temperature in Celsius
- _byte = static_cast<byte>(
- mussel_dht.readTemperature());
- #else
- _byte = 255;
- #endif
- break;
- case 4:
- // 2 if button is pressed, else 42
- _byte = static_cast<byte>(
- digitalRead(_pin) == HIGH
- ? 2
- : 42);
- break;
- case 5: {
- bool _reading = digitalRead(_pin); // Read button state
- // Debounce logic:
- // Ensures a single press isn't detected multiple times
- if (_reading != _boolState) {
- _time = millis(); // Reset debounce timer
- }
- if ((millis() - _time) > MUSSEL_DEBOUNCE_DELAY) {
- // Check for button press (transition from HIGH to LOW)
- if (_reading == LOW && _boolState == HIGH) {
- _count++; // Increment click count
- if (_count > 3) {
- _count = 0; // Reset cycle after 3 clicks
- }
- switch (_count) {
- case 1: _byte = 2; break; // State: Angry
- case 2: _byte = 42; break; // State: Happy
- case 3: _byte = 15; break; // State: Unsure
- case 0: _byte = 99; break; // State: Off
- }
- }
- }
- _boolState = _reading; // Update button state
- break;
- }
- case 6:
- if (Serial.available() > 0) {
- String command = Serial.readStringUntil('\n');
- command.trim();
- if (command.equalsIgnoreCase("ON")) {
- _boolState = HIGH;
- }
- else if (command.equalsIgnoreCase("OFF")) {
- _boolState = LOW;
- }
- }
- _byte = _boolState == HIGH
- ? 42
- : 2;
- break;
- default:
- _byte = 255;
- break;
- }
- return _byte;
- }
- /// Dump internal variables, formatted for use with Serial Plotter
- ///
- /// @return internal variables as String
- String Mussel::debug() {
- return static_cast<String>(
- "pin:") + _pin
- + "\tboolState:" + _boolState
- + "\ttime:" + _time
- + "\tcount:" + _count;
- }
|