// ESP8266_NMEA_BRIDGE_noCfg // This version of the ESP8266_NMEA_BRIDGE has hardcoded config // to connect to your local rounter with a fixed IP // and to be a server for the NMEA data via TCP on port 10110 and UDP 230.1.1.1 port 10110 /* (c)2020 Forward Computing and Control Pty. Ltd. NSW Australia, www.forward.com.au This code is not warranted to be fit for any purpose. You may only use it at your own risk. This code may be freely used for both private and commercial use Provide this copyright is maintained. */ // On ESP8266-01 and Adafruit HAZZAH ESP8266, connect LED + 270ohm resistor from D2 (GPIO2) to +3V3 to indicate when in config mode #include #include #include #include #include #include #include "SafeString.h" #include "millisDelay.h" // ================= HARD CODED CONFIG ================== const char ssid[] = "yourRouterSSID"; // set your network's SSID here const char password[] = "yourRouterPassword"; // set your network's password here IPAddress staticIP(10, 1, 1, 190); // set NMEA hub static IP here. NOTE the , between the numbers // make sure no other device is running with this same IP and that the IP is in your router IP range // common router IP ranges are 10.1.1.2 to 10.1.1.254 // 192.168.1.2 to 192.168.254.254 and // 172.16.1.2 to 172.31.254.254 // the router is usually 10.1.1.1 or 192.168.1.1 or 172.16.1.1 depending on its range IPAddress udpBroadcaseIP(230, 1, 1, 1); // set the UDP broadcast IP here. NOTE the , between the numbers. This IP is independent of the router range do not change const uint16_t tcpPortNo = 10110; // set NMEA tcp server port No here const uint16_t udpPortNo = 10110; // set NMEA UDP broadcast port No here const unsigned int txPower = 10; // TX power in range 0 to 82; const unsigned int GPS_BAUD_RATE = 4800; // the Serial baud rate of you GPS module // ================= END OF HARD CODED CONFIG ============== // Arduino Monitor input must be set to Newline (or CR and NL) !!! createSafeString(NMEAstr, 255); // max NMEA msg length is 82 so 255 is plenty // comment this out to remove UDP broadcast #define UDP_BROADCAST // this connects debugPtr I/O only use while testing leave commented out in final code //#define DEBUG #ifdef DEBUG // uncomment this to connect / disconnect messages on debugPtr out. #define CONNECTION_MESSAGES #endif WiFiServer tcpServer(tcpPortNo); //forward declarations void sendUDP(const char* str); void setupAP(const char* ssid_wifi, const char* password_wifi); Stream* debugPtr = NULL; #define MAX_SRV_CLIENTS 5 WiFiClient tcpServerClients[MAX_SRV_CLIENTS]; bool tcpClientConnected[MAX_SRV_CLIENTS]; pfodESP8266BufferedClient* bufferedClients[MAX_SRV_CLIENTS]; // buffers for each client pfodESP8266BufferedClient bufferedClient0; pfodESP8266BufferedClient bufferedClient1; pfodESP8266BufferedClient bufferedClient2; pfodESP8266BufferedClient bufferedClient3; pfodESP8266BufferedClient bufferedClient4; // must match MAX_SRV_CLIENTS-1 #ifdef UDP_BROADCAST WiFiUDP udp; #endif // UDP_BROADCAST #define SerialGPS Serial // GPS/AIS or other device connected to the ESP UART #define SerialDebug Serial1 // Serial1 Debug goes out on GPIO02, // use Serial for testing via Arduino IDE monitor with no GPS connected // if Serial used then baud rate is set to 38400 void setup() { //start UART. Be sure to set the speed to match the speed of whatever is //connected to the UART. SerialGPS.begin(GPS_BAUD_RATE); #ifdef DEBUG SerialDebug.begin(38400); // start another serial if you have separate debug out debugPtr = &SerialDebug; #endif if (debugPtr) { SafeString::setOutput(SerialDebug); } // Initialise wifi module #ifdef DEBUG debugPtr->println(); debugPtr->println(F("Connecting to AP")); debugPtr->print("ssid '"); debugPtr->print(ssid); debugPtr->println("'"); debugPtr->print("password '"); debugPtr->print(password); debugPtr->println("'"); #endif IPAddress gateway(staticIP[0], staticIP[1], staticIP[2], 1); // set gatway to ... 1 #ifdef DEBUG debugPtr->print(F("Setting gateway to: ")); debugPtr->println(gateway); #endif IPAddress subnet(255, 255, 255, 0); WiFi.config(staticIP, gateway, subnet); WiFi.mode(WIFI_STA); // WiFi.persistent(false); delay(10); float tx_dB = float(txPower) / 4.0f; WiFi.setOutputPower(tx_dB); if (debugPtr) { debugPtr->print(F("Tx Power set to ")); debugPtr->println(txPower); } if (debugPtr) { debugPtr->println(); for (int i = 10; i > 0; i--) { delay(1000); debugPtr->print(i); debugPtr->print(' '); } debugPtr->println(); debugPtr->println(F("Starting NMEA to WiFi Bridge")); } WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); #ifdef DEBUG debugPtr->print("."); #endif } #ifdef DEBUG debugPtr->println(); debugPtr->println(F("Connected!")); #endif for (int i = 0; i < MAX_SRV_CLIENTS ; i++) { tcpClientConnected[i] = false; } bufferedClients[0] = &bufferedClient0; bufferedClients[1] = &bufferedClient1; bufferedClients[2] = &bufferedClient2; bufferedClients[3] = &bufferedClient3; bufferedClients[4] = &bufferedClient4; // must match MAX_SRV_CLIENTS -1 // Start listening for connections tcpServer.begin(); tcpServer.setNoDelay(true); // does not do much if anything if (debugPtr) { debugPtr->println(F("TCP Server Started")); // Print the IP address debugPtr->print(WiFi.localIP()); debugPtr->print(':'); debugPtr->println(tcpPortNo); debugPtr->println(F("Listening for connections...")); } #ifdef UDP_BROADCAST if (debugPtr) { debugPtr->println(F("UDP Server Started")); // Print the IP address debugPtr->print(udpBroadcaseIP); debugPtr->print(':'); debugPtr->println(udpPortNo); } #endif // UDP_BROADCAST if (debugPtr) { debugPtr->print(F("Input baud rate is ")); debugPtr->println(GPS_BAUD_RATE); } } void loop() { // check for full buffers to send to TCP for (int i = 0; i < MAX_SRV_CLIENTS; i++) { bufferedClients[i]->available(); // checks for send timeout } // check for still connected for (int i = 0; i < MAX_SRV_CLIENTS; i++) { //find free/disconnected spot if (tcpClientConnected[i] && (!tcpServerClients[i].connected())) { if (debugPtr) { debugPtr->print("closed client:"); debugPtr->println(i); } tcpServerClients[i].stop(); bufferedClients[i]->stop(); tcpClientConnected[i] = false; } } // look for new clients connecting if (tcpServer.hasClient()) { #ifdef CONNECTION_MESSAGES if (debugPtr) { debugPtr->println("Have client"); } #endif bool foundSlot = false; for (int i = 0; i < MAX_SRV_CLIENTS; i++) { //find free/disconnected spot if (!tcpServerClients[i] || !tcpServerClients[i].connected()) { foundSlot = true; if (tcpServerClients[i]) { tcpServerClients[i].stop(); } tcpServerClients[i] = tcpServer.available(); tcpServerClients[i].setNoDelay(true); // does not do much if anything bufferedClients[i]->stop(); // clean up bufferedClients[i]->connect(&(tcpServerClients[i])); tcpClientConnected[i] = true; #ifdef CONNECTION_MESSAGES if (debugPtr) { debugPtr->print("New client: "); debugPtr->println(i); } #endif break; } } if (!foundSlot) { // drop some other client?? perhaps have half closed connection problem if (debugPtr) { debugPtr->println("No free slots for this client close last one."); } WiFiClient tcpClient = tcpServer.available(); tcpServerClients[MAX_SRV_CLIENTS - 1].stop(); bufferedClients[MAX_SRV_CLIENTS - 1]->stop(); // clean up tcpServerClients[MAX_SRV_CLIENTS - 1] = tcpClient; tcpServerClients[MAX_SRV_CLIENTS - 1].setNoDelay(true); // does not do much if anything bufferedClients[MAX_SRV_CLIENTS - 1]->connect(&(tcpServerClients[MAX_SRV_CLIENTS - 1])); if (debugPtr) { debugPtr->print("Closed "); debugPtr->print(MAX_SRV_CLIENTS - 1); debugPtr->println(" and reused"); } } } // check for incoming data to reset timer for (int i = 0; i < MAX_SRV_CLIENTS; i++) { if (tcpClientConnected[i] && tcpServerClients[i].connected()) { //get data from the telnet client and push it to the UART while ((bufferedClients[i]->available()) && (SerialGPS.availableForWrite() > 0)) { // use SerialGPS.availableForWrite to prevent loosing incoming data SerialGPS.write(bufferedClients[i]->read()); // NMEA I/O delay(0); } } } // handle input // read into SafeString until get terminator // filter (to be done) // write out to TCP and UDP if (NMEAstr.readUntil(SerialGPS, "\n")) { // non-blocking read // found \n in input so process line bool endsWithNL = NMEAstr.endsWith("\n"); NMEAstr.trim(); // remove leading and trailing white space if (!NMEAstr.isEmpty()) { // skip empty lines if (endsWithNL) { NMEAstr += "\r\n"; // add back terminators NMEA mgs should end with } // else just buffer full // add filtering here !!! // ... // if line passes add to TCP connections const char* str = NMEAstr.c_str(); size_t str_len = NMEAstr.length(); for (int i = 0; i < MAX_SRV_CLIENTS; i++) { if (tcpServerClients[i] && tcpServerClients[i].connected()) { //get data from the telnet client and push it to the UART bufferedClients[i]->write((const uint8_t*)str, str_len); delay(0); } } // send to UDP broadcast if enabled sendUDP(str); // does nothing if not enabled NMEAstr.clear(); // finished with this line } } } void sendUDP(const char* str) { #ifdef UDP_BROADCAST if (debugPtr) { debugPtr->print("sendUDP : "); debugPtr->println(str); } udp.beginPacketMulticast(udpBroadcaseIP, udpPortNo, staticIP); udp.write(str); udp.endPacket(); #endif // UDP_BROADCAST }