main.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include <Arduino.h> // needed for PlatformIO
  2. #include <Mesh.h>
  3. #include "MyMesh.h"
  4. #include <helpers/ArchiveStorage.h>
  5. #ifdef DISPLAY_CLASS
  6. #include "UITask.h"
  7. static UITask ui_task(display);
  8. #endif
  9. StdRNG fast_rng;
  10. SimpleMeshTables tables;
  11. ArchiveStorage archive;
  12. MyMesh the_mesh(board, radio_driver, *new ArduinoMillis(), fast_rng, rtc_clock, tables);
  13. void halt() {
  14. while (1) ;
  15. }
  16. static char command[160];
  17. // For power saving
  18. unsigned long lastActive = 0; // mark last active time
  19. unsigned long nextSleepinSecs = 120; // next sleep in seconds. The first sleep (if enabled) is after 2 minutes from boot
  20. #if defined(PIN_USER_BTN) && defined(_SEEED_SENSECAP_SOLAR_H_)
  21. static unsigned long userBtnDownAt = 0;
  22. #define USER_BTN_HOLD_OFF_MILLIS 1500
  23. #endif
  24. void setup() {
  25. Serial.begin(115200);
  26. delay(1000);
  27. board.begin();
  28. archive.begin();
  29. #if defined(MESH_DEBUG) && defined(NRF52_PLATFORM)
  30. // give some extra time for serial to settle so
  31. // boot debug messages can be seen on terminal
  32. delay(5000);
  33. #endif
  34. // For power saving
  35. lastActive = millis(); // mark last active time since boot
  36. #ifdef DISPLAY_CLASS
  37. if (display.begin()) {
  38. display.startFrame();
  39. display.setCursor(0, 0);
  40. display.print("Please wait...");
  41. display.endFrame();
  42. }
  43. #endif
  44. if (!radio_init()) {
  45. MESH_DEBUG_PRINTLN("Radio init failed!");
  46. halt();
  47. }
  48. fast_rng.begin(radio_get_rng_seed());
  49. FILESYSTEM* fs;
  50. #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
  51. InternalFS.begin();
  52. fs = &InternalFS;
  53. IdentityStore store(InternalFS, "");
  54. #elif defined(ESP32)
  55. SPIFFS.begin(true);
  56. fs = &SPIFFS;
  57. IdentityStore store(SPIFFS, "/identity");
  58. #elif defined(RP2040_PLATFORM)
  59. LittleFS.begin();
  60. fs = &LittleFS;
  61. IdentityStore store(LittleFS, "/identity");
  62. store.begin();
  63. #else
  64. #error "need to define filesystem"
  65. #endif
  66. if (!store.load("_main", the_mesh.self_id)) {
  67. MESH_DEBUG_PRINTLN("Generating new keypair");
  68. the_mesh.self_id = radio_new_identity(); // create new random identity
  69. int count = 0;
  70. while (count < 10 && (the_mesh.self_id.pub_key[0] == 0x00 || the_mesh.self_id.pub_key[0] == 0xFF)) { // reserved id hashes
  71. the_mesh.self_id = radio_new_identity(); count++;
  72. }
  73. store.save("_main", the_mesh.self_id);
  74. }
  75. Serial.print("Repeater ID: ");
  76. mesh::Utils::printHex(Serial, the_mesh.self_id.pub_key, PUB_KEY_SIZE); Serial.println();
  77. command[0] = 0;
  78. sensors.begin();
  79. the_mesh.begin(fs, &archive);
  80. #ifdef DISPLAY_CLASS
  81. ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
  82. #endif
  83. // send out initial zero hop Advertisement to the mesh
  84. #if ENABLE_ADVERT_ON_BOOT == 1
  85. the_mesh.sendSelfAdvertisement(16000, false);
  86. #endif
  87. }
  88. void loop() {
  89. #if defined(TBEAM_1W)
  90. board.updateFanControl();
  91. #endif
  92. int len = strlen(command);
  93. while (Serial.available() && len < sizeof(command)-1) {
  94. char c = Serial.read();
  95. if (c != '\n') {
  96. command[len++] = c;
  97. command[len] = 0;
  98. Serial.print(c);
  99. }
  100. if (c == '\r') break;
  101. }
  102. if (len == sizeof(command)-1) { // command buffer full
  103. command[sizeof(command)-1] = '\r';
  104. }
  105. if (len > 0 && command[len - 1] == '\r') { // received complete line
  106. Serial.print('\n');
  107. command[len - 1] = 0; // replace newline with C string null terminator
  108. char reply[160];
  109. the_mesh.handleCommand(0, command, reply); // NOTE: there is no sender_timestamp via serial!
  110. if (reply[0]) {
  111. Serial.print(" -> "); Serial.println(reply);
  112. }
  113. command[0] = 0; // reset command buffer
  114. }
  115. #if defined(PIN_USER_BTN) && defined(_SEEED_SENSECAP_SOLAR_H_)
  116. // Hold the user button to power off the SenseCAP Solar repeater.
  117. int btnState = digitalRead(PIN_USER_BTN);
  118. if (btnState == LOW) {
  119. if (userBtnDownAt == 0) {
  120. userBtnDownAt = millis();
  121. } else if ((unsigned long)(millis() - userBtnDownAt) >= USER_BTN_HOLD_OFF_MILLIS) {
  122. Serial.println("Powering off...");
  123. board.powerOff(); // does not return
  124. }
  125. } else {
  126. userBtnDownAt = 0;
  127. }
  128. #endif
  129. the_mesh.loop();
  130. sensors.loop();
  131. #ifdef DISPLAY_CLASS
  132. ui_task.loop();
  133. #endif
  134. rtc_clock.tick();
  135. if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
  136. #if defined(NRF52_PLATFORM)
  137. board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible
  138. #else
  139. if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep
  140. board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet
  141. lastActive = millis();
  142. nextSleepinSecs = 5; // Default: To work for 5s and sleep again
  143. } else {
  144. nextSleepinSecs += 5; // When there is pending work, to work another 5s
  145. }
  146. #endif
  147. }
  148. }