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