I run on solar panels so I will not take to much time with the computer connected. Here are the starting lines of the multiplexer code
Code: Select all
/*
ESP32NMEA4WIFI is a multiplexer that reads 4 serial NMEA 0183 ports and outputs the combination
through WIFI and (or) through an output serial port. Incoming WIFI can also be sent over the
serial output port. The output serial port is "parallel" with an USB port.
UDP and TCP protocols are supported
This software runs on the NodeMCU-32S ESP32 board and can be compiled and uploaded through the
Arduino IDE version 1.8.10 using ESP32 1.0.4 core
More information on www.vela-navega.com/nmea2wifi.html
*/
const char soft_version[ ] = "Firmware Version 3.4";
// version 2.1 corrects filtering with 6 sentences on the filtering
// version 2.2 allows specification of AP IP Address
// version 2.2 corrects the verification of self-test
// version 2.2 corrects TPC > P5 not going false when TCP PORT NUMBER = 0
// version 2.2 now both TCP and UDP can be zero
// version 2.3 hiddens the specification of the AP IP Address
// version 2.4 changes in Self Test - 25uS for the starting test;
// - checks if buffer is empty
// - 40 "U"s instead of 20 "U"s
// version 2.5 corrects SeaTalk1 conversions
// version 2.6 changes udp.println and Nmea_X[] buffer terminations
// corrects AIS is now possible on USB input
// corrects DBT conversion
// version 2.7 adds CR LF to nmea_4 when receiving SeaTalk1
// version 2.8 changes the flags Input_? used in the main loop
// version 2.9 introduces simulation mode and runs now compiled
// with ESP32 core 1.0.4 and Arduino IDE 1.8.10 which
// resolved UDP packet loss on Android
// version 3.2 Include Input flags; improve the acknowledges messages;
// revision of SeaTalk1 conversion; filter = 0 now is more efficient
#include <WiFi.h>
#include <WiFiUdp.h>
#include <WiFiClient.h>
#include <EEPROM.h>
#include <esp_wifi.h>
#include <WebServer.h>
#include <Update.h>
// #define DEBUG // remove this comment to activate debug
#ifdef DEBUG
#define DebugPrint(x) Serial2.print(x)
#define DebugPrintln(x) Serial2.println(x)
#define DebugWrite(x) Serial2.write(x)
#define DebugBegin(x) Serial2.begin(x)
#define DebugDelay(x) delay(x)
#else
#define DebugPrint(x)
#define DebugPrintln(x)
#define DebugWrite(x)
#define DebugBegin(x)
#define DebugDelay(x)
#endif
// GPIO pins for Leds L1 L2 L3 and L4. Led L5 lights automatically when
// transmit pin TX0 (GPIO1) goes LOW
#define LED_PIN_1 12 // diode L1 for input port #1
#define LED_PIN_2 13 // diode L2 for input port #2
#define LED_PIN_3 15 // diode L3 for input port #3
#define LED_PIN_4 5 // diode L4 for input port #4
#define LED_PIN_5 4 // diode L5 for wifi traffic
#define RESET_PIN 0 // GPIO0 it is the Boot Switch on the module
// GPIO pins for receiving UARTs
#define RX_PIN_1 39 // HardwareSerial (1) used on input port #1
#define RX_PIN_2 14 // HardwareSerial (0) used on input port #2
#define RX_PIN_3 36 // Software Serial0_ used on input port #3
#define RX_PIN_4 2 // Software Serial1_ used on input port #4
#define RX_PIN_5A 25 // HardwareSerial (2) not used on output port #5 when IsUSB == false
#define RX_PIN_5B 3 // HardwareSerial (2) used on input/output port #5 when IsUSB == true
// GPIO transmitting pins for hardware UARTs.
#define TX_PIN_1 26 // Hardware Serial (1) fake not used on input port #1
#define TX_PIN_2 27 // Hardware Serial (0) fake not used on input port #2
#define TX_PIN_5 1 // Hardware Serial (2) used on output port #5
boolean IsSeaTalk = false; // flag that indicates if input is SeaTalk1 (true) or Nmea 0183 (false)
boolean Is_ST = false; // clean SeaTalk sentence is being received on port #4
boolean IsUSB = false;
// These are the initialization of serial ports in function StartSerialPorts():
// Serial1.begin(baud1,SERIAL_8N1,RX_PIN_1,TX_PIN_1);
// Serial.begin(baud2,SERIAL_8N1,RX_PIN_2,TX_PIN_2);
// Serial0_begin(RX_PIN_3, rxUART_SIZE, baud3);
// Serial1_begin(RX_PIN_4, rxUART_SIZE, baud4);
// Serial2.begin(baud5,SERIAL_8N1,RX_PIN_5,TX_PIN_5);
#define rxUART_SIZE 256 // size of input buffer for Software Serial Uarts
// eprom0 is read from EEPROM when NMEA4WIFI starts
// ************************************************
byte eprom0;
// if eprom0 == 0xFF enter AP mode using factory settings
// if eprom0 == 0x0F enter AP mode using EEPROM user settings
// if eprom0 == 0x00 enter AP mode using EEPROM user settings and
// try to connect to an existing network as a Client Station
// In April, 28th, 2018 - so when eprom0 is read from EEPROM as 0xFF
// because of a previous Factory Settings it should
// be changed to 0x0F because the system is actually in AP mode
// In October 2018 - if eprom0 is not any of the 3 values it will
// be set to 0xFF. This solves the "first flash problem"
boolean SimMode = false; // if true after SET, the multiplexer enters Simulation mode
boolean DebugMode = false; // if true after SET, the multiplexer enters Debug mode
char ssidAP[16]; // ssid of the network to create in AP mode
char passwordAP[16]; // password for above mode
char ipadAP[16]; // ip address for above mode
char ssidST[16]; // ssid of the network to connect in STA mode
char passwordST[16]; // password for above mode
char ipadST[16]; // ip address for connection in STA mode ("0.0.0.0" means DHCP)
const char s_defAP[ ] = "NMEA4WIFI"; // default or factory values for ssidAP
const char p_defAP[ ] = "12345678"; // and passwordAP
const char s_defST[ ] = "NETWORK_NAME"; // default or factory values for ssidST
const char p_defST[ ] = "12345678"; // passwordST
boolean IsConnected = false; // used when eprom0 == 0x00 to flag connection success
unsigned long timer = 0; // used by the built-in watch dog
unsigned long twdg = 10000; // watchdog interval 10000 means 10s
unsigned long MyAge = 0; // go to sleep when MyAge is 5 minutes if wifi = OFF
boolean IsSleeping = false; // will go true after 5 minutes if wifi is OFF
boolean Blink_ON = false; // to allow blinking on core 0
boolean Led1 = false; // used to blink led1
boolean Led2 = false; // used to blink led2
boolean Led3 = false; // used to blink led3
boolean Led4 = false; // used to blink led4
boolean Led5 = false; // used to blink led5
// start simulation mode definitions
// =================================
unsigned long timer_ais = 0; // used by ais generation
const unsigned long inter_ais = 2000; // ais interval in miliseconds
const int number_ais = 13; // number of AIS sentences (minus 1)
int index_ais = 0;
char ais01[] = "!AIVDM,1,1,,A,13sSO2U000QqTdHFGhnRF1pdP50l,0*4B\r\n";
char ais02[] = "!AIVDM,1,1,,A,1=T0M4U000QqTqlFGkAdq:DFP50l,0*04\r\n";
char ais03[] = "!AIVDM,1,1,,A,13sSO2U000QqTdHFGhnRF1pfP50l,0*49\r\n";
char ais04[] = "!AIVDM,1,1,,A,1=T0M4U000QqTqlFGkAdq:DJP50l,0*08\r\n";
char ais05[] = "!AIVDM,1,1,,A,13sSO2U000QqTdHFGhnRF1phP50l,0*47\r\n";
char ais06[] = "!AIVDM,1,1,,A,1=T0M4U000QqTqlFGkAdq:DLP50l,0*0E\r\n";
char ais07[] = "!AIVDM,1,1,,A,13sSO2U000QqTdHFGhnRF1pjP50l,0*45\r\n";
char ais08[] = "!AIVDM,1,1,,A,1=T0M4U000QqTqlFGkAdq:DLP50l,0*0E\r\n";
char ais09[] = "!AIVDM,1,1,,A,13sSO2U000QqTdHFGhnRF1plP50l,0*43\r\n";
char ais10[] = "!AIVDM,1,1,,A,1=T0M4U000QqTqlFGkAdq:DNP50l,0*0C\r\n";
char ais11[] = "!AIVDM,2,1,0,A,53sSO2T2qo;0=87SS;L8D5Dl58U>22222222220T,0*1B\r\n";
char ais12[] = "!AIVDM,2,2,0,A,10413396n4Q1APEC588888888888882,2*0D\r\n";
char ais13[] = "!AIVDM,2,1,0,A,5=T0M4T2JU59UCKO;R0L4hD4v22222222222220T,0*7E\r\n";
char ais14[] = "!AIVDM,2,2,0,A,104132Vi>511APEC588888888888882,2*0D\r\n";
char * ais[] = { ais01, ais02, ais03, ais04, ais05, ais06, ais07,
ais08, ais09, ais10, ais11, ais12, ais13, ais14 };
// now the NMEA 0183 sentences
unsigned long timer_nmea = 0; // used by Nmea generation
const unsigned long inter_nmea = 120; // Nmea interval in miliseconds
const int number_nmea = 24; // number of Nmea sentences (minus 1)
int index_nmea = 0;
char nmea01[] = "$GPRMC,120000.03,A,3905.84900,N,02633.42800,E,0000.0,330.0,011019,0.0,W,A,S*60\r\n";
//char nmea01[] = "$GPGLL,3905.84900,N,02633.42800,E,232131.98,A,A*68\r\n";
char nmea02[] = "$IIDBT,13.1,f,04.0,M,02.2,F*26\r\n";
char nmea03[] = "$IIVHW,330.0,T,330.0,M,00.0,N,00.0,K*55\r\n";
char nmea04[] = "$WIMWV,090.6,R,009.6,N,A*23\r\n";
char nmea05[] = "$WIMTW,19.3,C*06\r\n";
char nmea06[] = "$GPRMC,120001.03,A,3905.84900,N,02633.42800,E,0000.0,330.0,011019,0.0,W,A,S*61\r\n";
//char nmea06[] = "$GPGLL,3905.84900,N,02633.42800,E,232132.98,A,A*6B\r\n";
char nmea07[] = "$IIDBT,13.1,f,04.0,M,02.2,F*26\r\n";
char nmea08[] = "$IIVHW,330.0,T,330.0,M,00.0,N,00.0,K*55\r\n";
char nmea09[] = "$WIMWV,093.2,R,010.2,N,A*28\r\n";
char nmea10[] = "$WIMTW,19.3,C*06\r\n";
char nmea11[] = "$GPRMC,120002.03,A,3905.84900,N,02633.42800,E,0000.0,330.0,011019,0.0,W,A,S*62\r\n";
//char nmea11[] = "$GPGLL,3905.84900,N,02633.42800,E,232133.98,A,A*6A\r\n";
char nmea12[] = "$IIDBT,13.2,f,04.0,M,02.2,F*25\r\n";
char nmea13[] = "$IIVHW,330.0,T,330.0,M,00.0,N,00.0,K*55\r\n";
char nmea14[] = "$WIMWV,091.8,R,009.9,N,A*23\r\n";
char nmea15[] = "$WIMTW,19.3,C*06\r\n";
char nmea16[] = "$GPRMC,120003.03,A,3905.84900,N,02633.42800,E,0000.0,330.0,011019,0.0,W,A,S*63\r\n";
//char nmea16[] = "$GPGLL,3905.84900,N,02633.42800,E,232134.98,A,A*6D\r\n";
char nmea17[] = "$IIDBT,13.4,f,04.1,M,02.2,F*22\r\n";
char nmea18[] = "$IIVHW,330.0,T,330.0,M,00.0,N,00.0,K*55\r\n";
char nmea19[] = "$WIMWV,085.7,R,010.2,N,A*2A\r\n";
char nmea20[] = "$WIMTW,19.3,C*06\r\n";
char nmea21[] = "$GPRMC,120004.03,A,3905.84900,N,02633.42800,E,0000.0,330.0,011019,0.0,W,A,S*64\r\n";
//char nmea21[] = "$GPGLL,3905.84900,N,02633.42800,E,232135.97,A,A*63\r\n";
char nmea22[] = "$IIDBT,13.0,f,04.0,M,02.2,F*27\r\n";
char nmea23[] = "$IIVHW,330.0,T,330.0,M,00.0,N,00.0,K*55\r\n";
char nmea24[] = "$WIMWV,086.9,R,009.6,N,A*2B\r\n";
char nmea25[] = "$WIMTW,19.3,C*06\r\n";
char * nmea[] = { nmea01, nmea02, nmea03, nmea04, nmea05, nmea06,
nmea07, nmea08, nmea09, nmea10, nmea11, nmea12,
nmea13, nmea14, nmea15, nmea16, nmea17, nmea18,
nmea19, nmea20, nmea21, nmea22, nmea23, nmea24,
nmea25 };
// end of simulation mode definitions
// ==================================
const unsigned long led_off = 30; // time in miliseconds for leds to go off in Sim Mode
unsigned int udpport; // local UDP port
const unsigned int udp_def = 2000; // default (factory) value
unsigned int tcpport; // local TCP port
const unsigned int tcp_def = 0; // default (factory) value; zero means TCP is OFF
boolean IsTcpClient = false; // to signal TCP connection available
unsigned int baud1; // adjustable baud rate for port #1 (input) (4800 or 9600)
const unsigned int b1_def = 4800; // default (factory) value
unsigned int baud2; // adjustable baud rate for port #2 (input) (4800 or 9600 ... 38400)
const unsigned int b2_def = 38400; // default (factory) value
unsigned int baud3; // adjustable baud rate for port #3 (input) (4800 or 9600)
const unsigned int b3_def = 4800; // default (factory) value
unsigned int baud4; // adjustable baud rate for port #4 (input) (4800 or 9600)
const unsigned int b4_def = 4800; // default (factory) value
// (invisible) value of 0 will mean SeaTalk input
unsigned long baud5; // adjustable baud rate for port #5 (output) (4800 or 9600 ... 38400)
const unsigned long b5_def = 38400; // default (factory) value
byte wifiON; // means ( P4>TCP, P3>TCP, P2>TCP, P1>TCP, P4>UDP, P3>UDP, P2>UDP, P1>UDP )
byte wO_def = 3; // default value of wifiON eg P1 and P2 going to UDP only
byte serialON; // means ( UDP>TCP, TCP>UDP, TCP>P5, UDP>P5, P4>P5, P3>P5, P2>P5, P1>P5 )
byte sO_def = 0; // default value of serialON
boolean udpON_1 = true; // Port P#1 goes to udp
boolean udpON_2 = true; // Port P#2 goes to udp
boolean udpON_3 = false; // Port P#3 goes to udp
boolean udpON_4 = false; // Port P#4 goes to udp
boolean tcpON_1 = false; // Port P#1 goes to tcp
boolean tcpON_2 = false; // Port P#2 goes to tcp
boolean tcpON_3 = false; // Port P#3 goes to tcp
boolean tcpON_4 = false; // Port P#4 goes to tcp
boolean serialON_1 = false; // Port P#1 goes to serial port P#5
boolean serialON_2 = false; // Port P#2 goes to serial port P#5
boolean serialON_3 = false; // Port P#3 goes to serial port P#5
boolean serialON_4 = false; // Port P#4 goes to serial port P#5
boolean serialON_U = false; // UDP goes to serial port P#5
boolean serialON_T = false; // TCP goes to serial port P#5
boolean udpON_T = false; // TCP goes to UDP
boolean tcpON_U = false; // UDP goes to TCP
char nmea_1[83]; // NMEA buffer for Port #1
int line_1 = 0; // data available flag for port #1
int i_1 = 0; // lenght of sentence on port #1
boolean Isnmea_1 = false; // clean Nmea sentence is being received on port #1
char nmea_2[83]; // NMEA buffer for port #2
int line_2 = 0; // data available flag for port #2
int i_2 = 0; // lenght of sentence on port #2
boolean Isnmea_2 = false; // clean Nmea sentence is being received on port #2
char nmea_3[83]; // NMEA buffer for Port #3
int line_3 = 0; // data available flag for port #3
int i_3 = 0; // lenght of sentence on port #3
boolean Isnmea_3 = false; // clean Nmea sentence is being received on port #3
char nmea_4[83]; // NMEA buffer for port #4
int line_4 = 0; // data available flag for port #4
int i_4 = 0; // lenght of sentence on port #4
boolean Isnmea_4 = false; // clean Nmea sentence is being received on port #4
char nmea_T[83]; // NMEA buffer for TCP input port
int line_T = 0; // data available flag for TCP input port
int i_T = 0; // lenght of sentence on TCP input port
boolean Isnmea_T = false; // clean Nmea sentence is being received on TCP input port
char nmea_U[83]; // NMEA buffer for UDP input port
int line_U = 0; // data available flag (lenght of packet) for UDP port
boolean Input_1 = true; // if false, input is forgotten
boolean Input_2 = true; // if false, input is forgotten
boolean Input_3 = true; // if false, input is forgotten
boolean Input_4 = true; // if false, input is forgotten
boolean Input_U = true; // if false, input is forgotten
boolean Input_T = true; // if false, input is forgotten
char FltStr_1[43]; // for input serial port P1
char FltStr_2[43]; // for input serial port P2
char FltStr_3[43]; // for input serial port P3
char FltStr_4[43]; // for input serial port P4
char FltStr_5[43]; // for output serial port P5
char FltStr_U[43]; // for UDP in port
char FltStr_T[43]; // for TCP in port
int Skip_1 = 0; int FltSkip_1 ; boolean No_Flt_1;
int Skip_2 = 0; int FltSkip_2 ; boolean No_Flt_2;
int Skip_3 = 0; int FltSkip_3 ; boolean No_Flt_3;
int Skip_4 = 0; int FltSkip_4 ; boolean No_Flt_4;
int Skip_5 = 0; int FltSkip_5 ; boolean No_Flt_5;
int Skip_U = 0; int FltSkip_U ; boolean No_Flt_U;
int Skip_T = 0; int FltSkip_T ; boolean No_Flt_T;
boolean UseDHCP = true;
boolean APDefault = true; // when false we can set a different IP in AP mode (not 192.168.4.1)
IPAddress ap_ip(192, 168, 4, 1); // the IP address in AP mode
IPAddress udp_ip(192, 168, 4, 255); // the IP address to send UDP data
IPAddress sta_ip(0, 0, 0, 0); // the IP address (or received from DHCP if 0.0.0.0) in Station mode
IPAddress gateway(0, 0, 0, 0); // the IP address for Gateway in Station mode (not used if DHCP)
IPAddress subnet(255, 255, 255, 0); // the Subnet Mask in Station mode
WiFiUDP Udp;
WiFiServer webserver(80);
WiFiClient webclient;
WiFiServer tcpserver(tcp_def); // this may be changed during setup()
WiFiClient tcpclient;
WebServer server(82);
TaskHandle_t ForCore0;
void setup() {
DebugBegin(38400);
pinMode(RESET_PIN, INPUT);
pinMode(RX_PIN_1, INPUT);
pinMode(RX_PIN_2, INPUT);
pinMode(RX_PIN_3, INPUT);
pinMode(RX_PIN_4, INPUT);
pinMode(RX_PIN_5A, INPUT_PULLUP);
pinMode(RX_PIN_5B, INPUT);
pinMode(TX_PIN_5, OUTPUT);
pinMode(LED_PIN_1, OUTPUT);
pinMode(LED_PIN_2, OUTPUT);
pinMode(LED_PIN_3, OUTPUT);
pinMode(LED_PIN_4, OUTPUT);
pinMode(LED_PIN_5, OUTPUT);
ReadEeprom(); // start by reading EEPROM
// if you need to join an external network do it before creating the AP!
if (eprom0 == 0x00) { // Station mode
WiFi.persistent(true);
if ( UseDHCP == false ) {
gateway = sta_ip;
gateway[0] = 0x01;
WiFi.config(sta_ip, gateway, subnet);
delay(10);
}
WiFi.begin(ssidST, passwordST);
CheckConnection();
}
if (eprom0 == 0x0F) { // create an Access Point (0xFF >>> 0x0F on Read Eprom)
WiFi.persistent(false);
StartSoftAP();
delay(10);
WiFi.mode(WIFI_AP);
}
LedsOn();
SetOutputFlags();
BuildNmeaTables();
SetNmeaTab_1();
SetNmeaTab_2();
SetNmeaTab_3();
SetNmeaTab_4();
SetNmeaTab_5();
SetNmeaTab_U();
SetNmeaTab_T();
OtaSetting();
delay(10);
webserver.begin();
delay(10);
LedsOff(); // lights goe OFF
// Start Serial and Wifi Ports
StartWifiPorts();
StartSerialPorts();
delay(10);
Blink_ON = true;
// start led blinking on core 0
xTaskCreatePinnedToCore( codeForCore0, "Core0", 1000, NULL, 1, &ForCore0, 0);
}
void loop() {
// check if TCP connection is available
if ( tcpport > 0 ) { IsTcpClient = Test_T_Connection(); }
else { IsTcpClient = false; }
yield();
// test inputs and output
if ( Input_1 ) {
Test_Serial_1(); // check if Hardware Serial port #1 is available
if ( line_1 ) { Output_1(); } // output to wifi and/or serial
}
if ( Input_2 ) {
Test_Serial_2(); // check if Hardware Serial port #2 is available
if ( line_2 ) { Output_2(); }
}
if ( Input_3 ) {
Test_Serial_3(); // check if Software Serial port #3 is available
if (line_3) { Output_3(); }
}
if ( Input_4 ) {
Test_Serial_4(); // check if Software Serial port #4 is available
if (line_4) { Output_4(); }
}
if ( Input_U ) {
Test_U(); // check if udp packet is available
if (line_U) { Output_U(); }
}
if ( Input_T ) {
if ( IsTcpClient ) { // check if tcp packet is available
Test_T();
if (line_T) { Output_T(); }
}
}
if ( DebugMode == false ) {
Test_WebClient(); // Check if a web client has connected
server.handleClient(); // this is for OTA update
}
if (digitalRead(RESET_PIN) == LOW) { Test_Reset(); } // check if reset pin is LOW
if ((millis() - timer) > twdg) {
DoWatchDog(); // check state of the system
}
}
Now the reading and the outputting for port P2 (others are similar - P1 has the USB addittion)
There is no loop. Even if there was you could use filtering to break the loop. Sorry for this long post. In the midle of September I can discuss this in detail. In particular the problem of having TCP bidirectional. At this moment I am preparing the crossing to Mytiline where I will leave my boat. It will hauled out on the 12th and I will flight on the 15th.