Connection matrix settings

Discussion and support for the Nmea4Wifi multiplexer - a 4-input Nmea 0183 wifi multiplexer.
Post Reply
dagnall
Posts: 459
Joined: Wed Mar 04, 2020 6:36 pm

Connection matrix settings

Post by dagnall » Sun Aug 30, 2020 12:19 pm

Luis.
I hope your trip to Thasos was good.
I have some connection matrix settings questions regarding what data is "repeated" if you set TCP>P5.
:?: If I have P1/P2 >TCP, and TCP>P5, does it send all P1/P2 recieved data out to P5? (I think No, but am not sure)
"P5" on my Spartpilot x5 is NMEA 0183, so is slow and may be overwhelmed if lots of (P2) AIS messages are trying to be copied to it.

I hope that I have read the specification correctly, and that TCP>P5 ONLY sends data to P5 that the (Ipad/INAVX) sends OUT (back to the multiplexer) on TCP. (Plus any set by P1>P5 etc). - So I tried to test this.

My experiment was supposed to find if INavX is also "copying" data it receives and resending it "back" on TCP. - Certainly on the boat, I only saw "SOG" (gps) on my autopilot when InavX was connected via TCP, and this makes me wonder where its getting that GPS signal from. For my home test I have the multiplexer module USB connected to PC, and am using the arduino serial monitor to see what is sent on P5. I can see data being sent to the Ipad using the NMEA test features in INavX.
:!: but I discovered another small bug.when trying simulation mode.
  • If I set TCP>P5, The "simulation mode" does not work properly - at least on my ESP32 test board here- .
  • It does go to the "simulation page",
  • but no data is actually sent out on UDP or TCP as far as I can see when looking using the IPad.


My replacement ESP32 modules should arrive Sept 3, and then I can replace in the boat and not have to rely on Simulation mode. My home test ESP32 setup is still using manual IP as these ESP32 suffer from the disconnect issue if I use AutoIP. This may be related to the inability to use TCP>P5 in simulation mode.. but its not possible to tell.

I may wish to take you up on your kind offer of a replacement (preprogrammed!) ESP32 module if the new ones suffer problems!.

Sorry to add to the bug list - unless this is related to the other one?
I may experiment with older software revisions to use up some time!
All the very best..
Dagnall

Luis Sa
Site Admin
Posts: 845
Joined: Thu May 04, 2017 4:12 am

Re: Connection matrix settings

Post by Luis Sa » Sun Aug 30, 2020 1:47 pm

Hello,

Thank you for your informative post. It is very useful to me. The crossing to Thassos (Limnearia) was as planned except that I got unexpected 28 knots window when forecast was 15. It happened just when I passed the Mont Athos cape. It is a mountain of 2020 meters high. When I was approaching the cape the wind stopped because of that 2020 meters wall but when I went past the cable it was about 25 for an hour or so and returned to the expected 15 knots. As I am writing I am in Kavala.

What goes out on P5 is a combination of what arrived at P1 P2 P3 P4 UDP and/or TCP. If you set P1 > TCP and TCP > P5, P1 will not go to P5.

I would use TCP on a single direction TCP > P5. On the other direction I would use P1... or/and P4 > UDP. The reason is that the multiplexer is the server in the "client server" TCP connection. In the main loop of the multiplexer it tests if a TCP client is available. This client can be a sending or a receiving device. In the case of TCP > P5 when the device has data it requests a connection and sends data when the server (the multiplexer) says that it can receive that data. If at the same time you had set P1 > TCP the multiplexer will send data from P1 (if it exists) just because it noted the "client is available" created by the P5 request. If the device to receive data by TCP is not prepared, the multiplexer will crash after a minute since it sends sends and sends the data from P1 because it receives no acknowledgement. If it was UDP it would send data and would forget about that. I hope you could follow me.

I will look to the bug that you pointed to me. Note that you could use my tool Nmea0183Tester.exe and instead of using the simulator you could just type whatever sentence you want to be transmitted. Or write a file with test sentences and send them out to the multiplexer. There are many ways you can use this tool. With your esp32 module you have at home you can send a file to the multiplexer by TCP and save the received file by UDP if you had set TCP > UDP. And much more.

If you need a esp32 module I can send for 5 euros plus postal cost.

Regards, Luis

dagnall
Posts: 459
Joined: Wed Mar 04, 2020 6:36 pm

Re: Connection matrix settings

Post by dagnall » Sun Aug 30, 2020 5:39 pm

Luis Sa wrote:
Sun Aug 30, 2020 1:47 pm
I would use TCP on a single direction TCP > P5.
On the other direction I would use P1... or/and P4 > UDP.
The reason is that the multiplexer is the server in the "client server" TCP connection. In the main loop of the multiplexer it tests if a TCP client is available. This client can be a sending or a receiving device. In the case of TCP > P5 when the device has data it requests a connection and sends data when the server (the multiplexer) says that it can receive that data. If at the same time you had set P1 > TCP the multiplexer will send data from P1 (if it exists) just because it noted the "client is available" created by the P5 request. If the device to receive data by TCP is not prepared, the multiplexer will crash after a minute since it sends sends and sends the data from P1 because it receives no acknowledgement. If it was UDP it would send data and would forget about that. I hope you could follow me.
Luis,
Thanks for taking time to respond..
I thought I understood the routing, but now I am not so sure.. ! :?
The bit I find confusing is where you note "will send data from P1 (if it exists) just because it noted the "client is available" created by the P5 request.".
:?: Do you mean that P2 data could under some circumstances be sent to P5 if I have (for example):
  • P1>P5,TCP
  • P2>TCP
  • TCP>P5
I want to avoid data duplication, especially with the loads of AIS around here.

You suggest UDP, but in tests I have not been able to set InavX to SEND the WP/Goto data to the Autopilot except in TCP mode. I thought UDP (broadcast) was only usable from Multiplexer "outwards to all clients" and not from IPad "back" to multiplexer. .? Attempts to test with InavX seem to result in a quick NMEA4WIFI crash if I try to send data using UDP. - But this could be my dodgy setup.

I have attached a drawing of Scubacats electronics I did today after being inspired by your diagrams. You can see that I am particularly afraid that If I send stuff to the Autopilot, it may be able to loop back data for endless repetition via the bi-directional ST bus. The SPX-5 manual does not address this issue, but it does say that it sends HDG and RSA to NMEA0183. However I am not sure if it also copies these onto its own ST1 bus (which would be reasonable). If the multiplexer picks these up with other ST instrument data and then sends them to TCP, it would also send them to P5 and loop..... ? so I might need to filter them out.

ESP32 replacement --- YES PLEASE! I have one on order but a "proper" spare would give peace of mind..
If you can email me / or PM in this forum with some contact details I will send you money for a "proper" ESP32 !.
As far as I can see the module is now obsolete.. so you may have the last stock?

I hope you have a great time in Kavala. I may follow on MarineTraffic!!.

Enjoy the sun and great meals!
Dagnall

P.S. I cannot use the .exe program as the PC refuses to connect to the Multiplexer via wifi so it will not "connect"..
I am probably missing something when I try to set the PC's Manual IP as it wants to know the DNS address..
Attachments
Scubacat Electronics (s).pdf
Scubacat Electronics
(326.68 KiB) Downloaded 467 times

Luis Sa
Site Admin
Posts: 845
Joined: Thu May 04, 2017 4:12 am

Re: Connection matrix settings

Post by Luis Sa » Sun Aug 30, 2020 7:04 pm

Hello,

I could send you the loop code so that you could understand better. It is in my PC and I am writing using my smartphone.

I will try to write here what the loop is:

1) Check if there is a http request at port 82 and if so go to OTA update.
2) Check if there is a http request at port 80 and if so go web page setting interface.
3) Test if a TCP client is connected and if so set TCP_Client to true. Else to false.
4) Get Input P1. If a complete sentence has arrived set variable P1_Available to true.
If P1_Available Output_P1
.... same for P2 P3 P4 UDP and TCP but for TCP which would be 9) it only "gets" if TCP_Client is true.


Now Output_P1:

... I will connect my PC and will write the actual code...

Regards, Luis

Luis Sa
Site Admin
Posts: 845
Joined: Thu May 04, 2017 4:12 am

Re: Connection matrix settings

Post by Luis Sa » Sun Aug 30, 2020 7:26 pm

Hello again,

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)

Code: Select all

void Test_Serial_2() {       // Hardware Serial (2) port #2

  if ( SimMode ) {
    line_2 = 0;
    if ((millis() - timer_ais) > inter_ais) {
      if ( Led2 == false ) { Led2 = true; }
      timer_ais = millis();
      index_ais = index_ais + 1;
      if ( index_ais > number_ais ) { index_ais = 0; }
      strcpy( nmea_2 , ais[index_ais] );
      line_2 = 1;
    }  
  return;
  }

  byte b;
  while (Serial.available() > 0) {    // get the character
    b = Serial.read();
    if ( Isnmea_2 ) {
      nmea_2[i_2] = b; 
      i_2 = i_2 + 1;
      if (i_2 == 6) { 
        if ( CheckNmeaFlt_2() ) { if ( Led2 == false ) { Led2 = true; } }
        else { Isnmea_2 = false; return; }
      }
      if (b == 0x0D) {        //0D is CR
        if ( i_2 > 8 ) {
          nmea_2[i_2] = 0x0A; 
          nmea_2[i_2 + 1] = 0x00;  
          line_2 = 1;      
          Isnmea_2 = false;   
          return;
        }
        else { Isnmea_2 = false; return; } 
      }
    }
    if ( Isnmea_2 == false ) {
      if (( b == 0x21 ) || ( b == 0x24 )) {      //  test for ! or $  (AIS or NMEA)
        if ( Skip_2 < FltSkip_2 ) {
          Skip_2 = Skip_2 + 1; }
        else {
          Skip_2 = 0;
          nmea_2[0] = b; 
          i_2 = 1;
          Isnmea_2 = true;
        }
      } 
    }
    if (i_2 > 80) { Isnmea_2 = false;  return; }   // line too long   
  }
}

void Output_2() {
  if ( DebugMode ) {
    webclient.print( "P#2: " );
    webclient.print( nmea_2 );
    webclient.print( "<br>" );
    line_2 = 0;          // reset buffer
    i_2 = 0;
    return;
  }
  boolean wifi;
  if (udpON_2 == true) {
     wifi = true; if (eprom0 == 0x00) { if ( IsConnected == false) { wifi = false; } } 
     if ( wifi ) {
        if ( Led5 == false ) { Led5 = true; }  
        Udp.beginPacket(udp_ip, udpport);
        Udp.print(nmea_2);
        Udp.endPacket();
     }  
  }
  if (tcpON_2 == true) {
    wifi = true; if (eprom0 == 0x00) { if ( IsConnected == false) { wifi = false; } } 
    if ( wifi ) {
      if ( IsTcpClient ) { 
        if ( Led5 == false ) { Led5 = true; }        
        tcpclient.print( nmea_2 );
      }
    }
  }  
  if ( serialON_2 ) {
    if ( Skip_5 < FltSkip_5 ) {
      Skip_5 = Skip_5 + 1; }
    else {
      Skip_5 = 0;
      if ( CheckNmeaFlt_5( 2 ) ) {    
        if ( Serial2.availableForWrite() > (i_2 + 1) ) { Serial2.print( nmea_2 ); }
      }
    }
  }
  line_2 = 0;          // reset buffer & flag
  i_2 = 0;
}
Ñow for TCP test and output

Code: Select all

