-
-
Save tgxn/1022cf9910f8cf5eb59702f334448129 to your computer and use it in GitHub Desktop.
Walter Features Test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <esp_mac.h> | |
| #include <WalterModem.h> | |
| #include <HardwareSerial.h> | |
| #define MODEM_HTTP_PROFILE 1 | |
| #define TLS_PROFILE 1 | |
| /** | |
| * @brief The size in bytes of a minimal sensor + GNSS + cell info packet. | |
| */ | |
| #define PACKET_SIZE 29 | |
| /** | |
| * @brief All fixes with a confidence below this number are considered ok. | |
| */ | |
| #define MAX_GNSS_CONFIDENCE 50.0 | |
| /** | |
| * @brief The serial interface to talk to the modem. | |
| */ | |
| #define ModemSerial Serial2 | |
| /** | |
| * @brief The radio access technology to use - LTEM or NBIOT. | |
| */ | |
| #define RADIO_TECHNOLOGY WALTER_MODEM_RAT_LTEM | |
| // modem stuff | |
| /** | |
| * @brief The modem instance. | |
| */ | |
| WalterModem modem; | |
| /** | |
| * @brief Flag used to signal when a fix is received. | |
| */ | |
| volatile bool fixRcvd = false; | |
| /** | |
| * @brief The last received GNSS fix. | |
| */ | |
| WalterModemGNSSFix posFix = {}; | |
| /** | |
| * @brief The buffer to transmit to the UDP server. The first 6 bytes will be | |
| * the MAC address of the Walter this code is running on. | |
| */ | |
| uint8_t dataBuf[PACKET_SIZE] = { 0 }; | |
| /** | |
| * @brief Connect to the LTE network. | |
| * | |
| * This function will connect the modem to the LTE network. This function will | |
| * block until the modem is attached. | |
| * | |
| * @return True on success, false on error. | |
| */ | |
| bool lteConnect() | |
| { | |
| /* Set the operational state to full */ | |
| if (!modem.setOpState(WALTER_MODEM_OPSTATE_FULL)) | |
| { | |
| Serial.print("Could not set operational state to FULL\r\n"); | |
| return false; | |
| } | |
| /* Set the network operator selection to automatic */ | |
| if (!modem.setNetworkSelectionMode(WALTER_MODEM_NETWORK_SEL_MODE_AUTOMATIC)) | |
| { | |
| Serial.print("Could not set the network selection mode to automatic\r\n"); | |
| return false; | |
| } | |
| /* Wait for the network to become available */ | |
| WalterModemNetworkRegState regState = modem.getNetworkRegState(); | |
| while (!(regState == WALTER_MODEM_NETWORK_REG_REGISTERED_HOME || | |
| regState == WALTER_MODEM_NETWORK_REG_REGISTERED_ROAMING)) | |
| { | |
| delay(100); | |
| regState = modem.getNetworkRegState(); | |
| } | |
| /* Stabilization time */ | |
| Serial.print("Connected to the network\r\n"); | |
| return true; | |
| } | |
| /** | |
| * @brief Disconnect from the LTE network. | |
| * | |
| * This function will disconnect the modem from the LTE network and block until | |
| * the network is actually disconnected. After the network is disconnected the | |
| * GNSS subsystem can be used. | |
| * | |
| * @return True on success, false on error. | |
| */ | |
| bool lteDisconnect() | |
| { | |
| /* Set the operational state to minimum */ | |
| if (!modem.setOpState(WALTER_MODEM_OPSTATE_MINIMUM)) | |
| { | |
| Serial.print("Could not set operational state to MINIMUM\r\n"); | |
| return false; | |
| } | |
| /* Wait for the network to become available */ | |
| WalterModemNetworkRegState regState = modem.getNetworkRegState(); | |
| while (regState != WALTER_MODEM_NETWORK_REG_NOT_SEARCHING) | |
| { | |
| delay(100); | |
| regState = modem.getNetworkRegState(); | |
| } | |
| Serial.print("Disconnected from the network\r\n"); | |
| return true; | |
| } | |
| /** | |
| * @brief Check the assistance data in the modem response. | |
| * | |
| * This function checks the availability of assistance data in the modem's | |
| * response. This function also sets a flag if any of the assistance databases | |
| * should be updated. | |
| * | |
| * @param rsp The modem response to check. | |
| * @param updateAlmanac Pointer to the flag to set when the almanac should be | |
| * updated. | |
| * @param updateEphemeris Pointer to the flag to set when ephemeris should be | |
| * updated. | |
| * | |
| * @return None. | |
| */ | |
| void checkAssistanceData( | |
| WalterModemRsp *rsp, | |
| bool *updateAlmanac = NULL, | |
| bool *updateEphemeris = NULL | |
| ) { | |
| if (updateAlmanac != NULL) { | |
| *updateAlmanac = false; | |
| } | |
| if (updateEphemeris != NULL) { | |
| *updateEphemeris = false; | |
| } | |
| Serial.print("Almanac data is "); | |
| if (rsp->data.gnssAssistance.almanac.available) { | |
| Serial.printf("available and should be updated within %ds\r\n", | |
| rsp->data.gnssAssistance.almanac.timeToUpdate); | |
| if (updateAlmanac != NULL) { | |
| *updateAlmanac = rsp->data.gnssAssistance.almanac.timeToUpdate <= 0; | |
| } | |
| } else { | |
| Serial.print("not available.\r\n"); | |
| if (updateAlmanac != NULL) { | |
| *updateAlmanac = true; | |
| } | |
| } | |
| Serial.print("Real-time ephemeris data is "); | |
| if (rsp->data.gnssAssistance.realtimeEphemeris.available) { | |
| Serial.printf("available and should be updated within %ds\r\n", rsp->data.gnssAssistance.realtimeEphemeris.timeToUpdate); | |
| if (updateEphemeris != NULL) { | |
| *updateEphemeris = rsp->data.gnssAssistance.realtimeEphemeris.timeToUpdate <= 0; | |
| } | |
| } else { | |
| Serial.print("not available.\r\n"); | |
| if (updateEphemeris != NULL) { | |
| *updateEphemeris = true; | |
| } | |
| } | |
| } | |
| /** | |
| * @brief This function will update GNSS assistance data when needed. | |
| * | |
| * This funtion will check if the current real-time ephemeris data is good | |
| * enough to get a fast GNSS fix. If not the function will attach to the LTE | |
| * network to download newer assistance data. | |
| * | |
| * @return True on success, false on error. | |
| */ | |
| bool updateGNSSAssistance() { | |
| bool lteConnected = false; | |
| WalterModemRsp rsp = {}; | |
| lteDisconnect(); | |
| /* Even with valid assistance data the system clock could be invalid */ | |
| if (!modem.getClock(&rsp)) | |
| { | |
| Serial.print("Could not check the modem time\r\n"); | |
| return false; | |
| } | |
| if (rsp.data.clock.epochTime <= 0) | |
| { | |
| /* The system clock is invalid, connect to LTE network to sync time */ | |
| if (!lteConnect()) | |
| { | |
| Serial.print("Could not connect to LTE network\r\n"); | |
| return false; | |
| } | |
| lteConnected = true; | |
| /* | |
| * Wait for the modem to synchronize time with the LTE network, try 5 times | |
| * with a delay of 500ms. | |
| */ | |
| for (int i = 0; i < 5; ++i) { | |
| if (!modem.getClock(&rsp)) { | |
| Serial.print("Could not check the modem time\r\n"); | |
| return false; | |
| } | |
| if (rsp.data.clock.epochTime > 0) { | |
| Serial.printf("Synchronized clock with network: %" PRIi64 "\r\n", rsp.data.clock.epochTime); | |
| break; | |
| } else if (i == 4) { | |
| Serial.print("Could not sync time with network\r\n"); | |
| return false; | |
| } | |
| delay(500); | |
| } | |
| } | |
| /* Check the availability of assistance data */ | |
| if (!modem.gnssGetAssistanceStatus(&rsp) || | |
| rsp.type != WALTER_MODEM_RSP_DATA_TYPE_GNSS_ASSISTANCE_DATA) | |
| { | |
| Serial.print("Could not request GNSS assistance status\r\n"); | |
| return false; | |
| } | |
| bool updateAlmanac = false; | |
| bool updateEphemeris = false; | |
| checkAssistanceData(&rsp, &updateAlmanac, &updateEphemeris); | |
| if (!(updateAlmanac || updateEphemeris)) | |
| { | |
| if (lteConnected) | |
| { | |
| if (!lteDisconnect()) | |
| { | |
| Serial.print("Could not disconnect from the LTE network\r\n"); | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| if (!lteConnected) | |
| { | |
| if (!lteConnect()) | |
| { | |
| Serial.print("Could not connect to LTE network\r\n"); | |
| return false; | |
| } | |
| } | |
| if (updateAlmanac) | |
| { | |
| if (!modem.gnssUpdateAssistance(WALTER_MODEM_GNSS_ASSISTANCE_TYPE_ALMANAC)) | |
| { | |
| Serial.print("Could not update almanac data\r\n"); | |
| return false; | |
| } | |
| } | |
| if (updateEphemeris) | |
| { | |
| if (!modem.gnssUpdateAssistance( | |
| WALTER_MODEM_GNSS_ASSISTANCE_TYPE_REALTIME_EPHEMERIS)) | |
| { | |
| Serial.print("Could not update real-time ephemeris data\r\n"); | |
| return false; | |
| } | |
| } | |
| if (!modem.gnssGetAssistanceStatus(&rsp) || | |
| rsp.type != WALTER_MODEM_RSP_DATA_TYPE_GNSS_ASSISTANCE_DATA) | |
| { | |
| Serial.print("Could not request GNSS assistance status\r\n"); | |
| return false; | |
| } | |
| checkAssistanceData(&rsp); | |
| if (!lteDisconnect()) | |
| { | |
| Serial.print("Could not disconnect from the LTE network\r\n"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| /** | |
| * @brief This function is called when a fix attempt finished. | |
| * | |
| * This function is called by Walter's modem library as soon as a fix attempt | |
| * has finished. This function should be handled as an interrupt and should be | |
| * as short as possible as it is called within the modem data thread. | |
| * | |
| * @param fix The fix data. | |
| * @param args Optional arguments, a NULL pointer in this case. | |
| * | |
| * @return None. | |
| */ | |
| void fixHandler(const WalterModemGNSSFix *fix, void *args) { | |
| memcpy(&posFix, fix, sizeof(WalterModemGNSSFix)); | |
| fixRcvd = true; | |
| } | |
| void printMac() { | |
| /* Get the MAC address for board validation */ | |
| esp_read_mac(dataBuf, ESP_MAC_WIFI_STA); | |
| Serial.printf("Walter's MAC is: %02X:%02X:%02X:%02X:%02X:%02X\r\n", | |
| dataBuf[0], | |
| dataBuf[1], | |
| dataBuf[2], | |
| dataBuf[3], | |
| dataBuf[4], | |
| dataBuf[5]); | |
| } | |
| const char* ratToString(int rat) { | |
| switch (rat) { | |
| case 0: return "LTEM"; | |
| case 1: return "NBIOT"; | |
| case 2: return "AUTO"; | |
| case 99: return "UNKNOWN"; | |
| default: return "default"; | |
| } | |
| } | |
| void setup() { | |
| Serial.begin(115200); | |
| delay(1000); | |
| Serial.println(); | |
| Serial.println("Walter Modem Turn On :: v0.0.1"); | |
| printMac(); | |
| /* Modem initialization */ | |
| if(modem.begin(&ModemSerial)) { | |
| Serial.println("Modem initialization OK"); | |
| } else { | |
| Serial.println("Error: Modem initialization ERROR"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| WalterModemRsp rsp = {}; | |
| if(modem.getIdentity(&rsp)) { | |
| Serial.print("Modem identity:\r\n"); | |
| Serial.printf(" IMEI: %s\r\n", rsp.data.identity.imei); | |
| Serial.printf(" IMEISV: %s\r\n", rsp.data.identity.imeisv); | |
| Serial.printf(" SVN: %s\r\n", rsp.data.identity.svn); | |
| } | |
| if(modem.getRAT(&rsp)) { | |
| Serial.printf("Modem radio technology: %s\r\n", ratToString(rsp.data.rat)); | |
| if(rsp.data.rat != RADIO_TECHNOLOGY) { | |
| modem.setRAT(RADIO_TECHNOLOGY); | |
| Serial.println("Switched modem radio technology"); | |
| } | |
| } else { | |
| Serial.println("Could not retrieve radio access technology"); | |
| } | |
| if(!modem.definePDPContext()) { | |
| Serial.println("Could not create PDP context"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| if(!modem.setOpState(WALTER_MODEM_OPSTATE_NO_RF)) { | |
| Serial.println("Could not set operational state to NO RF"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| delay(500); | |
| if(modem.getSIMCardID(&rsp)) { | |
| Serial.print("SIM card identity:\r\n"); | |
| Serial.printf(" ICCID: %s\r\n", rsp.data.simCardID.iccid); | |
| Serial.printf(" eUICCID: %s\r\n", rsp.data.simCardID.euiccid); | |
| } | |
| if(modem.getSIMCardIMSI(&rsp)) { | |
| Serial.printf("Active IMSI: %s\r\n", rsp.data.imsi); | |
| } | |
| if(!modem.gnssConfig()) { | |
| Serial.print("Could not configure the GNSS subsystem\r\n"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| modem.gnssSetEventHandler(fixHandler); | |
| } | |
| void loop() { | |
| Serial.println(""); | |
| Serial.println("-----"); | |
| Serial.println("1. Connect + Test Modem"); | |
| Serial.println("-----"); | |
| static WalterModemRsp rsp = {}; | |
| if (!lteConnect()) { | |
| Serial.println("Could not connect to the LTE network"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| /* Read the temperature of Walter */ | |
| float temp = temperatureRead(); | |
| Serial.printf("Temp: %.02f°c\r\n", temp); | |
| if (!modem.getCellInformation(WALTER_MODEM_SQNMONI_REPORTS_SERVING_CELL, &rsp)) { | |
| Serial.println("Could not request cell information"); | |
| } else { | |
| Serial.printf("Connected on band %u using operator %s (%u%02u)", | |
| rsp.data.cellInformation.band, rsp.data.cellInformation.netName, | |
| rsp.data.cellInformation.cc, rsp.data.cellInformation.nc); | |
| Serial.printf(" and cell ID %u.\r\n", | |
| rsp.data.cellInformation.cid); | |
| Serial.printf("Signal strength: RSRP: %.2f, RSRQ: %.2f.\r\n", | |
| rsp.data.cellInformation.rsrp, rsp.data.cellInformation.rsrq); | |
| } | |
| // Get signal quality | |
| if (modem.getSignalQuality(&rsp)) { | |
| Serial.print("rsrq: "); | |
| Serial.print(rsp.data.signalQuality.rsrq); | |
| Serial.print(", rsrp: "); | |
| Serial.println(rsp.data.signalQuality.rsrp); | |
| } else { | |
| Serial.println("Error: Could not get signal quality"); | |
| } | |
| if (modem.getRSSI(&rsp)) { | |
| Serial.print("rssi: "); | |
| Serial.print(rsp.data.rssi); | |
| Serial.println(" dB"); | |
| } else { | |
| Serial.println("Error: Could not get rssi"); | |
| } | |
| // Get clock | |
| if (modem.getClock(&rsp)) { | |
| Serial.print("epochTime: "); | |
| Serial.print(rsp.data.clock.epochTime); | |
| Serial.print(", timeZoneOffset: "); | |
| Serial.println(rsp.data.clock.timeZoneOffset); | |
| } else { | |
| Serial.println("Error: Could not get clock"); | |
| } | |
| if (!lteDisconnect()) | |
| { | |
| Serial.print("Could not disconnect from the LTE network\r\n"); | |
| return; | |
| } | |
| Serial.println("-----"); | |
| Serial.println("2. Get GPS Fix"); | |
| Serial.println("-----"); | |
| if(!modem.gnssConfig()) { | |
| Serial.print("Could not configure the GNSS subsystem\r\n"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| /* Check clock and assistance data, update if required */ | |
| if (!updateGNSSAssistance()) { | |
| Serial.println("Could not update GNSS assistance data"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| /* Try up to 5 times to get a good fix */ | |
| for (int i = 0; i < 10; ++i) { | |
| fixRcvd = false; | |
| if(!modem.gnssPerformAction()) { | |
| Serial.print("Could not request GNSS fix\r\n"); | |
| delay(1000); | |
| ESP.restart(); | |
| return; | |
| } | |
| Serial.print("Started GNSS fix\r\n"); | |
| int j = 0; | |
| while (!fixRcvd) { | |
| Serial.print("."); | |
| if (j >= 600) { | |
| Serial.println(""); | |
| Serial.println("Timed out while waiting for GNSS fix"); | |
| delay(1000); | |
| ESP.restart(); | |
| break; | |
| } | |
| j++; | |
| delay(500); | |
| } | |
| Serial.println(""); | |
| if (posFix.estimatedConfidence <= MAX_GNSS_CONFIDENCE) { | |
| break; | |
| } | |
| } | |
| uint8_t abovedBTreshold = 0; | |
| for (int i = 0; i < posFix.satCount; ++i) { | |
| if (posFix.sats[i].signalStrength >= 30) { | |
| abovedBTreshold += 1; | |
| } | |
| } | |
| Serial.printf("GNSS fix attempt finished:\r\n" | |
| " Confidence: %.02f\r\n" | |
| " Latitude: %.06f\r\n" | |
| " Longitude: %.06f\r\n" | |
| " Satcount: %d\r\n" | |
| " Good sats: %d\r\n", | |
| posFix.estimatedConfidence, | |
| posFix.latitude, | |
| posFix.longitude, | |
| posFix.satCount, | |
| abovedBTreshold); | |
| Serial.print("----- waiting 60s "); | |
| for (int i = 1; i <= 60; ++i) { | |
| Serial.print("."); | |
| delay(1000); | |
| } | |
| Serial.println(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment