#include <config.h> #include <axp20x.h> #include <Arduino_LoRaWAN_ttn.h> #include <lmic.h> #include <hal/hal.h> #include <SPI.h> #include <TinyGPS++.h> #include <OneButton.h> 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) { // save uFcntDown somwwhere } void cLoRaWAN::NetSaveFCntUp(uint32_t uFCntUp) { // save uFCntUp somewhere } void cLoRaWAN::NetSaveSessionInfo( const SessionInfo &Info, const uint8_t *pExtraInfo, size_t nExtraInfo) { // save Info somewhere. } const cLoRaWAN::lmic_pinmap pinMap = { .nss = 18, .rxtx = cLoRaWAN::lmic_pinmap::LMIC_UNUSED_PIN, .rst = 23, .dio = {26, 33, cLoRaWAN::lmic_pinmap::LMIC_UNUSED_PIN}, }; AXP20X_Class axp; HardwareSerial GPS(1); TinyGPSPlus gps; cLoRaWAN LoRaWAN{}; OneButton btn = OneButton(BUTTON_PIN, true, true); static uint8_t mydata[] = "Hello, world!"; static osjob_t sendjob; const unsigned TX_INTERVAL = 60; 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); } void setupGps() { GPS.begin(9600, SERIAL_8N1, 34, 12); // IO34: RX, IO12: TX } void printStatus() { axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); while (GPS.available()) { gps.encode(GPS.read()); } 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("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("--- GPS ---"); Serial.print("Latitude : "); Serial.println(gps.location.lat(), 5); Serial.print("Longitude : "); Serial.println(gps.location.lng(), 4); Serial.print("Satellites : "); Serial.println(gps.satellites.value()); Serial.print("Altitude : "); Serial.print(gps.altitude.feet() / 3.2808); Serial.println("M"); Serial.print("Time : "); Serial.print(gps.time.hour()); Serial.print(":"); Serial.print(gps.time.minute()); Serial.print(":"); Serial.println(gps.time.second()); Serial.print("Speed : "); Serial.println(gps.speed.kmph()); Serial.println("##############################"); axp.setChgLEDMode(AXP20X_LED_OFF); } static void handleClick() { printStatus(); } void do_send(osjob_t *j) { // Check if there is not a current TX/RX job running if (LMIC.opmode & OP_TXRXPEND) { Serial.println(F("OP_TXRXPEND, not sending")); } else { // Prepare upstream data transmission at the next possible time. LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0); Serial.println(F("Packet queued")); } // Next TX is scheduled after TX_COMPLETE event. } void onEvent(ev_t ev) { Serial.print(os_getTime()); Serial.print(": "); 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")); // TTN uses SF9 for its RX2 window. LMIC.dn2Dr = EU868_DR_SF9; break; case EV_JOINED: Serial.println(F("EV_JOINED")); { u4_t netid = 0; devaddr_t devaddr = 0; u1_t nwkKey[16]; u1_t artKey[16]; LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey); Serial.print("netid: "); Serial.println(netid, DEC); Serial.print("devaddr: "); Serial.println(devaddr, HEX); Serial.print("artKey: "); for (int i = 0; i < sizeof(artKey); ++i) { Serial.print(artKey[i], HEX); } Serial.println(""); Serial.print("nwkKey: "); for (int i = 0; i < sizeof(nwkKey); ++i) { Serial.print(nwkKey[i], HEX); } Serial.println(""); LMIC_setSeqnoUp(140); } 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")); } // Schedule next transmission os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); break; case EV_LOST_TSYNC: Serial.println(F("EV_LOST_TSYNC")); break; case EV_RESET: Serial.println(F("EV_RESET")); break; case EV_RXCOMPLETE: // data received in ping slot 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")); break; default: Serial.println(F("Unknown event " + (unsigned)ev)); break; } } void setup() { Serial.begin(115200); Wire.begin(21, 22); setupPower(); setupGps(); LoRaWAN.begin(pinMap); btn.attachClick(handleClick); printStatus(); do_send(&sendjob); } void loop() { LoRaWAN.loop(); btn.tick(); }