void Test_T() {     // TCP input port
  if ( SimMode ) {
    line_T = 0;
    return;
  }
  byte b;
  while (tcpclient.available()) {    // get the character
    b = tcpclient.read();
    if ( Isnmea_T ) {
      nmea_T[i_T] = b; 
      i_T = i_T + 1;
      if (i_T == 6) { 
        if ( CheckNmeaFlt_T() ) { if ( Led5 == false ) { Led5 = true; } }
        else { Isnmea_T = false; return; }
      }    
      if (b == 0x0D) {        //0D is CR
        if ( i_T > 8 ) {
          nmea_T[i_T] = 0x0A;
          nmea_T[i_T + 1] = 0x00;          
          line_T = 1;      
          Isnmea_T = false;   
          return;     
        }
        else { Isnmea_T = false; return; } 
      }
    }
    if ( Isnmea_T == false ) {
      if (( b == 0x21 ) || ( b == 0x24 )) {      //  test for ! or $  (AIS or NMEA)
        if ( Skip_T < FltSkip_T ) {
          Skip_T = Skip_T + 1; }
        else {
          Skip_T = 0;
          nmea_T[0] = b; 
          i_T = 1;
          Isnmea_T = true;
        }
      } 
    }
    if (i_T > 80) { Isnmea_T = false;  return; }   // line too long   
  }
}

void Output_T() {
  if ( DebugMode ) {
    webclient.print( "TCP: " );
    webclient.print( nmea_T );
    webclient.print( "<br>" );
    line_T = 0;          // reset buffer
    i_T = 0;
    return;
  }
  if ( udpON_T ) {
        if ( Led5 == false ) { Led5 = true; }      
        Udp.beginPacket(udp_ip, udpport);
        Udp.print(nmea_T);
        Udp.endPacket();  
  }
  if ( serialON_T ) {  
    if ( Skip_5 < FltSkip_5 ) {
      Skip_5 = Skip_5 + 1; }
    else {
      Skip_5 = 0;    
      if ( CheckNmeaFlt_5( 6 ) ) {    
        if ( Serial2.availableForWrite() > (i_T + 1) ) { Serial2.print( nmea_T ); }
      }
    }
  }
  line_T = 0;          // reset buffer
  i_T = 0;
}

Also this part is needed to understand routing

Code: Select all

