diff --git a/Example_Sketches/9_2_PPP_State_Machine/9_2_PPP_State_Machine.ino b/Example_Sketches/9_2_PPP_State_Machine/9_2_PPP_State_Machine.ino new file mode 100644 index 0000000..da39a2b --- /dev/null +++ b/Example_Sketches/9_2_PPP_State_Machine/9_2_PPP_State_Machine.ino @@ -0,0 +1,67 @@ +#include + +//---------------------------------------- + +#define ARDUINO_EVENT_LARA_ON ((arduino_event_id_t)-1) + +//---------------------------------------- + +typedef bool (* IS_CONNECTED)(); + +//---------------------------------------- + +typedef struct _HTTP_CLIENT_CONNECTION +{ + IS_CONNECTED isInternetAvailable; + const char * hostName; + const char * url; + + // The following parameters are initialized to zero (false) + bool suppressFirstPageOutput; + NetworkClient client; + int headerLength; + int pageLength; + uint8_t hccState; + bool tagEndFound; + int tagEndOffset; + bool tagStartFound; + int tagStartOffset; + uint32_t timer; + uint8_t buffer[2048]; +} HTTP_CLIENT_CONNECTION; + +HTTP_CLIENT_CONNECTION google; +HTTP_CLIENT_CONNECTION SparkFun; + +//---------------------------------------- +// System initialization +void setup() +{ + Serial.begin(115200); + + // Initialize the network + Network.onEvent(networkOnEvent); + + // Set the HTTPS parameters + google.hostName = "www.google.com"; + google.url = "/"; + google.isInternetAvailable = pppIsInternetAvailable; +// google.suppressFirstPageOutput = true; + + SparkFun.hostName = "www.SparkFun.com"; + SparkFun.url = "/"; + SparkFun.isInternetAvailable = pppIsInternetAvailable; +// SparkFun.suppressFirstPageOutput = true; + + // Start LARA + pppEvent(ARDUINO_EVENT_LARA_ON); +} + +//---------------------------------------- +// Main loop +void loop() +{ + pppUpdate(); + httpUpdate(&google, 80, 15 * 1000); + httpUpdate(&SparkFun, 80, 16 * 1000); +} diff --git a/Example_Sketches/9_2_PPP_State_Machine/HTTP.ino b/Example_Sketches/9_2_PPP_State_Machine/HTTP.ino new file mode 100644 index 0000000..f649d30 --- /dev/null +++ b/Example_Sketches/9_2_PPP_State_Machine/HTTP.ino @@ -0,0 +1,178 @@ +//---------------------------------------- + +enum HTTP_STATE +{ + HTTP_STATE_WAIT_NETWORK = 0, + HTTP_STATE_CONNECT_HOST, + HTTP_STATE_WAIT_RESPONSE, + HTTP_STATE_READ_PAGE, + HTTP_STATE_CLOSE_PAGE, + HTTP_STATE_INIT_DELAY, + HTTP_STATE_DELAY, +}; + +//---------------------------------------- +// Read the www.google.com web-page +void httpUpdate(HTTP_CLIENT_CONNECTION * hcc, uint16_t portNumber, uint32_t delayMsec) +{ + int bytesRead; + int dataBytes; + const char * tagEnd = ""; + const char * tagStart = "hccState) + { + // Wait for the PPP connection + case HTTP_STATE_WAIT_NETWORK: + if (hcc->isInternetAvailable()) + hcc->hccState = HTTP_STATE_CONNECT_HOST; + break; + + // Connect to Google + case HTTP_STATE_CONNECT_HOST: + // Has the network failed + if (!hcc->isInternetAvailable()) + { + hcc->hccState = HTTP_STATE_WAIT_NETWORK; + break; + } + + // Connect to the remote host + if (!hcc->client.connect(hcc->hostName, portNumber)) + { + Serial.printf("Connection to %s:%d failed!\r\n", hcc->hostName, portNumber); + hcc->hccState = HTTP_STATE_INIT_DELAY; + } + else + { + Serial.printf("Connection to %s:%d successful\r\n", hcc->hostName, portNumber); + + // Request the web page + hcc->client.printf("GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", hcc->url, hcc->hostName); + + // No data read yet + hcc->headerLength = 0; + hcc->pageLength = 0; + hcc->tagEndFound = false; + hcc->tagEndOffset = 0; + hcc->tagStartFound = false; + hcc->tagStartOffset = 0; + hcc->hccState = HTTP_STATE_WAIT_RESPONSE; + } + break; + + case HTTP_STATE_WAIT_RESPONSE: + // Has the network failed or the connection closed + if ((!hcc->isInternetAvailable()) || (!hcc->client.connected())) + { + hcc->hccState = HTTP_STATE_CLOSE_PAGE; + break; + } + + // Wait for the response + if (hcc->client.available()) + hcc->hccState = HTTP_STATE_READ_PAGE; + break; + + // Read the web-page + case HTTP_STATE_READ_PAGE: + // Has the network failed or the connection closed + if ((!hcc->isInternetAvailable()) || (!hcc->client.connected())) + { + hcc->hccState = HTTP_STATE_CLOSE_PAGE; + break; + } + + // Check for end-of-file + dataBytes = hcc->client.available(); + if (hcc->tagEndFound && (!dataBytes)) + { + hcc->suppressFirstPageOutput = true; + hcc->hccState = HTTP_STATE_CLOSE_PAGE; + } + + // Determine if data was received + else if (dataBytes > 0) + { + // Read as much data as possible + if (dataBytes > sizeof(hcc->buffer)) + dataBytes = sizeof(hcc->buffer); + bytesRead = hcc->client.read(hcc->buffer, dataBytes); + + // Check for a read error + if (bytesRead < 0) + { + Serial.println("\r\n\nRead error!"); + hcc->hccState = HTTP_STATE_CLOSE_PAGE; + break; + } + + // Display the web page on the first pass + if (!hcc->suppressFirstPageOutput) + Serial.write(hcc->buffer, bytesRead); + + // Check for the start-of-page + dataBytes = 0; + if (!hcc->tagStartFound) + { + for (; dataBytes < bytesRead; dataBytes++) + if ((!hcc->tagStartFound) && (hcc->buffer[dataBytes] == tagStart[hcc->tagStartOffset])) + { + hcc->tagStartOffset += 1; + hcc->tagStartFound = (hcc->tagStartOffset == strlen(tagStart)); + if (hcc->tagStartFound) + { + hcc->headerLength = hcc->pageLength + + dataBytes + - strlen(tagStart); + dataBytes += 1; + hcc->pageLength = - (dataBytes + strlen(tagStart)); + break; + } + } + else + hcc->tagStartOffset = 0; + } + + // Account for the data read + hcc->pageLength += bytesRead; + + // Check for the end-of-page + if (hcc->tagStartFound) + { + for (; dataBytes < bytesRead; dataBytes++) + if ((!hcc->tagEndFound) && (hcc->buffer[dataBytes] == tagEnd[hcc->tagEndOffset])) + { + hcc->tagEndOffset += 1; + hcc->tagEndFound = (hcc->tagEndOffset == strlen(tagEnd)); + } + else + hcc->tagEndOffset = 0; + } + } + break; + + // Close the socket + case HTTP_STATE_CLOSE_PAGE: + // Done with this network client + Serial.printf("\rRead %d header bytes and %d page bytes from %s\r\n", + hcc->headerLength, hcc->pageLength, hcc->hostName); + hcc->client.stop(); + hcc->hccState = HTTP_STATE_INIT_DELAY; + break; + + // Start the delay + case HTTP_STATE_INIT_DELAY: + Serial.println("----------"); + hcc->timer = millis(); + hcc->hccState = HTTP_STATE_DELAY; + break; + + // Delay for a while + case HTTP_STATE_DELAY: + // Delay before attempting again + if ((millis() - hcc->timer) >= delayMsec) + hcc->hccState = HTTP_STATE_WAIT_NETWORK; + break; + } +} diff --git a/Example_Sketches/9_2_PPP_State_Machine/Network.ino b/Example_Sketches/9_2_PPP_State_Machine/Network.ino new file mode 100644 index 0000000..59a0504 --- /dev/null +++ b/Example_Sketches/9_2_PPP_State_Machine/Network.ino @@ -0,0 +1,23 @@ +//---------------------------------------- +// Process network events +void networkOnEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + IPAddress ipv4; + + switch (event) + { + default: + if (event != ARDUINO_EVENT_PPP_GOT_IP6) + Serial.printf("ERROR: Unknown Arduino event: %d\r\n", event); + break; + + case ARDUINO_EVENT_PPP_START: + case ARDUINO_EVENT_PPP_CONNECTED: + case ARDUINO_EVENT_PPP_GOT_IP: + case ARDUINO_EVENT_PPP_LOST_IP: + case ARDUINO_EVENT_PPP_DISCONNECTED: + case ARDUINO_EVENT_PPP_STOP: + pppEvent(event); + break; + } +} diff --git a/Example_Sketches/9_2_PPP_State_Machine/PPP.ino b/Example_Sketches/9_2_PPP_State_Machine/PPP.ino new file mode 100644 index 0000000..2431ef4 --- /dev/null +++ b/Example_Sketches/9_2_PPP_State_Machine/PPP.ino @@ -0,0 +1,207 @@ +//---------------------------------------- + +// Power control +#define PWREN 32 + +// LARA pins +#define LARA_RST 26 // Using the power pin as reset +#define LARA_TX 13 +#define LARA_RX 14 +#define LARA_RTS -1 +#define LARA_CTS -1 + +// LARA R6001D no flow control +#define PPP_MODEM_RST_LOW false //active HIGH +#define PPP_MODEM_FC ESP_MODEM_FLOW_CONTROL_NONE +#define PPP_MODEM_MODEL PPP_MODEM_GENERIC + +#define PPP_MODEM_APN "internet" +#define PPP_MODEM_PIN NULL // Personal Identification Number: String in double quotes + +//---------------------------------------- + +// PPP states +enum PPP_STATES +{ + PPP_STATE_LARA_OFF = 0, // LARA powered off or being reset + PPP_STATE_LARA_ON, // LARA powered on and out of reset + PPP_STATE_MOBILE_NETWORK, // Connect to the mobile network + PPP_STATE_ATTACHED, // Attached to a mobile network + PPP_STATE_GOT_IP, // Got an IP address + PPP_STATE_CONNECTED, // Connected to the internet +}; + +//---------------------------------------- + +static uint8_t pppState; +static uint32_t pppTimer; +bool pppOnline; + +//---------------------------------------- +// Determine if the PPP link is connected to the internet +bool pppIsInternetAvailable() +{ + return pppOnline; +} + +//---------------------------------------- +// Perform PPP polling +void pppUpdate() +{ + switch (pppState) + { + case PPP_STATE_MOBILE_NETWORK: + if ((millis() - pppTimer) >= 100) + { + pppTimer = millis(); + if (PPP.attached()) + { + Serial.println("Attached to moble network"); + Serial.print(" State: "); + Serial.println(PPP.radioState()); + Serial.print(" Operator: "); + Serial.println(PPP.operatorName()); + Serial.print(" IMSI: "); + Serial.println(PPP.IMSI()); + Serial.print(" RSSI: "); + Serial.println(PPP.RSSI()); + int ber = PPP.BER(); + if (ber > 0) + { + Serial.print(" BER: "); + Serial.println(ber); + } + Serial.println("Switching to data mode..."); + pppOnline = false; + pppState = PPP_STATE_ATTACHED; + PPP.mode(ESP_MODEM_MODE_CMUX); // Data and Command mixed mode + } + } + break; + } +} + +//---------------------------------------- +// Update the PPP state due to an event +void pppEvent(arduino_event_id_t event) +{ + switch (pppState) + { + default: + Serial.printf("ERROR: Bad PPP state, %d\r\n", pppState); + break; + + case PPP_STATE_LARA_OFF: + 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); + + // Now enable the 3.3V regulators for the GNSS and LARA + pinMode(PWREN, OUTPUT); + digitalWrite(PWREN, HIGH); + + Serial.println("Starting the modem. It might take a while!"); + pppState = PPP_STATE_LARA_ON; + pppOnline = false; + PPP.begin(PPP_MODEM_MODEL); + } + break; + + case PPP_STATE_LARA_ON: + if (event == ARDUINO_EVENT_PPP_START) + { + Serial.println("PPP Started"); + Serial.print(" Manufacturer: "); + Serial.println(PPP.cmd("AT+CGMI", 10000)); + Serial.print(" Model: "); + Serial.println(PPP.moduleName()); + Serial.print(" IMEI: "); + Serial.println(PPP.IMEI()); + pppOnline = false; + pppState = PPP_STATE_MOBILE_NETWORK; + } + else if (event == ARDUINO_EVENT_PPP_STOP) + { + Serial.println("PPP Stopped"); + pppOnline = false; + pppState = PPP_STATE_LARA_OFF; + } + break; + + case PPP_STATE_ATTACHED: + if (event == ARDUINO_EVENT_PPP_GOT_IP) + { + IPAddress ipv4 = PPP.localIP(); + Serial.print("PPP Got IP: "); + Serial.print(ipv4); + Serial.println(); + pppOnline = false; + pppState = PPP_STATE_GOT_IP; + } + else if (event == ARDUINO_EVENT_PPP_DISCONNECTED) + { + Serial.println("PPP Disconnected"); + pppOnline = false; + pppState = PPP_STATE_MOBILE_NETWORK; + } + else if (event == ARDUINO_EVENT_PPP_STOP) + { + Serial.println("PPP Stopped"); + pppOnline = false; + pppState = PPP_STATE_LARA_OFF; + } + break; + + case PPP_STATE_GOT_IP: + if (event == ARDUINO_EVENT_PPP_CONNECTED) + { + Serial.println("PPP Connected"); + pppOnline = true; + pppState = PPP_STATE_CONNECTED; + } + else if (event == ARDUINO_EVENT_PPP_LOST_IP) + { + Serial.println("PPP Lost IP"); + pppOnline = false; + pppState = PPP_STATE_ATTACHED; + } + else if (event == ARDUINO_EVENT_PPP_DISCONNECTED) + { + Serial.println("PPP Disconnected"); + pppOnline = false; + pppState = PPP_STATE_MOBILE_NETWORK; + } + else if (event == ARDUINO_EVENT_PPP_STOP) + { + Serial.println("PPP Stopped"); + pppOnline = false; + pppState = PPP_STATE_LARA_OFF; + } + break; + + case PPP_STATE_CONNECTED: + if (event == ARDUINO_EVENT_PPP_LOST_IP) + { + Serial.println("PPP Lost IP"); + pppOnline = false; + pppState = PPP_STATE_ATTACHED; + } + else if (event == ARDUINO_EVENT_PPP_DISCONNECTED) + { + Serial.println("PPP Disconnected"); + pppOnline = false; + pppState = PPP_STATE_ATTACHED; + } + else if (event == ARDUINO_EVENT_PPP_STOP) + { + Serial.println("PPP Stopped"); + pppOnline = false; + pppState = PPP_STATE_LARA_OFF; + } + break; + } +} diff --git a/Example_Sketches/9_2_PPP_State_Machine/makefile b/Example_Sketches/9_2_PPP_State_Machine/makefile new file mode 100644 index 0000000..09a539f --- /dev/null +++ b/Example_Sketches/9_2_PPP_State_Machine/makefile @@ -0,0 +1,137 @@ +###################################################################### +# makefile +# +# Builds the example +###################################################################### + +########## +# Source files +########## + +EXAMPLE_SKETCH=9_2_PPP_State_Machine + +EXECUTABLES += example + +PARTITION_CSV_FILE=RTKEverywhere + +ifeq ($(OS),Windows_NT) +# Windows NT utilities +CLEAR=cls +COPY=copy +DELETE=rmdir /s +DIR_LISTING=dir +TERMINAL_APP= +TERMINAL_PARAMS= + +# Windows NT generic paths +USER_DIRECTORY_PATH=C:\Users\$(USERNAME) +ARDUINO_LIBRARY_PATH=$(USER_DIRECTORY_PATH)\Documents\Arduino\libraries +HOME_BOARD_PATH=$(USER_DIRECTORY_PATH)\AppData\Local\Arduino15\packages\esp32 +PATCH_SRC_PATH=Patch\ + +# Windows NT patch source paths +PARTITION_SRC_PATH=..\$(PARTITION_CSV_FILE).csv +PATCH_SRC_PATH=Patch\ + +# Windows NT patch destination paths +BLE_PATCH_DST_PATH=$(ARDUINO_LIBRARY_PATH)\ESP32_BleSerial\src\ +MBED_LIB_DEST_PATH=$(HOME_BOARD_PATH)\tools\esp32-arduino-libs\${{ env.ESP_IDF }}\esp32/lib\ +PARTITION_DST_PATH=$(HOME_BOARD_PATH)\hardware\esp32\$(ESP_CORE_VERSION)\tools\partitions\$(PARTITION_CSV_FILE).csv + +else +# Linux utilities +CLEAR=clear +COPY=cp +DELETE=rm -Rf +DIR_LISTING=ls +TERMINAL_APP=minicom +TERMINAL_PARAMS=-b 115200 -8 -D /dev/ttyUSB0 < /dev/tty + +# Linux generic paths +USER_DIRECTORY_PATH=~ +ARDUINO_LIBRARY_PATH=$(USER_DIRECTORY_PATH)/Arduino/libraries +ESP_IDF_PATH=$(HOME_BOARD_PATH)/tools/esp32-arduino-libs +HOME_BOARD_PATH=$(USER_DIRECTORY_PATH)/.arduino15/packages/esp32 + +# Linux patch source paths +PARTITION_SRC_PATH=../$(PARTITION_CSV_FILE).csv +PATCH_SRC_PATH=Patch/ + +# Linux patch destination paths +BLE_PATCH_DST_PATH=$(ARDUINO_LIBRARY_PATH)/ESP32_BleSerial/src/ +MBED_LIB_DEST_PATH=$(ESP_IDF_PATH)/$(ESP_IDF_VERSION)/esp32/lib/ +PARTITION_DST_PATH=$(HOME_BOARD_PATH)/hardware/esp32/$(ESP_CORE_VERSION)/tools/partitions/$(PARTITION_CSV_FILE).csv + +endif + +########## +# Buid all the sources - must be first +########## + +.PHONY: all + +all: $(EXECUTABLES) + +########## +# Add ESP32 board support +########## + +.PHONY: arduino-config + +arduino-config: + arduino-cli config init --overwrite --additional-urls "https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json" + +########## +# Build an example +########## + +.PHONY: example + +example: build/esp32.esp32.esp32/$(EXAMPLE_SKETCH).ino.bin + +DEBUG_LEVEL=none +#DEBUG_LEVEL=debug + +build/esp32.esp32.esp32/$(EXAMPLE_SKETCH).ino.bin: $(EXAMPLE_SKETCH).ino *.ino makefile + $(CLEAR) + arduino-cli compile --fqbn "esp32:esp32:esp32":DebugLevel=$(DEBUG_LEVEL),PSRAM=enabled $< \ + --warnings default \ + --build-property build.partitions=$(PARTITION_CSV_FILE) \ + --build-property upload.maximum_size=6291456 \ + --build-property "compiler.cpp.extra_flags=-MMD -c \"-DPOINTPERFECT_TOKEN=$(POINTPERFECT_TOKEN)\" \"-DFIRMWARE_VERSION_MAJOR=$(FIRMWARE_VERSION_MAJOR)\" \"-DFIRMWARE_VERSION_MINOR=$(FIRMWARE_VERSION_MINOR)\" \"-DENABLE_DEVELOPER=$(ENABLE_DEVELOPER)\"" \ + --export-binaries + +########## +# Upload the example +########## + +ESPTOOL_PATH=~/Arduino/hardware/espressif/esp32/tools/esptool +TERMINAL_PORT="/dev/ttyUSB0" +BOOT_LOADER_PATH=~/SparkFun/SparkFun_RTK_Firmware_Uploader/RTK_Firmware_Uploader/resource + +.PHONY: upload + +upload: build/esp32.esp32.esp32/$(EXAMPLE_SKETCH).ino.bin + python3 $(ESPTOOL_PATH)/esptool.py \ + --chip esp32 \ + --port $(TERMINAL_PORT) \ + --baud 921600 \ + --before default_reset \ + --after hard_reset \ + write_flash \ + --flash_mode dio \ + --flash_freq 80m \ + --flash_size detect \ + --compress \ + 0x1000 $(BOOT_LOADER_PATH)/RTK_Surveyor.ino.bootloader.bin \ + 0x8000 $(BOOT_LOADER_PATH)/RTK_Surveyor_Partitions_16MB.bin \ + 0xe000 $(BOOT_LOADER_PATH)/boot_app0.bin \ + 0x10000 $< + $(TERMINAL_APP) $(TERMINAL_PARAMS) + +########## +# Clean up the example +########## + +clean: + $(DELETE) build