target.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #include <Arduino.h>
  2. #include "target.h"
  3. #include <helpers/ArduinoHelpers.h>
  4. #include <helpers/sensors/MicroNMEALocationProvider.h>
  5. RAK4631Board board;
  6. RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
  7. WRAPPER_CLASS radio_driver(radio, board);
  8. VolatileRTCClock fallback_clock;
  9. AutoDiscoverRTCClock rtc_clock(fallback_clock);
  10. #if ENV_INCLUDE_GPS
  11. MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Wire);
  12. RAK4631SensorManager sensors = RAK4631SensorManager(nmea);
  13. #else
  14. RAK4631SensorManager sensors;
  15. #endif
  16. #if ENV_INCLUDE_BME680
  17. #ifndef TELEM_BME680_ADDRESS
  18. #define TELEM_BME680_ADDRESS 0x76 // BME680 environmental sensor I2C address
  19. #endif
  20. #include <bsec2.h>
  21. static Bsec2 BME680;
  22. static float rawPressure = 0;
  23. static float rawTemperature = 0;
  24. static float compTemperature = 0;
  25. static float rawHumidity = 0;
  26. static float compHumidity = 0;
  27. static float readIAQ = 0;
  28. static float readStaticIAQ = 0;
  29. static float readCO2 = 0;
  30. #endif
  31. #ifdef DISPLAY_CLASS
  32. DISPLAY_CLASS display;
  33. #endif
  34. #ifdef MESH_DEBUG
  35. uint32_t deviceOnline = 0x00;
  36. static void scanDevices(TwoWire *w)
  37. {
  38. uint8_t err, addr;
  39. int nDevices = 0;
  40. uint32_t start = 0;
  41. Serial.println("Scanning I2C for Devices");
  42. for (addr = 1; addr < 127; addr++) {
  43. start = millis();
  44. w->beginTransmission(addr); delay(2);
  45. err = w->endTransmission();
  46. if (err == 0) {
  47. nDevices++;
  48. switch (addr) {
  49. case 0x42:
  50. Serial.println("\tFound RAK12500 GPS Sensor");
  51. deviceOnline |= RAK12500_ONLINE;
  52. break;
  53. case 0x76:
  54. Serial.println("\tFound RAK1906 Environment Sensor");
  55. deviceOnline |= BME680_ONLINE;
  56. break;
  57. default:
  58. Serial.print("\tI2C device found at address 0x");
  59. if (addr < 16) {
  60. Serial.print("0");
  61. }
  62. Serial.print(addr, HEX);
  63. Serial.println(" !");
  64. break;
  65. }
  66. } else if (err == 4) {
  67. Serial.print("Unknow error at address 0x");
  68. if (addr < 16) {
  69. Serial.print("0");
  70. }
  71. Serial.println(addr, HEX);
  72. }
  73. }
  74. if (nDevices == 0)
  75. Serial.println("No I2C devices found\n");
  76. Serial.println("Scan for devices is complete.");
  77. Serial.println("\n");
  78. }
  79. #endif
  80. bool radio_init() {
  81. rtc_clock.begin(Wire);
  82. return radio.std_init(&SPI);
  83. }
  84. uint32_t radio_get_rng_seed() {
  85. return radio.random(0x7FFFFFFF);
  86. }
  87. void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
  88. radio.setFrequency(freq);
  89. radio.setSpreadingFactor(sf);
  90. radio.setBandwidth(bw);
  91. radio.setCodingRate(cr);
  92. }
  93. void radio_set_tx_power(uint8_t dbm) {
  94. radio.setOutputPower(dbm);
  95. }
  96. #if ENV_INCLUDE_GPS
  97. void RAK4631SensorManager::start_gps()
  98. {
  99. //function currently not used
  100. gps_active = true;
  101. pinMode(disStandbyPin, OUTPUT);
  102. digitalWrite(disStandbyPin, 1);
  103. MESH_DEBUG_PRINTLN("GPS should be on now");
  104. }
  105. void RAK4631SensorManager::stop_gps()
  106. {
  107. //function currently not used
  108. gps_active = false;
  109. pinMode(disStandbyPin, OUTPUT);
  110. digitalWrite(disStandbyPin, 0);
  111. MESH_DEBUG_PRINTLN("GPS should be off now");
  112. }
  113. void RAK4631SensorManager::sleep_gps() {
  114. gps_active = false;
  115. ublox_GNSS.powerSaveMode();
  116. MESH_DEBUG_PRINTLN("GPS should be sleeping now");
  117. }
  118. void RAK4631SensorManager::wake_gps() {
  119. gps_active = true;
  120. ublox_GNSS.powerSaveMode(false);
  121. MESH_DEBUG_PRINTLN("GPS should be waking now");
  122. }
  123. bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
  124. int pinInitialState = 0;
  125. //set initial waking state
  126. pinMode(ioPin,OUTPUT);
  127. digitalWrite(ioPin,0);
  128. delay(1000);
  129. digitalWrite(ioPin,1);
  130. delay(1000);
  131. if (ublox_GNSS.begin(Wire) == true){
  132. MESH_DEBUG_PRINTLN("GPS init correctly and GPS is turned on");
  133. ublox_GNSS.setI2COutput(COM_TYPE_NMEA);
  134. ublox_GNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);
  135. disStandbyPin = ioPin;
  136. gps_active = true;
  137. gps_detected = true;
  138. return true;
  139. }
  140. else
  141. MESH_DEBUG_PRINTLN("GPS failed to init on this IO pin... try the next");
  142. //digitalWrite(ioPin,pinInitialState); //reset the IO pin to initial state
  143. return false;
  144. }
  145. #endif
  146. #if ENV_INCLUDE_BME680
  147. static void checkBMEStatus(Bsec2 bsec) {
  148. if (bsec.status < BSEC_OK)
  149. {
  150. MESH_DEBUG_PRINTLN("BSEC error code : %f", float(bsec.status));
  151. }
  152. else if (bsec.status > BSEC_OK)
  153. {
  154. MESH_DEBUG_PRINTLN("BSEC warning code : %f", float(bsec.status));
  155. }
  156. if (bsec.sensor.status < BME68X_OK)
  157. {
  158. MESH_DEBUG_PRINTLN("BME68X error code : %f", bsec.sensor.status);
  159. }
  160. else if (bsec.sensor.status > BME68X_OK)
  161. {
  162. MESH_DEBUG_PRINTLN("BME68X warning code : %f", bsec.sensor.status);
  163. }
  164. }
  165. static void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) {
  166. if (!outputs.nOutputs) {
  167. MESH_DEBUG_PRINTLN("No new data to report out");
  168. return;
  169. }
  170. MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", (int) (outputs.output[0].time_stamp / INT64_C(1000000)));
  171. for (uint8_t i = 0; i < outputs.nOutputs; i++) {
  172. const bsecData output = outputs.output[i];
  173. switch (output.sensor_id)
  174. {
  175. case BSEC_OUTPUT_IAQ:
  176. readIAQ = output.signal;
  177. MESH_DEBUG_PRINTLN("\tIAQ = %f", output.signal);
  178. MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", output.accuracy);
  179. break;
  180. case BSEC_OUTPUT_RAW_TEMPERATURE:
  181. rawTemperature = output.signal;
  182. MESH_DEBUG_PRINTLN("\tTemperature = %f", output.signal);
  183. break;
  184. case BSEC_OUTPUT_RAW_PRESSURE:
  185. rawPressure = output.signal;
  186. MESH_DEBUG_PRINTLN("\tPressure = %f", output.signal);
  187. break;
  188. case BSEC_OUTPUT_RAW_HUMIDITY:
  189. rawHumidity = output.signal;
  190. MESH_DEBUG_PRINTLN("\tHumidity = %f", output.signal);
  191. break;
  192. case BSEC_OUTPUT_RAW_GAS:
  193. MESH_DEBUG_PRINTLN("\tGas resistance = %f", output.signal);
  194. break;
  195. case BSEC_OUTPUT_STABILIZATION_STATUS:
  196. MESH_DEBUG_PRINTLN("\tStabilization status = %f", output.signal);
  197. break;
  198. case BSEC_OUTPUT_RUN_IN_STATUS:
  199. MESH_DEBUG_PRINTLN("\tRun in status = %f", output.signal);
  200. break;
  201. case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
  202. compTemperature = output.signal;
  203. MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", output.signal);
  204. break;
  205. case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
  206. compHumidity = output.signal;
  207. MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", output.signal);
  208. break;
  209. case BSEC_OUTPUT_STATIC_IAQ:
  210. readStaticIAQ = output.signal;
  211. MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", output.signal);
  212. break;
  213. case BSEC_OUTPUT_CO2_EQUIVALENT:
  214. readCO2 = output.signal;
  215. MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", output.signal);
  216. break;
  217. case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
  218. MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", output.signal);
  219. break;
  220. case BSEC_OUTPUT_GAS_PERCENTAGE:
  221. MESH_DEBUG_PRINTLN("\tGas percentage = %f", output.signal);
  222. break;
  223. case BSEC_OUTPUT_COMPENSATED_GAS:
  224. MESH_DEBUG_PRINTLN("\tCompensated gas = %f", output.signal);
  225. break;
  226. default:
  227. break;
  228. }
  229. }
  230. }
  231. #endif
  232. bool RAK4631SensorManager::begin() {
  233. #ifdef MESH_DEBUG
  234. scanDevices(&Wire);
  235. #endif
  236. #if ENV_INCLUDE_GPS
  237. //search for the correct IO standby pin depending on socket used
  238. if(gpsIsAwake(P_GPS_STANDBY_A)){
  239. MESH_DEBUG_PRINTLN("GPS is on socket A");
  240. }
  241. else if(gpsIsAwake(P_GPS_STANDBY_C)){
  242. MESH_DEBUG_PRINTLN("GPS is on socket C");
  243. }
  244. else if(gpsIsAwake(P_GPS_STANDBY_F)){
  245. MESH_DEBUG_PRINTLN("GPS is on socket F");
  246. }
  247. else{
  248. MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F");
  249. gps_active = false;
  250. gps_detected = false;
  251. return false;
  252. }
  253. #ifndef FORCE_GPS_ALIVE
  254. //Now that GPS is found and set up, set to sleep for initial state
  255. stop_gps();
  256. #endif
  257. #endif
  258. #if ENV_INCLUDE_BME680
  259. bsecSensor sensorList[5] = {
  260. BSEC_OUTPUT_IAQ,
  261. // BSEC_OUTPUT_RAW_TEMPERATURE,
  262. BSEC_OUTPUT_RAW_PRESSURE,
  263. // BSEC_OUTPUT_RAW_HUMIDITY,
  264. // BSEC_OUTPUT_RAW_GAS,
  265. // BSEC_OUTPUT_STABILIZATION_STATUS,
  266. // BSEC_OUTPUT_RUN_IN_STATUS,
  267. BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
  268. BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
  269. BSEC_OUTPUT_STATIC_IAQ,
  270. // BSEC_OUTPUT_CO2_EQUIVALENT,
  271. // BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
  272. // BSEC_OUTPUT_GAS_PERCENTAGE,
  273. // BSEC_OUTPUT_COMPENSATED_GAS
  274. };
  275. if(!BME680.begin(TELEM_BME680_ADDRESS, Wire)){
  276. checkBMEStatus(BME680);
  277. bme680_present = false;
  278. bme680_active = false;
  279. return false;
  280. }
  281. MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS);
  282. bme680_present = true;
  283. bme680_active = true;
  284. if (SAMPLING_RATE == BSEC_SAMPLE_RATE_ULP)
  285. {
  286. BME680.setTemperatureOffset(BSEC_SAMPLE_RATE_ULP);
  287. }
  288. else if (SAMPLING_RATE == BSEC_SAMPLE_RATE_LP)
  289. {
  290. BME680.setTemperatureOffset(TEMP_OFFSET_LP);
  291. }
  292. if (!BME680.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLING_RATE))
  293. {
  294. checkBMEStatus(BME680);
  295. }
  296. BME680.attachCallback(newDataCallback);
  297. #endif
  298. }
  299. bool RAK4631SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
  300. #ifdef ENV_INCLUDE_GPS
  301. if (requester_permissions & TELEM_PERM_LOCATION && gps_active) { // does requester have permission?
  302. telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
  303. }
  304. #endif
  305. if (requester_permissions & TELEM_PERM_ENVIRONMENT) {
  306. #if ENV_INCLUDE_BME680
  307. if (bme680_active) {
  308. telemetry.addTemperature(TELEM_CHANNEL_SELF, compTemperature);
  309. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, compHumidity);
  310. telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, rawPressure);
  311. telemetry.addTemperature(TELEM_CHANNEL_SELF+1, readIAQ);
  312. telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readStaticIAQ);
  313. }
  314. #endif
  315. }
  316. return true;
  317. }
  318. void RAK4631SensorManager::loop() {
  319. static long next_update = 0;
  320. #ifdef ENV_INCLUDE_GPS
  321. _nmea->loop();
  322. #endif
  323. if (millis() > next_update) {
  324. #ifdef ENV_INCLUDE_GPS
  325. if(gps_active){
  326. node_lat = (double)ublox_GNSS.getLatitude()/10000000.;
  327. node_lon = (double)ublox_GNSS.getLongitude()/10000000.;
  328. node_altitude = (double)ublox_GNSS.getAltitude()/1000.;
  329. MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
  330. }
  331. #endif
  332. #ifdef ENV_INCLUDE_BME680
  333. if(bme680_active){
  334. if (!BME680.run()){
  335. checkBMEStatus(BME680);
  336. }
  337. }
  338. #endif
  339. next_update = millis() + 1000;
  340. }
  341. }
  342. int RAK4631SensorManager::getNumSettings() const {
  343. #if ENV_INCLUDE_GPS
  344. return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected
  345. #else
  346. return 0;
  347. #endif
  348. }
  349. const char* RAK4631SensorManager::getSettingName(int i) const {
  350. #if ENV_INCLUDE_GPS
  351. return (gps_detected && i == 0) ? "gps" : NULL;
  352. #else
  353. return NULL;
  354. #endif
  355. }
  356. const char* RAK4631SensorManager::getSettingValue(int i) const {
  357. #if ENV_INCLUDE_GPS
  358. if (gps_detected && i == 0) {
  359. return gps_active ? "1" : "0";
  360. }
  361. #endif
  362. return NULL;
  363. }
  364. bool RAK4631SensorManager::setSettingValue(const char* name, const char* value) {
  365. #if ENV_INCLUDE_GPS
  366. if (gps_detected && strcmp(name, "gps") == 0) {
  367. if (strcmp(value, "0") == 0) {
  368. stop_gps();
  369. } else {
  370. start_gps();
  371. }
  372. return true;
  373. }
  374. #endif
  375. return false; // not supported
  376. }
  377. mesh::LocalIdentity radio_new_identity() {
  378. RadioNoiseListener rng(radio);
  379. return mesh::LocalIdentity(&rng); // create new random identity
  380. }