Skip to content

Commit

Permalink
Merge pull request #12 from LeeLeahy2/9-6
Browse files Browse the repository at this point in the history
9_6: Add example 9_6_Network_Failover for Arduino v3
  • Loading branch information
PaulZC authored Sep 4, 2024
2 parents 05f380e + e5e74e6 commit 9e1f016
Show file tree
Hide file tree
Showing 13 changed files with 2,376 additions and 8 deletions.
6 changes: 6 additions & 0 deletions Example_Sketches/9_5_PPP_HTTPS/9_5_PPP_HTTPS.ino
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ bool RTK_CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC = false;

#define ARDUINO_EVENT_LARA_ON ((arduino_event_id_t)-1)

#define USE_EVENT_QUEUE 0 // Change to 1 to enable the event queue

//----------------------------------------

typedef bool (* IS_CONNECTED)();
Expand Down Expand Up @@ -45,8 +47,12 @@ HTTPS_CLIENT_CONNECTION SparkFun;
// System initialization
void setup()
{
delay(1000);

Serial.begin(115200);

Serial.println("SparkFun EVK Example");

// Initialize the network
Network.onEvent(networkOnEvent);

Expand Down
21 changes: 20 additions & 1 deletion Example_Sketches/9_5_PPP_HTTPS/Network.ino
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//----------------------------------------
// Process network events

std::vector<arduino_event_id_t> eventQueue; // vector of network events

void networkOnEvent(arduino_event_id_t event, arduino_event_info_t info)
{
IPAddress ipv4;
Expand All @@ -17,7 +20,23 @@ void networkOnEvent(arduino_event_id_t event, arduino_event_info_t info)
case ARDUINO_EVENT_PPP_LOST_IP:
case ARDUINO_EVENT_PPP_DISCONNECTED:
case ARDUINO_EVENT_PPP_STOP:
pppEvent(event);
if (USE_EVENT_QUEUE)
eventQueue.push_back(event);
else
pppEvent(event);
break;
}
}

void processEventQueue()
{
if (USE_EVENT_QUEUE)
{
auto it = eventQueue.begin();
if (it != eventQueue.end())
{
pppEvent(*it);
eventQueue.erase(it);
}
}
}
48 changes: 41 additions & 7 deletions Example_Sketches/9_5_PPP_HTTPS/PPP.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#define PWREN 32

