diff --git a/.gitignore b/.gitignore index 95b4ce9c50f7cb542044183a97fae1a8fa30915c..c334dbba4bdd1cccf28f837a6a536ed16004fa2a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .vscode .travis.yml BikeBeam.code-workspace -src/config.h +include/config.h diff --git a/include/button.h b/include/button.h new file mode 100644 index 0000000000000000000000000000000000000000..343c3a75d6c7736d6601b0ef97bf08b101c97cc5 --- /dev/null +++ b/include/button.h @@ -0,0 +1,2 @@ +void buttonSetup(); +void buttonLoop(); \ No newline at end of file diff --git a/src/config.h.sample b/include/config.h.sample similarity index 71% rename from src/config.h.sample rename to include/config.h.sample index 2606b700bddd331b4879ff8f7f0b7735546af808..d342c1d9d6a693fe1316ab2dcfd220762fe0e4b9 100644 --- a/src/config.h.sample +++ b/include/config.h.sample @@ -1,4 +1,6 @@ -#define TIME_SLEEP 900 // 15 minutes +#define SLEEP_SECONDS 900 // 15 minutes +#define GPS_INT_SECONDS 1 +#define GPS_WAIT_SECONDS 120 #define TTN_DEVEUI { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; // LSB #define TTN_APPEUI { 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0xD5, 0xB3, 0x70 }; // LSB diff --git a/include/gps.h b/include/gps.h new file mode 100644 index 0000000000000000000000000000000000000000..f391c931fc04eb754caafd0545808b5ea4f0c587 --- /dev/null +++ b/include/gps.h @@ -0,0 +1,6 @@ +#include <TinyGPS++.h> + +void gpsStatus(); +void gpsSetup(); +TinyGPSPlus getGps(); +int gpsCheck(); diff --git a/include/lora.h b/include/lora.h new file mode 100644 index 0000000000000000000000000000000000000000..6547485c8726ea02fca62d5fd81d54a8bf0d76a3 --- /dev/null +++ b/include/lora.h @@ -0,0 +1,5 @@ +#include <CayenneLPP.h> + +void loraSetup(); +void loraLoop(); +int loraSend(CayenneLPP payload); \ No newline at end of file diff --git a/include/power.h b/include/power.h new file mode 100644 index 0000000000000000000000000000000000000000..e5f434c31c1820a59017078faabb4284ef7d7def --- /dev/null +++ b/include/power.h @@ -0,0 +1,8 @@ +#include <axp20x.h> + +void powerLed(axp_chgled_mode_t); +float powerGetBattVoltage(); +void powerSetOutput(uint8_t channel, bool enabled); +void powerStatus(); +void powerSetup(); +void powerSleep(); \ No newline at end of file diff --git a/include/states.h b/include/states.h new file mode 100644 index 0000000000000000000000000000000000000000..253e2f1256e8321a6ca40b8e6445ae0d0f16deb0 --- /dev/null +++ b/include/states.h @@ -0,0 +1,4 @@ +#define STATE_INIT 1 +#define STATE_READY 2 +#define STATE_SENDING 3 +#define STATE_DONE 4 diff --git a/src/button.cpp b/src/button.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf6e407c29ca429479afb07dc9a950a749cc5103 --- /dev/null +++ b/src/button.cpp @@ -0,0 +1,20 @@ +#include <OneButton.h> +#include "power.h" + +OneButton btn = OneButton(GPIO_NUM_38, true, true); + +static void buttonClick() +{ + Serial.println("\nButton pressed, going to sleep."); + powerSleep(); +} + +void buttonSetup() +{ + btn.attachClick(buttonClick); +} + +void buttonLoop() +{ + btn.tick(); +} \ No newline at end of file diff --git a/src/gps.cpp b/src/gps.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d59ca0e0fa7a693d011c973be0c367e3f0baea5 --- /dev/null +++ b/src/gps.cpp @@ -0,0 +1,63 @@ +#include "config.h" +#include "states.h" +#include "power.h" +#include <TinyGPS++.h> + +HardwareSerial GPS(1); +TinyGPSPlus gps; +extern int state; +unsigned long gpsTimer; +unsigned long gpsCount; + +TinyGPSPlus getGps() +{ + while (GPS.available()) + { + gps.encode(GPS.read()); + } + return gps; +} + +void gpsStatus() +{ + gps = getGps(); + Serial.println("\n########## GPS ##########"); + Serial.printf("Latitude : %f\n", gps.location.lat()); + Serial.printf("Longitude : %f\n", gps.location.lng()); + Serial.printf("Satellites : %d\n", gps.satellites.value()); + Serial.printf("Altitude : %g m\n", gps.altitude.meters()); + Serial.printf("Time : %02d:%02d:%02d\n", gps.time.hour(), gps.time.minute(), gps.time.second()); + Serial.printf("Speed : %g\n", gps.speed.kmph()); + Serial.println("#########################\n"); +} + +void gpsSetup() +{ + gpsTimer = millis(); + gpsCount = 0; + GPS.begin(9600, SERIAL_8N1, 34, 12); // IO34: RX, IO12: TX + powerLed(AXP20X_LED_BLINK_1HZ); +} + +void gpsCheck() +{ + if (millis() - gpsTimer >= 1000 * GPS_INT_SECONDS) + { + ++gpsCount; + Serial.printf("Waiting for GPS fix... (%lus)\n", gpsCount * GPS_INT_SECONDS); + gps = getGps(); + if (gps.location.isValid()) + { + Serial.printf("Got GPS fix after %lu seconds.\n", gpsCount * GPS_INT_SECONDS); + gpsStatus(); + powerLed(AXP20X_LED_BLINK_4HZ); + state = STATE_READY; + } + else if (gpsCount * GPS_INT_SECONDS >= GPS_WAIT_SECONDS) + { + Serial.printf("No GPS fix after %d seconds, cancelling.\n", GPS_WAIT_SECONDS); + state = STATE_DONE; + } + gpsTimer = millis(); + } +} \ No newline at end of file diff --git a/src/lora.cpp b/src/lora.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ea3cb0b747ce9ce4bfa585f67f6e36017bb2ab6 --- /dev/null +++ b/src/lora.cpp @@ -0,0 +1,169 @@ +#include "config.h" +#include "states.h" +#include "power.h" +#include <Arduino_LoRaWAN_ttn.h> +#include <lmic.h> +#include <hal/hal.h> +#include <CayenneLPP.h> + +extern int state; + +class cLoRaWAN : public Arduino_LoRaWAN_ttn +{ +public: + cLoRaWAN(){}; + +protected: + virtual bool GetOtaaProvisioningInfo(Arduino_LoRaWAN::OtaaProvisioningInfo *) override; + virtual void NetSaveFCntUp(uint32_t uFCntUp) override; + virtual void NetSaveFCntDown(uint32_t uFCntDown) override; + virtual void NetSaveSessionInfo(const SessionInfo &Info, const uint8_t *pExtraInfo, size_t nExtraInfo) override; +}; + +bool cLoRaWAN::GetOtaaProvisioningInfo( + OtaaProvisioningInfo *pInfo) +{ + static const uint8_t DEVEUI[8] = TTN_DEVEUI; + static const uint8_t APPEUI[8] = TTN_APPEUI; + static const uint8_t APPKEY[16] = TTN_APPKEY; + + if (pInfo) + { + memcpy(pInfo->AppKey, APPKEY, sizeof(APPKEY)); + memcpy(pInfo->DevEUI, DEVEUI, sizeof(DEVEUI)); + memcpy(pInfo->AppEUI, APPEUI, sizeof(APPEUI)); + } + return true; +} + +void cLoRaWAN::NetSaveFCntDown(uint32_t uFCntDown) +{ +} + +void cLoRaWAN::NetSaveFCntUp(uint32_t uFCntUp) +{ +} + +void cLoRaWAN::NetSaveSessionInfo( + const SessionInfo &Info, + const uint8_t *pExtraInfo, + size_t nExtraInfo) +{ +} + +const cLoRaWAN::lmic_pinmap pinMap = { + .nss = 18, + .rxtx = cLoRaWAN::lmic_pinmap::LMIC_UNUSED_PIN, + .rst = 23, + .dio = {26, 33, 32}, +}; + +cLoRaWAN LoRaWAN{}; + +void loraSetup() +{ + LoRaWAN.begin(pinMap); +} + +void loraLoop() +{ + LoRaWAN.loop(); +} + +int loraSend(CayenneLPP payload) +{ + Serial.println("Sending payload..."); + if (LMIC.opmode & OP_TXRXPEND) + { + Serial.println(F("TX/RX operation still pending, not sending payload.")); + return STATE_READY; + } + else + { + LMIC_setTxData2(1, payload.getBuffer(), payload.getSize(), 0); + Serial.println(F("Payload queued for sending.")); + } + return STATE_SENDING; +} + +void onEvent(ev_t ev) +{ + Serial.printf("%d: ", os_getTime()); + switch (ev) + { + case EV_SCAN_TIMEOUT: + Serial.println(F("EV_SCAN_TIMEOUT")); + break; + case EV_BEACON_FOUND: + Serial.println(F("EV_BEACON_FOUND")); + break; + case EV_BEACON_MISSED: + Serial.println(F("EV_BEACON_MISSED")); + break; + case EV_BEACON_TRACKED: + Serial.println(F("EV_BEACON_TRACKED")); + break; + case EV_JOINING: + Serial.println(F("EV_JOINING")); + break; + case EV_JOINED: + Serial.println(F("EV_JOINED")); + powerLed(AXP20X_LED_LOW_LEVEL); + break; + case EV_RFU1: + Serial.println(F("EV_RFU1")); + break; + case EV_JOIN_FAILED: + Serial.println(F("EV_JOIN_FAILED")); + break; + case EV_REJOIN_FAILED: + Serial.println(F("EV_REJOIN_FAILED")); + break; + break; + case EV_TXCOMPLETE: + Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); + if (LMIC.txrxFlags & TXRX_ACK) + Serial.println(F("Received ack")); + if (LMIC.dataLen) + { + Serial.println(F("Received ")); + Serial.println(LMIC.dataLen); + Serial.println(F(" bytes of payload")); + } + // go to sleep + state = STATE_DONE; + break; + case EV_LOST_TSYNC: + Serial.println(F("EV_LOST_TSYNC")); + break; + case EV_RESET: + Serial.println(F("EV_RESET")); + break; + case EV_RXCOMPLETE: + Serial.println(F("EV_RXCOMPLETE")); + break; + case EV_LINK_DEAD: + Serial.println(F("EV_LINK_DEAD")); + break; + case EV_LINK_ALIVE: + Serial.println(F("EV_LINK_ALIVE")); + break; + case EV_SCAN_FOUND: + Serial.println(F("EV_SCAN_FOUND")); + break; + case EV_TXSTART: + Serial.println(F("EV_TXSTART")); + break; + case EV_TXCANCELED: + Serial.println(F("EV_TXCANCELLED")); + break; + case EV_JOIN_TXCOMPLETE: + Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept")); + // restart sending + state = STATE_READY; + break; + default: + Serial.println(F("Unknown event " + (unsigned)ev)); + break; + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f84574a75834543e7a497c946ed93d3fd3627e2e..c4db76f2f7b0d996ccbc538d08a1c6b6387e6dc3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,315 +1,42 @@ -#include <config.h> -#include <axp20x.h> +#include "config.h" +#include "states.h" #include <Arduino_LoRaWAN_ttn.h> #include <lmic.h> #include <hal/hal.h> #include <SPI.h> -#include <TinyGPS++.h> #include <CayenneLPP.h> -#include <OneButton.h> +#include "power.h" +#include "gps.h" +#include "lora.h" +#include "button.h" -#define STATE_WAIT 1 -#define STATE_READY 2 -#define STATE_SENDING 3 -#define STATE_DONE 4 - -class cLoRaWAN : public Arduino_LoRaWAN_ttn -{ -public: - cLoRaWAN(){}; - -protected: - virtual bool GetOtaaProvisioningInfo(Arduino_LoRaWAN::OtaaProvisioningInfo *) override; - virtual void NetSaveFCntUp(uint32_t uFCntUp) override; - virtual void NetSaveFCntDown(uint32_t uFCntDown) override; - virtual void NetSaveSessionInfo(const SessionInfo &Info, const uint8_t *pExtraInfo, size_t nExtraInfo) override; -}; - -bool cLoRaWAN::GetOtaaProvisioningInfo( - OtaaProvisioningInfo *pInfo) -{ - static const uint8_t DEVEUI[8] = TTN_DEVEUI; - static const uint8_t APPEUI[8] = TTN_APPEUI; - static const uint8_t APPKEY[16] = TTN_APPKEY; - - if (pInfo) - { - memcpy(pInfo->AppKey, APPKEY, sizeof(APPKEY)); - memcpy(pInfo->DevEUI, DEVEUI, sizeof(DEVEUI)); - memcpy(pInfo->AppEUI, APPEUI, sizeof(APPEUI)); - } - return true; -} - -void cLoRaWAN::NetSaveFCntDown(uint32_t uFCntDown) -{ -} - -void cLoRaWAN::NetSaveFCntUp(uint32_t uFCntUp) -{ -} - -void cLoRaWAN::NetSaveSessionInfo( - const SessionInfo &Info, - const uint8_t *pExtraInfo, - size_t nExtraInfo) -{ -} - -const cLoRaWAN::lmic_pinmap pinMap = { - .nss = 18, - .rxtx = cLoRaWAN::lmic_pinmap::LMIC_UNUSED_PIN, - .rst = 23, - .dio = {26, 33, 32}, -}; - -AXP20X_Class axp; -HardwareSerial GPS(1); -TinyGPSPlus gps; -cLoRaWAN LoRaWAN{}; -OneButton btn = OneButton(GPIO_NUM_38, true, true); -CayenneLPP lpp(55); -DynamicJsonDocument jsonBuffer(1024); int state; -unsigned long timerGpsFix; RTC_DATA_ATTR int bootCount = 0; +CayenneLPP payload(55); -void onEvent(ev_t ev) -{ - Serial.printf("%d: ", os_getTime()); - switch (ev) - { - case EV_SCAN_TIMEOUT: - Serial.println(F("EV_SCAN_TIMEOUT")); - break; - case EV_BEACON_FOUND: - Serial.println(F("EV_BEACON_FOUND")); - break; - case EV_BEACON_MISSED: - Serial.println(F("EV_BEACON_MISSED")); - break; - case EV_BEACON_TRACKED: - Serial.println(F("EV_BEACON_TRACKED")); - break; - case EV_JOINING: - Serial.println(F("EV_JOINING")); - break; - case EV_JOINED: - Serial.println(F("EV_JOINED")); - axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); - break; - case EV_RFU1: - Serial.println(F("EV_RFU1")); - break; - case EV_JOIN_FAILED: - Serial.println(F("EV_JOIN_FAILED")); - break; - case EV_REJOIN_FAILED: - Serial.println(F("EV_REJOIN_FAILED")); - break; - break; - case EV_TXCOMPLETE: - Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); - if (LMIC.txrxFlags & TXRX_ACK) - Serial.println(F("Received ack")); - if (LMIC.dataLen) - { - Serial.println(F("Received ")); - Serial.println(LMIC.dataLen); - Serial.println(F(" bytes of payload")); - } - // go to sleep - state = STATE_DONE; - break; - case EV_LOST_TSYNC: - Serial.println(F("EV_LOST_TSYNC")); - break; - case EV_RESET: - Serial.println(F("EV_RESET")); - break; - case EV_RXCOMPLETE: - Serial.println(F("EV_RXCOMPLETE")); - break; - case EV_LINK_DEAD: - Serial.println(F("EV_LINK_DEAD")); - break; - case EV_LINK_ALIVE: - Serial.println(F("EV_LINK_ALIVE")); - break; - case EV_SCAN_FOUND: - Serial.println(F("EV_SCAN_FOUND")); - break; - case EV_TXSTART: - Serial.println(F("EV_TXSTART")); - break; - case EV_TXCANCELED: - Serial.println(F("EV_TXCANCELLED")); - break; - case EV_JOIN_TXCOMPLETE: - Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept")); - // restart sending - state = STATE_READY; - break; - default: - Serial.println(F("Unknown event " + (unsigned)ev)); - break; - } -} - -void printPowerStatus() -{ - Serial.println("##############################"); - Serial.println("--- Power ---"); - Serial.printf("DCDC1/OLED Status : %s\n", axp.isDCDC1Enable() ? "enabled" : "disabled"); - Serial.printf("DCDC1/OLED Voltage : %g V\n", (float)axp.getDCDC1Voltage() / 1000); - Serial.printf("DCDC2/N/C Status : %s\n", axp.isDCDC2Enable() ? "enabled" : "disabled"); - Serial.printf("DCDC2/N/C Voltage : %g V\n", (float)axp.getDCDC2Voltage() / 1000); - Serial.printf("DCDC3/ESP32 Status : %s\n", axp.isDCDC3Enable() ? "enabled" : "disabled"); - Serial.printf("DCDC3/ESP32 Voltage : %g V\n", (float)axp.getDCDC3Voltage() / 1000); - Serial.printf("LDO2/LoRa Status : %s\n", axp.isLDO2Enable() ? "enabled" : "disabled"); - Serial.printf("LDO2/LoRa Voltage : %g V\n", (float)axp.getLDO2Voltage() / 1000); - Serial.printf("LDO3/GPS Status : %s\n", axp.isLDO3Enable() ? "enabled" : "disabled"); - Serial.printf("LDO3/GPS Voltage : %g V\n", (float)axp.getLDO3Voltage() / 1000); - Serial.println("--- Battery ---"); - Serial.printf("Battery Connected: %s\n", axp.isBatteryConnect() ? "true" : "false"); - if (axp.isBatteryConnect()) - { - Serial.printf("Battery Percentage : %d %%\n", axp.getBattPercentage()); - Serial.printf("Battery Voltage : %g V\n", axp.getBattVoltage() / 1000); - Serial.printf("Battery Current : %g mA\n", axp.getBattDischargeCurrent()); - Serial.println("--- Charging ---"); - Serial.printf("Charging Enabled : %s\n", axp.isChargeingEnable() ? "true" : "false"); - Serial.printf("Battery Charging : %s\n", axp.isChargeing() ? "true" : "false"); - Serial.printf("Set Charge Current : %g mA\n", axp.getSettingChargeCurrent()); - } - Serial.println("--- Chip ---"); - Serial.printf("Chip Temp : %.1f C°\n", axp.getTemp() / 10); - Serial.println("##############################"); -} - -void printGpsStatus() -{ - while (GPS.available()) - { - gps.encode(GPS.read()); - } - Serial.println("##############################"); - Serial.println("--- GPS ---"); - Serial.printf("Latitude : %f\n", gps.location.lat()); - Serial.printf("Longitude : %f\n", gps.location.lng()); - Serial.printf("Satellites : %d\n", gps.satellites.value()); - Serial.printf("Altitude : %g m\n", gps.altitude.meters()); - Serial.printf("Time : %02d:%02d:%02d\n", gps.time.hour(), gps.time.minute(), gps.time.second()); - Serial.printf("Speed : %g\n", gps.speed.kmph()); - Serial.println("##############################"); -} - -void setupPower() -{ - if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) - { - Serial.println("AXP192 Begin PASS"); - } - else - { - Serial.println("AXP192 Begin FAIL"); - } - axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); // OLED : off - axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); // N/C : off - axp.setPowerOutPut(AXP192_DCDC3, AXP202_ON); // ESP32 : on - axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA : on - axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS : on - /* - axp.setDCDC3Voltage(3300); // ESP32 : 3.3V - axp.setLDO2Voltage(3300); // LORA : 3.3V - axp.setLDO3Voltage(3300); // GPS : 3.3V - */ - axp.setChgLEDMode(AXP20X_LED_OFF); - printPowerStatus(); -} - -void setupGps() -{ - GPS.begin(9600, SERIAL_8N1, 34, 12); // IO34: RX, IO12: TX -} - -void checkGpsFix() +void createPayload() { - if (millis() - timerGpsFix >= 1000 * 1) // 1 second - { - Serial.println("Waiting for GPS fix..."); - while (GPS.available()) - { - gps.encode(GPS.read()); - } - if (gps.location.isValid()) - { - printGpsStatus(); - state = STATE_READY; - } - timerGpsFix = millis(); - } + payload.reset(); + TinyGPSPlus gps = getGps(); + payload.addGPS(1, gps.location.lat(), gps.location.lng(), gps.altitude.meters()); + payload.addAnalogInput(2, powerGetBattVoltage() / 1000); } -void createPayload() -{ - while (GPS.available()) - { - gps.encode(GPS.read()); - } - lpp.reset(); - lpp.addGPS(1, gps.location.lat(), gps.location.lng(), gps.altitude.meters()); - lpp.addAnalogInput(2, axp.getBattVoltage() / 1000); - // debug output +void printPayload() { + DynamicJsonDocument jsonBuffer(1024); JsonObject json = jsonBuffer.to<JsonObject>(); - lpp.decodeTTN(lpp.getBuffer(), lpp.getSize(), json); + payload.decodeTTN(payload.getBuffer(), payload.getSize(), json); + Serial.println("\n########## Payload ##########"); serializeJsonPretty(json, Serial); - Serial.println(); -} - -void sendPayload() -{ - if (LMIC.opmode & OP_TXRXPEND) - { - Serial.println(F("OP_TXRXPEND, not sending")); - state = STATE_READY; - } - else - { - LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0); - Serial.println(F("Packet queued")); - } + Serial.println("\n#########################\n"); } -void sendStatus() +static void bootInfo() { - Serial.println("Sending status..."); - axp.setChgLEDMode(AXP20X_LED_BLINK_4HZ); - createPayload(); - sendPayload(); - state = STATE_SENDING; -} - -void doSleep() -{ - Serial.println("Going to sleep for " + String(TIME_SLEEP) + " seconds."); - axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA : off - axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // GPS : off - axp.setChgLEDMode(AXP20X_LED_OFF); - esp_sleep_enable_ext0_wakeup(GPIO_NUM_38, LOW); // wake up with "user" button (middle) - esp_sleep_enable_timer_wakeup(1000000 * TIME_SLEEP); - esp_deep_sleep_start(); -} - -static void handleClick() -{ - doSleep(); -} + ++bootCount; + Serial.println("Boot number: " + String(bootCount)); -void print_wakeup_reason() -{ esp_sleep_wakeup_cause_t wakeup_reason; - wakeup_reason = esp_sleep_get_wakeup_cause(); switch (wakeup_reason) @@ -339,36 +66,34 @@ void setup() { Serial.begin(115200); Wire.begin(21, 22); - ++bootCount; - Serial.println("Boot number: " + String(bootCount)); - print_wakeup_reason(); - setupPower(); - setupGps(); - LoRaWAN.begin(pinMap); - btn.attachClick(handleClick); - timerGpsFix = millis(); - axp.setChgLEDMode(AXP20X_LED_BLINK_1HZ); - state = STATE_WAIT; + bootInfo(); + powerSetup(); + gpsSetup(); + loraSetup(); + buttonSetup(); + state = STATE_INIT; } void loop() { - btn.tick(); - LoRaWAN.loop(); + loraLoop(); + buttonLoop(); switch (state) { - case STATE_WAIT: - checkGpsFix(); + case STATE_INIT: + gpsCheck(); break; case STATE_READY: - sendStatus(); + createPayload(); + state = loraSend(payload); // success: STATE_SENDING, error: STATE_READY + printPayload(); break; case STATE_SENDING: // idle break; case STATE_DONE: - doSleep(); + powerSleep(); break; default: break; diff --git a/src/power.cpp b/src/power.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89e276fafa0d4cf4928cf2dc3fef67a50653a35a --- /dev/null +++ b/src/power.cpp @@ -0,0 +1,86 @@ +#include "config.h" +#include <axp20x.h> + +AXP20X_Class axp; + +void powerLed(axp_chgled_mode_t mode) +{ + axp.setChgLEDMode(mode); +} + +float powerGetBattVoltage() +{ + return axp.getBattVoltage(); +} + +void powerSetOutput(uint8_t channel, bool enabled) +{ + axp.setPowerOutPut(channel, enabled); +} + +void powerStatus() +{ + Serial.println("\n########## Power ##########"); + Serial.printf("DCDC1/OLED Status : %s\n", axp.isDCDC1Enable() ? "enabled" : "disabled"); + Serial.printf("DCDC1/OLED Voltage : %g V\n", (float)axp.getDCDC1Voltage() / 1000); + Serial.printf("DCDC2/N/C Status : %s\n", axp.isDCDC2Enable() ? "enabled" : "disabled"); + Serial.printf("DCDC2/N/C Voltage : %g V\n", (float)axp.getDCDC2Voltage() / 1000); + Serial.printf("DCDC3/ESP32 Status : %s\n", axp.isDCDC3Enable() ? "enabled" : "disabled"); + Serial.printf("DCDC3/ESP32 Voltage : %g V\n", (float)axp.getDCDC3Voltage() / 1000); + Serial.printf("LDO2/LoRa Status : %s\n", axp.isLDO2Enable() ? "enabled" : "disabled"); + Serial.printf("LDO2/LoRa Voltage : %g V\n", (float)axp.getLDO2Voltage() / 1000); + Serial.printf("LDO3/GPS Status : %s\n", axp.isLDO3Enable() ? "enabled" : "disabled"); + Serial.printf("LDO3/GPS Voltage : %g V\n", (float)axp.getLDO3Voltage() / 1000); + Serial.println("--- Battery ---"); + Serial.printf("Battery Connected: %s\n", axp.isBatteryConnect() ? "true" : "false"); + if (axp.isBatteryConnect()) + { + Serial.printf("Battery Percentage : %d %%\n", axp.getBattPercentage()); + Serial.printf("Battery Voltage : %g V\n", axp.getBattVoltage() / 1000); + Serial.printf("Battery Current : %g mA\n", axp.getBattDischargeCurrent()); + Serial.println("--- Charging ---"); + Serial.printf("Charging Enabled : %s\n", axp.isChargeingEnable() ? "true" : "false"); + Serial.printf("Battery Charging : %s\n", axp.isChargeing() ? "true" : "false"); + Serial.printf("Set Charge Current : %g mA\n", axp.getSettingChargeCurrent()); + } + Serial.println("--- Chip ---"); + Serial.printf("Chip Temp : %.1f C°\n", axp.getTemp() / 10); + Serial.println("#########################\n"); +} + +void powerSetup() +{ + if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) + { + Serial.println("AXP192 Begin PASS"); + } + else + { + Serial.println("AXP192 Begin FAIL"); + } + axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); // OLED : off + axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); // N/C : off + axp.setPowerOutPut(AXP192_DCDC3, AXP202_ON); // ESP32 : on + axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA : on + axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS : on + /* + axp.setDCDC3Voltage(3300); // ESP32 : 3.3V + axp.setLDO2Voltage(3300); // LORA : 3.3V + axp.setLDO3Voltage(3300); // GPS : 3.3V + */ + axp.setChgLEDMode(AXP20X_LED_OFF); + powerStatus(); +} + +void powerSleep() +{ + Serial.printf("\nSystem has been up for %llu seconds.\n", esp_timer_get_time()/1000000); + Serial.printf("Going to sleep for %d seconds.\n", SLEEP_SECONDS); + powerSetOutput(AXP192_LDO2, AXP202_OFF); // LORA : off + powerSetOutput(AXP192_LDO3, AXP202_OFF); // GPS : off + powerLed(AXP20X_LED_OFF); + esp_sleep_enable_ext0_wakeup(GPIO_NUM_38, LOW); // wake up with "user" button (middle) + esp_sleep_enable_timer_wakeup(1000000 * SLEEP_SECONDS); + Serial.println("\n### END ###"); + esp_deep_sleep_start(); +} \ No newline at end of file