aboutsummaryrefslogtreecommitdiff
path: root/vote/vote.ino
blob: cc17e79b34b0b3cbce4fddd4852d6968d6c4968a (plain)
  1. // SPDX-FileCopyrightText: 2025 Amal Mazrah <mazrah@ruc.dk>
  2. // SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
  3. // SPDX-FileCopyrightText: 2025 Mennatullah Hatim Kassim <stud-mennatulla@ruc.dk>
  4. // SPDX-FileCopyrightText: 2025 Noor Ahmad <noora@ruc.dk>
  5. // SPDX-FileCopyrightText: 2025 Tanishka Suwalka <tanishkas@ruc.dk>
  6. // SPDX-License-Identifier: GPL-3.0-or-later
  7. /// Mussel vote - an Arduino sketch to monitor mussel biosensors
  8. ///
  9. /// @version 0.0.3
  10. /// @see <https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z2tFBF4gN7ziG9oXtUytVQNYe3VhQ>
  11. /// @see <https://moodle.ruc.dk/course/view.php?id=23504>
  12. // arduino-esp32 Logging system
  13. // activate in Arduino IDE: Tools -> Core Debug Level
  14. // special: set Core Debug Level to Error for plot-friendly output
  15. #define CONFIG_ARDUHAL_ESP_LOG 1
  16. #define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
  17. #include <esp32-hal-log.h>
  18. #undef ARDUHAL_LOG_FORMAT
  19. #define ARDUHAL_LOG_FORMAT(letter, format) \
  20. ARDUHAL_LOG_COLOR_##letter "[" #letter "] %s(): " format \
  21. ARDUHAL_LOG_RESET_COLOR "\r\n", __FUNCTION__
  22. // arduino-esp32 Bluetooth Low Energy (BLE) networking stack
  23. #include <BLEDevice.h>
  24. #include <BLEScan.h>
  25. #include <BLEAdvertisedDevice.h>
  26. #include <BLEEddystoneTLM.h>
  27. #include <BLEBeacon.h>
  28. #define MUSSEL_VOTE_TIME_AHEAD 60000U // 1 minute
  29. #define MUSSEL_VOTE_TIME_BEHIND 120000U // 2 minutes
  30. // Limited size NOW!! can be transformed into infinite array
  31. #define STACK_SIZE 1000
  32. struct Vote {
  33. String id;
  34. unsigned long timestamp;
  35. int measure;
  36. };
  37. bool push(String id, unsigned long timestamp, int measure);
  38. void printStack();
  39. bool qualifyVote(Vote vote, unsigned long currentTime);
  40. int _attitude;
  41. int _pin;
  42. bool _boolState;
  43. byte _count;
  44. unsigned long _time;
  45. // Array to store ID strings
  46. String idStack[STACK_SIZE];
  47. unsigned long timeStack[STACK_SIZE];
  48. int measureStack[STACK_SIZE];
  49. // Index of the top element in the stack, -1 means stack is empty
  50. int top = -1;
  51. int scanTime = 1; //In seconds
  52. // pointer to control Bluetooth networking
  53. BLEScan *pBLEScan;
  54. // Bluetooth beacon discovery callbacks
  55. class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  56. // decode name and temperature from Eddystone TLM advertisement
  57. void onResult(BLEAdvertisedDevice advertisedDevice) {
  58. if (advertisedDevice.haveName()
  59. && advertisedDevice.getFrameType() == BLE_EDDYSTONE_TLM_FRAME
  60. ) {
  61. BLEEddystoneTLM EddystoneTLM(&advertisedDevice);
  62. push(
  63. advertisedDevice.getName(),
  64. millis(),
  65. EddystoneTLM.getTemp()
  66. );
  67. }
  68. }
  69. };
  70. /// Function to push data onto the stack
  71. bool push(String id, unsigned long timestamp, int measure) {
  72. // Check if stack is full
  73. if (top >= STACK_SIZE - 1) {
  74. Serial.println("Stack Full");
  75. // Return false if stack is full
  76. return false;
  77. }
  78. top++;
  79. idStack[top] = id;
  80. timeStack[top] = timestamp;
  81. measureStack[top] = measure;
  82. // Return true on successful push
  83. return true;
  84. }
  85. /// Function to print stack contents
  86. void printStack() {
  87. for (int i = top; i >= 0; i--) {
  88. Serial.print("ID: "); Serial.print(idStack[i]);
  89. Serial.print(", Time: "); Serial.print(timeStack[i]);
  90. Serial.print(", measure: "); Serial.println(measureStack[i]);
  91. }
  92. }
  93. bool qualifyVote(Vote vote, unsigned long currentTime) {
  94. // If the measure is 42 (YES), check timestamp validity
  95. if (vote.measure == 42) {
  96. // If the vote's timestamp is within 1 minute, count it as YES
  97. if (currentTime - vote.timestamp <= MUSSEL_VOTE_TIME_AHEAD) {
  98. return true;
  99. }
  100. // If the vote's timestamp is older than 2 minutes, count it as NO
  101. else if (currentTime - vote.timestamp > MUSSEL_VOTE_TIME_BEHIND) {
  102. return false;
  103. }
  104. }
  105. // If the measure is 2, always count the vote as NO
  106. if (vote.measure == 2) {
  107. return false;
  108. }
  109. // Default case: vote is invalid if no conditions are met
  110. return false;
  111. }
  112. void setup() {
  113. // enable logging to serial
  114. Serial.begin(115200);
  115. esp_log_level_set("*", ESP_LOG_DEBUG);
  116. // setup Bluetooth
  117. BLEDevice::init("");
  118. pBLEScan = BLEDevice::getScan();
  119. pBLEScan->setAdvertisedDeviceCallbacks(
  120. new MyAdvertisedDeviceCallbacks());
  121. pBLEScan->setActiveScan(true);
  122. pBLEScan->setInterval(100);
  123. pBLEScan->setWindow(99);
  124. }
  125. void loop() {
  126. BLEScanResults *foundDevices = pBLEScan->start(scanTime, false);
  127. pBLEScan->clearResults();
  128. // misuse error-only log level for plot-friendly output
  129. #if ARDUHAL_LOG_LEVEL == ARDUHAL_LOG_LEVEL_ERROR
  130. Serial.printf("pin:%d boolState:%d time:%d count:%d\n",
  131. _pin, _boolState, _time, _count);
  132. #endif
  133. delay(500);
  134. }