// LARA pins
#define LARA_RST 26 // Using the power pin as reset
#define LARA_PWR 26
#define LARA_TX 13
#define LARA_RX 14
#define LARA_RTS -1
Expand Down Expand Up @@ -48,6 +48,8 @@ bool pppIsInternetAvailable()
// Perform PPP polling
void pppUpdate()
{
processEventQueue();

switch (pppState)
{
case PPP_STATE_MOBILE_NETWORK:
Expand Down Expand Up @@ -95,17 +97,49 @@ void pppEvent(arduino_event_id_t event)
if (event == ARDUINO_EVENT_LARA_ON)
{
// Configure the modem
PPP.setApn(PPP_MODEM_APN);
PPP.setPin(PPP_MODEM_PIN);
PPP.setResetPin(LARA_RST, PPP_MODEM_RST_LOW);
PPP.setPins(LARA_TX, LARA_RX, LARA_RTS, LARA_CTS, PPP_MODEM_FC);
// Note: the modem AT commands are defined in:
// https://github.com/espressif/esp-protocols/blob/master/components/esp_modem/src/esp_modem_command_library.cpp

// Set LARA_PWR low
// LARA_PWR is inverted by the RTK EVK level-shifter
// High 'pushes' the LARA PWR_ON pin, toggling the power
// Configure the pin here as PPP doesn't configure _pin_rst until .begin is called
pinMode(LARA_PWR, OUTPUT);
digitalWrite(LARA_PWR, LOW);

// Now enable the 3.3V regulators for the GNSS and LARA
pinMode(PWREN, OUTPUT);
digitalWrite(PWREN, HIGH);

delay(2000); // Wait for the power to stabilize

// We don't know if the module is on or off
// From the datasheet:
// Hold LARA_PWR pin low for 0.15 - 3.20s to switch module on
// Hold LARA_PWR pin low for 1.50s minimum to switch module off
// (Remember that LARA_PWR is inverted by the RTK EVK level-shifter)
// From initial power-on, the LARA will be off
// If the LARA is already on, toggling LARA_PWR could turn it off...
// If the LARA is already on and in a data state, an escape sequence (+++) (set_command_mode)
// is needed to deactivate. PPP.begin tries this, but it fails if the modem is in CMUX mode.
// Also, the LARA takes ~8 seconds to start up after power on....

// If the modem is off, a 2s push will turn it on
// If the modem is on, a 2s push will turn it off
Serial.println("Toggling the modem power");
digitalWrite(LARA_PWR, HIGH);
delay(2000);
digitalWrite(LARA_PWR, LOW);
delay(2000); // 1000 is too short

// Now let the PPP turn the modem back on again if needed - with a 200ms reset
// If the modem is on, this is too short to turn it off again
Serial.println("Starting the modem. It might take a while!");
pppState = PPP_STATE_LARA_ON;
PPP.setApn(PPP_MODEM_APN);
PPP.setPin(PPP_MODEM_PIN);
PPP.setResetPin(LARA_PWR, PPP_MODEM_RST_LOW); // v3.0.2 allows you to set the reset delay, but we don't need it
PPP.setPins(LARA_TX, LARA_RX, LARA_RTS, LARA_CTS, PPP_MODEM_FC);
pppState = PPP_STATE_LARA_ON; // Change pppState now. PPP_START / PPP_STOP will occur in the new state
pppOnline = false;
PPP.begin(PPP_MODEM_MODEL);
}
Expand All @@ -124,7 +158,7 @@ void pppEvent(arduino_event_id_t event)
pppOnline = false;
pppState = PPP_STATE_MOBILE_NETWORK;
}
else if (event == ARDUINO_EVENT_PPP_STOP)
else if (event == ARDUINO_EVENT_PPP_STOP) // This happens when the PPP.begin fails
{
Serial.println("PPP Stopped");
pppOnline = false;
Expand Down
230 changes: 230 additions & 0 deletions Example_Sketches/9_6_Network_Failover/9_6_Network_Failover.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#include <ETH.h>
#include <PPP.h>
#include <SPI.h>
#include <WiFi.h>
//#include <WiFiGeneric.h>
#include <WiFiMulti.h>
#include <Wire.h>

#include "secrets.h"
#include "base64.h" //Built-in. Needed for NTRIP Client credential encoding.

#define NETWORK_DEBUG_STATE true
#define NETWORK_DEBUG_SEQUENCE true

//----------------------------------------

#define TIME_ZONE_HOURS -10
#define TIME_ZONE_MINUTES 0
#define TIME_ZONE_SECONDS 0

#define DELAY_SEC(s) (s * 1000)
#define DELAY_MIN(m) (60 * DELAY_SEC(m))
#define DELAY_HR(h) (60 * DELAY_MIN(h))

//----------------------------------------

bool debugCorrections = false;
bool debugNtripClientRtcm = false;
bool debugNtripClientState = true;
const char * platformPrefix = "EVK";

//----------------------------------------

#include <SparkFun_u-blox_GNSS_v3.h> //http://librarymanager/All#SparkFun_u-blox_GNSS_v3
SFE_UBLOX_GNSS myGNSS;
bool gnssOnline;
bool gnssClientUnitsFeetInches = true;

float gnssHorizontalAccuracy;
double gnssLatitude;
double gnssLongitude;

float gnssAltitude;

uint8_t gnssDay;
uint8_t gnssMonth;
uint16_t gnssYear;
uint8_t gnssHour;
uint8_t gnssMinute;
uint8_t gnssSecond;
int32_t gnssNanosecond;
uint16_t gnssMillisecond; // Limited to first two digits

uint8_t gnssSatellitesInView;
uint8_t gnssFixType;
uint8_t gnssCarrierSolution;

bool gnssValidDate;
bool gnssValidTime;
bool gnssConfirmedDate;
bool gnssConfirmedTime;
bool gnssFullyResolved;
uint32_t gnssTAcc;

bool RTK_CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC = false;

#define MILLIMETERS_PER_INCH 25.4
#define MILLIMETERS_PER_FOOT (MILLIMETERS_PER_INCH * 12.)

//----------------------------------------

const int SDA_1 = 21; // ZED-F9P and NEO-D9S
const int SCL_1 = 22; // ZED-F9P and NEO-D9S

TwoWire I2C_1 = TwoWire(0);

WiFiMulti wifiMulti;

const int ETHERNET_CS = 27; // Chip select for the WizNet W5500
const int PWREN = 32; // 74HC4066 switch Enable - pull high to enable SCL2/SDA2 and GNSS_INT
const int ETHERNET_INT = 39; // WizNet W5500 interrupt

#define ETH_PHY_TYPE ETH_PHY_W5500
#define ETH_PHY_ADDR 0
#define ETH_PHY_CS ETHERNET_CS
#define ETH_PHY_IRQ ETHERNET_INT
#define ETH_PHY_RST -1

#define ETH_SPI_SCK 18
#define ETH_SPI_MISO 19
#define ETH_SPI_MOSI 23

//----------------------------------------
// RTK EVK hardware pins

// Power control
#define PWREN 32

// LARA pins
#define CELLULAR_CTS -1
#define CELLULAR_RTS -1
#define CELLULAR_RX 14
#define CELLULAR_TX 13
#define LARA_PWR 26

#define CELLULAR_MODEM_RST_LOW false //active HIGH

#define CELLULAR_RST 26 // Using the power pin as reset

// LARA R6001D no flow control
#define CELLULAR_MODEM_FC ESP_MODEM_FLOW_CONTROL_NONE

//----------------------------------------

#define NTRIP_CLIENT_PUSHING_RTCM ntripClientIsPushingRtcm()

//----------------------------------------

typedef void (* NETWORK_POLL_ROUTINE)(uint8_t priority, uintptr_t parameter, bool debug);

typedef struct _NETWORK_POLL_SEQUENCE
{
NETWORK_POLL_ROUTINE routine; // Address of poll routine, nullptr at end of table
uintptr_t parameter; // Parameter passed to poll routine
const char * description; // Description of operation
} NETWORK_POLL_SEQUENCE;

extern NETWORK_POLL_SEQUENCE laraBootSequence[];
extern NETWORK_POLL_SEQUENCE laraOnSequence[];
extern NETWORK_POLL_SEQUENCE laraOffSequence[];

// Poll routines
void cellularAttached(uint8_t priority, uintptr_t parameter, bool debug);
void cellularSetup(uint8_t priority, uintptr_t parameter, bool debug);
void cellularStart(uint8_t priority, uintptr_t parameter, bool debug);
void networkDelay(uint8_t priority, uintptr_t parameter, bool debug);
void networkStartDelayed(uint8_t priority, uintptr_t parameter, bool debug);

//----------------------------------------

// Network priority entry
typedef struct _NETWORK_PRIORITY
{
NetworkInterface * netif; // Network interface object address
const char * name; // Name of the network interface
NETWORK_POLL_SEQUENCE * boot; // Boot sequence, may be nullptr
NETWORK_POLL_SEQUENCE * start; // Start sequence (Off --> On), may be nullptr
NETWORK_POLL_SEQUENCE * stop; // Stop routine (On --> Off), may be nullptr
} NETWORK_PRIORITY;

typedef uint8_t NetMask_t; // One bit for each network interface

// Network priority listed in decending order
// Multiple networks may running in parallel with highest priority being
// set to the default network. The start routine is called as the priority
// drops to that level. The stop routine is called as the priority rises
// above that level. The priority will continue to fall or rise until a
// network is found that is online.
const NETWORK_PRIORITY networkPriorityTable[] =
{ // Interface Name Boot Sequence Start Sequence Stop Sequence
{&ETH, "Ethernet", nullptr, nullptr, nullptr},
{&PPP, "Cellular", laraBootSequence, laraOnSequence, laraOffSequence},
{&WiFi.STA, "WiFi", nullptr, nullptr, nullptr},
};
const int networkPriorityTableEntries = sizeof(networkPriorityTable) / sizeof(networkPriorityTable[0]);

#define NETWORK_OFFLINE networkPriorityTableEntries

// Network priorities
NetMask_t ethernetPriority = NETWORK_OFFLINE;
NetMask_t cellularPriority = NETWORK_OFFLINE;
NetMask_t wifiPriority = NETWORK_OFFLINE;

// Network support routines
bool networkIsInterfaceOnline(uint8_t priority);
void networkMarkOffline(int priority);
void networkMarkOnline(int priority);
uint8_t networkPriorityGet(NetworkInterface *netif);
void networkPriorityValidation(uint8_t priority);
void networkSequenceBoot(uint8_t priority);
void networkSequenceNextEntry(uint8_t priority);

//----------------------------------------
// System initialization
void setup()
{
delay(1000);

Serial.begin(115200);
Serial.println();

Serial.println("SparkFun EVK Example");

// Listen for modem events
Network.onEvent(networkOnEvent);

// Set LARA_PWR low
// LARA_PWR is inverted by the RTK EVK level-shifter
// High 'pushes' the LARA PWR_ON pin, toggling the power
// Configure the pin here as PPP doesn't configure _pin_rst until .begin is called
pinMode(LARA_PWR, OUTPUT);
digitalWrite(LARA_PWR, LOW);

// Now enable the 3.3V regulators for the GNSS and LARA
pinMode(PWREN, OUTPUT);
digitalWrite(PWREN, HIGH);

// Start I2C. Connect to the GNSS.
I2C_1.begin((int)SDA_1, (int)SCL_1); //Start I2C

delay(2000); // Wait for the power to stabilize

// Initialize the network interfaces
ethernetSetup();
wifiSetup();
laraSetup();

// Start the GNSS device
gnssSetup(I2C_1);
}

//----------------------------------------
// Main loop
void loop()
{
networkPoll();
ntripClientUpdate();
gnssUpdate();
gnssDisplayLocation(5 * 1000);
}
Loading

0 comments on commit 9e1f016

Please sign in to comment.