void SetOutputFlags() {

  timer = millis();
  MyAge = 0;
    
  udpON_1 = wifiON & B00000001;
  udpON_2 = wifiON & B00000010;
  udpON_3 = wifiON & B00000100;
  udpON_4 = wifiON & B00001000;
  tcpON_1 = wifiON & B00010000;
  tcpON_2 = wifiON & B00100000;
  tcpON_3 = wifiON & B01000000;
  tcpON_4 = wifiON & B10000000;

  serialON_1 = serialON & B00000001;
  serialON_2 = serialON & B00000010;
  serialON_3 = serialON & B00000100;
  serialON_4 = serialON & B00001000;
  serialON_U = serialON & B00010000;
  serialON_T = serialON & B00100000;
  tcpON_U = serialON & B01000000;
  udpON_T = serialON & B10000000;

  Input_1 = true; Input_2 = true; Input_3 = true;
  Input_4 = true; Input_U = true; Input_T = true; 
  
  if ( udpport == 0 ) {
    Input_U = false;
    udpON_1 = false;
    udpON_2 = false;
    udpON_3 = false;
    udpON_4 = false;
    udpON_T = false;
    serialON_U = false;
    tcpON_U = false;
  }

  if ( tcpport == 0 ) {
    Input_T = false;
    tcpON_1 = false;
    tcpON_2 = false;
    tcpON_3 = false;
    tcpON_4 = false;
    tcpON_U = false;
    serialON_T = false;
    udpON_T = false;
  }
  
  if ( FltStr_1[0] == 57 ) {    // 9 is ASCII 57
    Input_1 = false; 
    udpON_1 = false;
    tcpON_1 = false;
    serialON_1 = false;    
  }
   
  if ( FltStr_2[0] == 57 ) {
    Input_2 = false; 
    udpON_2 = false;
    tcpON_2 = false;
    serialON_2 = false;
  }
   
  if ( FltStr_3[0] == 57 ) { 
    Input_3 = false; 
    udpON_3 = false;
    tcpON_3 = false;
    serialON_3 = false;    
  }
  
  if ( FltStr_4[0] == 57 ) { 
    Input_4 = false; 
    udpON_4 = false;
    tcpON_4 = false;
    serialON_4 = false;    
  }
  
  if ( FltStr_U[0] == 57 ) {
    Input_U = false;
    tcpON_U = false;
    serialON_U = false;    
  }
 
  if ( FltStr_T[0] == 57 ) {
    Input_T = false;
    udpON_T = false;
    serialON_U = false;       
  }

  No_Flt_1 = false; No_Flt_2 = false; No_Flt_3 = false; No_Flt_4 = false;
  No_Flt_5 = false; No_Flt_U = false; No_Flt_T = false;

  if ( FltStr_1[0] == 48 ) { No_Flt_1 = true; }
  if ( FltStr_2[0] == 48 ) { No_Flt_2 = true; }
  if ( FltStr_3[0] == 48 ) { No_Flt_3 = true; }
  if ( FltStr_4[0] == 48 ) { No_Flt_4 = true; }  
  if ( FltStr_5[0] == 48 ) { No_Flt_5 = true; }
  if ( FltStr_U[0] == 48 ) { No_Flt_U = true; }  
  if ( FltStr_T[0] == 48 ) { No_Flt_T = true; }

  if (DebugMode == false) {
    if ( (serialON_1 == false) && (udpON_1 == false) && (tcpON_1 == false) ) { Input_1 = false; }
    if ( (serialON_2 == false) && (udpON_2 == false) && (tcpON_2 == false) ) { Input_2 = false; }  
    if ( (serialON_3 == false) && (udpON_3 == false) && (tcpON_3 == false) ) { Input_3 = false; }
    if ( (serialON_4 == false) && (udpON_4 == false) && (tcpON_4 == false) ) { Input_4 = false; }  
  
    if ( (serialON_U == false) && (tcpON_U == false) ) { Input_U = false; }    
    if ( (serialON_T == false) && (udpON_T == false) ) { Input_T = false; } 
  }
  
}
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.

Regards, Luis

dagnall
Posts: 459
Joined: Wed Mar 04, 2020 6:36 pm

Re: Connection matrix settings

Post by dagnall » Wed Sep 02, 2020 1:40 pm

Luis.
Many thanks. That makes me much more comfortable that I should not get a data Loop.

The rest of this note is for reading when you have finished travelling! -

I have done a lot of experiments to try and explore the stability issue to see if I can help and have come up with an interesting result that may give a hint as to the source of the disconnect/reconnect bug.

To try and compress the story: In April, I made a "home" copy of NMEA4WIFI using a ESP32 lite board to test how it worked and help me set up my iphone etc at home using simulation mode. This board was stable and worked fine. (V34). I realised that the only difference between what I did then and recently was that I originally used the "OTAWebUploader" sketch example and not your "NMEA4WIFI" OTA upload sketch.

For all my recent tests I have been using your OTA sketch as the starting point and had noted that I now needed a capacitor across 3V3, because without this addition, the module was going into a low power reset. (And when it was working, it was "reliably" showing the disconnect/reconnect behaviours unless I used Manual IP).

As a final resort I have today tried to replicate my April setup, and loaded the "OTAWebUploader" sketch and then used that to upload V34. I have now done this for two modules now and the results are the same: Both now connect reliably in Auto IP mode, and do not need the added capacitor. :!:

My conclusion- for what its worth- is that your OTA upload sketch (accidentally?) sets some WIFI parameters (power/brownout ? ) that are not reset by the V34 sketch? - and that the "OTAWebUploader" sketch example somehow sets them differently. I have not tried to explore this.

If your other users who are experiencing connect/reconnect issues also did the upload /upgrade using the same process, it is possible we are all seeing the same results.

I hope this helps when you come to try and sort things when you get home.
All the best
Dagnall

Post Reply