target.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include <Arduino.h>
  2. #include "target.h"
  3. #include <helpers/sensors/MicroNMEALocationProvider.h>
  4. TBeamS3SupremeBoard board;
  5. bool pmuIntFlag;
  6. #ifndef LORA_CR
  7. #define LORA_CR 5
  8. #endif
  9. #if defined(P_LORA_SCLK)
  10. static SPIClass spi;
  11. RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
  12. #else
  13. RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
  14. #endif
  15. WRAPPER_CLASS radio_driver(radio, board);
  16. ESP32RTCClock fallback_clock;
  17. AutoDiscoverRTCClock rtc_clock(fallback_clock);
  18. MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
  19. TbeamSupSensorManager sensors = TbeamSupSensorManager(nmea);
  20. static void setPMUIntFlag(){
  21. pmuIntFlag = true;
  22. }
  23. #ifdef MESH_DEBUG
  24. void TBeamS3SupremeBoard::printPMU()
  25. {
  26. Serial.print("isCharging:"); Serial.println(PMU.isCharging() ? "YES" : "NO");
  27. Serial.print("isDischarge:"); Serial.println(PMU.isDischarge() ? "YES" : "NO");
  28. Serial.print("isVbusIn:"); Serial.println(PMU.isVbusIn() ? "YES" : "NO");
  29. Serial.print("getBattVoltage:"); Serial.print(PMU.getBattVoltage()); Serial.println("mV");
  30. Serial.print("getVbusVoltage:"); Serial.print(PMU.getVbusVoltage()); Serial.println("mV");
  31. Serial.print("getSystemVoltage:"); Serial.print(PMU.getSystemVoltage()); Serial.println("mV");
  32. // The battery percentage may be inaccurate at first use, the PMU will automatically
  33. // learn the battery curve and will automatically calibrate the battery percentage
  34. // after a charge and discharge cycle
  35. if (PMU.isBatteryConnect()) {
  36. Serial.print("getBatteryPercent:"); Serial.print(PMU.getBatteryPercent()); Serial.println("%");
  37. }
  38. Serial.println();
  39. }
  40. #endif
  41. bool TBeamS3SupremeBoard::power_init()
  42. {
  43. bool result = PMU.begin(PMU_WIRE_PORT, I2C_PMU_ADD, PIN_BOARD_SDA1, PIN_BOARD_SCL1);
  44. if (result == false) {
  45. MESH_DEBUG_PRINTLN("power is not online..."); while (1)delay(50);
  46. }
  47. MESH_DEBUG_PRINTLN("Setting charge led");
  48. PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
  49. // Set up PMU interrupts
  50. MESH_DEBUG_PRINTLN("Setting up PMU interrupts");
  51. pinMode(PIN_PMU_IRQ, INPUT_PULLUP);
  52. attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING);
  53. // GPS
  54. MESH_DEBUG_PRINTLN("Setting and enabling a-ldo4 for GPS");
  55. PMU.setALDO4Voltage(3300);
  56. PMU.enableALDO4(); // disable to save power
  57. // Lora
  58. MESH_DEBUG_PRINTLN("Setting and enabling a-ldo3 for LoRa");
  59. PMU.setALDO3Voltage(3300);
  60. PMU.enableALDO3();
  61. // To avoid SPI bus issues during power up, reset OLED, sensor, and SD card supplies
  62. MESH_DEBUG_PRINTLN("Reset a-ldo1&2 and b-ldo1");
  63. if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause())
  64. {
  65. PMU.disableALDO1();
  66. PMU.disableALDO2();
  67. PMU.disableBLDO1();
  68. delay(250);
  69. }
  70. // BME280 and OLED
  71. MESH_DEBUG_PRINTLN("Setting and enabling a-ldo1 for oled");
  72. PMU.setALDO1Voltage(3300);
  73. PMU.enableALDO1();
  74. // QMC6310U
  75. MESH_DEBUG_PRINTLN("Setting and enabling a-ldo2 for QMC");
  76. PMU.setALDO2Voltage(3300);
  77. PMU.enableALDO2(); // disable to save power
  78. // SD card
  79. MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for SD card");
  80. PMU.setBLDO1Voltage(3300);
  81. PMU.enableBLDO1();
  82. // Out to header pins
  83. MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for output to header");
  84. PMU.setBLDO2Voltage(3300);
  85. PMU.enableBLDO2();
  86. MESH_DEBUG_PRINTLN("Setting and enabling dcdc4 for output to header");
  87. PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); // 1.8V
  88. PMU.enableDC4();
  89. MESH_DEBUG_PRINTLN("Setting and enabling dcdc5 for output to header");
  90. PMU.setDC5Voltage(3300);
  91. PMU.enableDC5();
  92. // Other power rails
  93. MESH_DEBUG_PRINTLN("Setting and enabling dcdc3 for ?");
  94. PMU.setDC3Voltage(3300); // doesn't go anywhere in the schematic??
  95. PMU.enableDC3();
  96. // Unused power rails
  97. MESH_DEBUG_PRINTLN("Disabling unused supplies dcdc2, dldo1 and dldo2");
  98. PMU.disableDC2();
  99. PMU.disableDLDO1();
  100. PMU.disableDLDO2();
  101. // Set charge current to 300mA
  102. MESH_DEBUG_PRINTLN("Setting battery charge current limit and voltage");
  103. PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
  104. PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
  105. // enable battery voltage measurement
  106. MESH_DEBUG_PRINTLN("Enabling battery measurement");
  107. PMU.enableBattVoltageMeasure();
  108. // Reset and re-enable PMU interrupts
  109. MESH_DEBUG_PRINTLN("Re-enable interrupts");
  110. PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
  111. PMU.clearIrqStatus();
  112. PMU.enableIRQ(
  113. XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts
  114. XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts
  115. XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts
  116. XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts
  117. );
  118. #ifdef MESH_DEBUG
  119. printPMU();
  120. #endif
  121. // Set the power key off press time
  122. PMU.setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
  123. return true;
  124. }
  125. bool l76kProbe()
  126. {
  127. bool result = false;
  128. uint32_t startTimeout ;
  129. Serial1.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
  130. delay(5);
  131. // Get version information
  132. startTimeout = millis() + 3000;
  133. MESH_DEBUG_PRINTLN("Trying to init L76K GPS");
  134. // Serial1.flush();
  135. while (Serial1.available()) {
  136. int c = Serial1.read();
  137. // Serial.write(c);
  138. // Serial.print(".");
  139. // Serial.flush();
  140. // Serial1.flush();
  141. if (millis() > startTimeout) {
  142. MESH_DEBUG_PRINTLN("L76K NMEA timeout!");
  143. return false;
  144. }
  145. };
  146. Serial.println();
  147. Serial1.flush();
  148. delay(200);
  149. Serial1.write("$PCAS06,0*1B\r\n");
  150. startTimeout = millis() + 500;
  151. String ver = "";
  152. while (!Serial1.available()) {
  153. if (millis() > startTimeout) {
  154. MESH_DEBUG_PRINTLN("Get L76K timeout!");
  155. return false;
  156. }
  157. }
  158. Serial1.setTimeout(10);
  159. ver = Serial1.readStringUntil('\n');
  160. if (ver.startsWith("$GPTXT,01,01,02")) {
  161. MESH_DEBUG_PRINTLN("L76K GNSS init succeeded, using L76K GNSS Module\n");
  162. result = true;
  163. }
  164. delay(500);
  165. // Initialize the L76K Chip, use GPS + GLONASS
  166. Serial1.write("$PCAS04,5*1C\r\n");
  167. delay(250);
  168. // only ask for RMC and GGA
  169. Serial1.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
  170. delay(250);
  171. // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
  172. Serial1.write("$PCAS11,3*1E\r\n");
  173. return result;
  174. }
  175. bool radio_init() {
  176. fallback_clock.begin();
  177. Wire1.begin(PIN_BOARD_SDA1,PIN_BOARD_SCL1);
  178. rtc_clock.begin(Wire1);
  179. #ifdef SX126X_DIO3_TCXO_VOLTAGE
  180. float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
  181. #else
  182. float tcxo = 1.6f;
  183. #endif
  184. #if defined(P_LORA_SCLK)
  185. spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
  186. #endif
  187. int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
  188. if (status != RADIOLIB_ERR_NONE) {
  189. Serial.print("ERROR: radio init failed: ");
  190. Serial.println(status);
  191. return false; // fail
  192. }
  193. radio.setCRC(1);
  194. return true; // success
  195. }
  196. uint32_t radio_get_rng_seed() {
  197. return radio.random(0x7FFFFFFF);
  198. }
  199. void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
  200. radio.setFrequency(freq);
  201. radio.setSpreadingFactor(sf);
  202. radio.setBandwidth(bw);
  203. radio.setCodingRate(cr);
  204. }
  205. void radio_set_tx_power(uint8_t dbm) {
  206. radio.setOutputPower(dbm);
  207. }
  208. void TbeamSupSensorManager::start_gps()
  209. {
  210. gps_active = true;
  211. pinMode(P_GPS_WAKE, OUTPUT);
  212. digitalWrite(P_GPS_WAKE, HIGH);
  213. }
  214. void TbeamSupSensorManager::sleep_gps() {
  215. gps_active = false;
  216. pinMode(P_GPS_WAKE, OUTPUT);
  217. digitalWrite(P_GPS_WAKE, LOW);
  218. }
  219. bool TbeamSupSensorManager::begin() {
  220. // init GPS port
  221. Serial1.begin(GPS_BAUD_RATE, SERIAL_8N1, P_GPS_RX, P_GPS_TX);
  222. bool result = false;
  223. for ( int i = 0; i < 3; ++i) {
  224. result = l76kProbe();
  225. if (result) {
  226. gps_active = true;
  227. return result;
  228. }
  229. }
  230. return result;
  231. }
  232. bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
  233. if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission?
  234. telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f);
  235. }
  236. return true;
  237. }
  238. void TbeamSupSensorManager::loop() {
  239. static long next_gps_update = 0;
  240. _nmea->loop();
  241. if (millis() > next_gps_update) {
  242. if (_nmea->isValid()) {
  243. node_lat = ((double)_nmea->getLatitude())/1000000.;
  244. node_lon = ((double)_nmea->getLongitude())/1000000.;
  245. //Serial.printf("lat %f lon %f\r\n", _lat, _lon);
  246. }
  247. next_gps_update = millis() + 1000;
  248. }
  249. }
  250. int TbeamSupSensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch)
  251. const char* TbeamSupSensorManager::getSettingName(int i) const {
  252. return i == 0 ? "gps" : NULL;
  253. }
  254. const char* TbeamSupSensorManager::getSettingValue(int i) const {
  255. if (i == 0) {
  256. return gps_active ? "1" : "0";
  257. }
  258. return NULL;
  259. }
  260. bool TbeamSupSensorManager::setSettingValue(const char* name, const char* value) {
  261. if (strcmp(name, "gps") == 0) {
  262. if (strcmp(value, "0") == 0) {
  263. sleep_gps();
  264. } else {
  265. start_gps();
  266. }
  267. return true;
  268. }
  269. return false; // not supported
  270. }
  271. mesh::LocalIdentity radio_new_identity() {
  272. RadioNoiseListener rng(radio);
  273. return mesh::LocalIdentity(&rng); // create new random identity
  274. }