Revision from firmware 31 to 32

Discussion and support for the Nmea4Wifi multiplexer - a 4-input Nmea 0183 wifi multiplexer.
Post Reply
Luis Sa
Site Admin
Posts: 844
Joined: Thu May 04, 2017 4:12 am

Revision from firmware 31 to 32

Post by Luis Sa » Fri Dec 06, 2019 2:02 am

Hello,

Every time I change or improve the firmware of the multiplexer I put comments on the source files so that I keep track of the evolution. Later, when I put the file available for download, I add a short description of what was made/added/corrected/modified/...

From now on I will open a topic where I add as much information as possible on the changes. I will write as the development goes on. Then I will release the file here as a candidate for a release. If I receive feedback that it is OK, I will place it on the topic that contains all the updates in chronological order.


Revision from firmware 31 to 32

  • When the filtering string is 0 the multiplexer should just jump the filtering process. In the new version the first thing the filtering routine does is to return if the string is zero. In the 31 version it was not so fast in recognizing this. This is a minor internal improvement.
  • The following applies to any of the 4 serial input ports. If for port, say P3, none of the routing boxes P3>P5 P3>UDP or P3>TCP is checked, P3 is ignored and not even read. You can have a sensor connected and sending data to P3 but the Green Led will not blink because the port is being ignored. It can be frustrating if you are not aware of this. An user (thank you Bernard!) call my attention to this detail and in the acknowledge web page that follows a change of settings, you can get a message like this: BAUD RATE P#3: 4800 but not used or read!
  • During the series of tests that I made to compare the SeaTalk1 conversion of the multiplexer to the conversion performed by the Raymarine bridge E85001 I suspected that there was a mistake in the evaluation of the checksum of the converted Nmea 0183 sentences. I just confirmed that the checksum is correct in version 31. No change then.
  • The reading of incoming SeaTalk1 bytes was modified aiming to be more robust. When the 2nd byte arrives, the length of the datagram is compared against a built in table and if there is mismatch the reading of the incoming datagram is abandoned. Also if before the arrival of the last byte of a datagram, a byte is received with the 9th bit set as a command datagram, the bytes received before are forgotten and the process of receiving a new datagram is initiated.
  • No change on ST=00 (depth below transducer). In response to ST=00 02 00 39 22, the multiplexer outputs a sentence of the type $SDDBT,876.1,f,,,,*05. If I send this sentence to box , it responds with ST=00 02 00 39 22. I will no use floating number operations to convert feet to meters and fathoms. It is the receiving (display) instrument which under the setting of a human user will present the depth in whatever units the user prefers. Also, I will not output the DBK sentence (depth below keel, as I would need to know the distance between the transducer and the keel) nor the sentence BBS (depth below surface, as I would need to know the offset between the water surface and the transducer). Neither I will output the sentence DPT (depth of water) except as explain below. I had several discussions with George about this subject. ST=00 brings the depth below transducer in feet. DPT has 3 fields. The first is depth below transducer in meters, which I can get from ST=00. The second field is an offset from transducer (meters positive means distance from transducer to water line, negative means distance from transducer to keel) which I could fill with a zero or a blank. As for the 3rd field, I have no idea about what it means but I could place a blank. George refers some Android apps that accept DPT and ignore DBT. If someone has this problem, please write me and I will send you a BIN file where ST=00 is converted to DPT.
  • No change on ST=10 and ST=11 (angle and wind speed) for the reasons referred to here. I do not have any SeaTalk1 wind sensor to test my idea but we need the angle and the speed. Both should arrive frequently. Just one, being it angle or speed, is not enough. I could send a sentence when the angle arrives (using the last speed that has been received) and send it again when the speed arrives (using the last angle that has been received). Good engineers like solving problems with minimal effort and cost. And being an engineer, I will only output the sequence on the speed arrival. It must be noticed that I want this software to run smoothly on the Nmea2Wifi multiplexer which does not have a powerful microprocessor as the Nmea4Wifi. Again I can change that on request.
  • ST=20 and ST=26 (speed through water)- in 31 when a ST=26 arrived a timer started. If later a ST=20 arrived it was ignored if more than 5 seconds measured on timer were elapsed. This was because ST=26 brings the speed through the water with more precision. In addition, if a Compass Heading value had been received in the last 5 seconds, the VHW sentence included that Heading. I removed all these features. In a system either the sensor transmits ST=20 or ST=26. I do not assume 2 sensors sending the same information. Even if they exist, each one will generate its VHW sentence. Also these 2 datagrams only bring speed through water. Therefore the VHW they will generate will only contain that and no Heading. Also, I will not calculate the value in kilometers per hour. The VHW will contain speed in knots, only. An additional comma "," at the end of the generated sentence was corrected.
  • ST=21 and ST=22 (Trip and Total Mileage) - now each the datagrams generate a VLW sentence like this $IIVLW,456.7,N,88.9,N*74. For example if ST=21 arrives it stores the Trip Mileage and generates a VLW sentence using this Trip Mileage and the stored Total Mileage. When a ST=22 arrives the Total Mileage is stored and is used to generate a VLW sentence using the stored Trip Mileage. If the stored values are not present (have not arrived) a blank is inserted.
  • ST=23 and ST=27 (Water Temperature) - Contrary to what I had said here that no change was needed, the conversion was not correctly done for negative temperatures. This has been corrected. Both STs will generate a MTW sentence.
  • ST=50 and ST=51 (latitude and longitude) - I detected an error in finding N or S for latitude and E or W for longitude. That is a bug that possibly never has been reported to me as I think (not sure as I do not have any SeaTalk1 GPS sensor!) that GPSs send position using the more accurate ST=58. Also if the value for minutes is greater then 60.00 (it should never happen but I was "playing" with arbitrary bytes on these datagrams) it will be truncated to 60.00. In opposition to the Raymarine box I trim the values. For example the box in the GLL sentence displays, say for the latitude of 7 degrees and 3.63 minutes North, "0703.630,N". In the case of the multiplexer this latitude will be displayed in the RMC sentence as "703.63,N". Another thing that I changed is - both datagrams should have arrived before ST=53 for the RMC sentence to be output. It serves no purpose, so I think, to send a fix with one of lat or lon missing!
  • ST=52 ST=53 ST=54 ST=56 and ST=58 (SOG, COG, Time, Date and LAT/LON) - I made no changes. I only send a RMC sentence when ST=53 arrives (as in version 31). I thought that might be an error on the building of the RMC sentence (sometimes 12 "," or 12 fields and sometimes 13 "," or 13 fields but that was due to the last field (FAA mode indicator used in NMEA 2.3 and later). I simply do not include this last field. If some user has any special requirement, please tell me and I can customize a firmware (not from May to October, when I am sailing :) )
  • ST=84 ST=89 ST=99 and ST=9C (Compass Heading on 84 89 and 9C and Magnetic Variation on 99) - no change. As referred to when describing ST=23 and ST=27, the Compass Heading is not included in the sentence MTW for speed of water.
This ends the modifications done on version 31. The file can be downloaded here: NMEA4WIFIV32.BIN. I appreciate any feedback before I move it to the list of available firmwares!

Regards, Luis

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

Re: Revision from firmware 31 to 32

Post by Luis Sa » Wed Dec 11, 2019 1:51 am

Hello,

The following is the source file SeaTalk.ino. It can not be compiled as there are functions and variables that are defined in other source files that generate the BIN file, but it is the result of the revision I made on the SeaTalk1 to Nmea0183 conversion. This particular file is for the Nmea2Wifi multiplexer. The main loop of the programme (also shown below) calls cyclically Test_Serial_1() for bytes that may have arrived in port P1. If the boolean variable Is_SeaTalk is true the control is passed to the TestSeaTalk() that is defined in the file that follows. The variable line_1 is used to signal that either a Nmea0183 sentence has been received on port P1 (or has been translated from a received SeaTalk1 datagram). The sentence will be contained in the char array nmea_1[].

This is exactly the same in the Nmea4Wifi multiplexer where we use nmea_4 and line_4 for the same purposes. In this case after the 6th character of the converted sentence is available there is a call to the filtering code (not available on the Nmea2Wifi multiplexer).

Code: Select all

/* 
 * Support for SeaTalk1 input on port P1
 */

// IsSeaTalk and IsST are defined in the Main file
// boolean IsSeaTalk = false;       // flag that indicates if input is SeaTalk1 (true) or Nmea 0183 (false)
// boolean IsST = false;            // indicates that a "clean" SeaTalk datagram is being received on port #1
// SerialST_ functions are defined in the rxUart file

char ST[10];            // buffer to store the SeaTalk datagram
uint8_t i_ST;           // index for the ST[] buffer
uint8_t last_ST;        // last index of datagram lenght - 1

void TestSeaTalk() {
  uint16_t inbyte;   // also used to set i_4
  while (AvailableRxSerial_ST() > 0) {    // get the character
    inbyte = ReadRxSerial_ST();
    if ( Is_ST ) {
      if ( highByte(inbyte) ) {
          ST[0] = lowByte(inbyte); 
          last_ST = GetLast_ST(ST[0]);
          if ( last_ST ) { 
            i_ST = 1; 
          }
          else {
            digitalWrite(GREEN_LED, LOW);
            Is_ST = false; return; 
          }
      }
      ST[i_ST] = lowByte(inbyte); 
      // added from 62 to 63
      if ( i_ST == 1 ) {
        uint8_t jj = (ST[1] & 0x0F) + 2;
        if ( jj != last_ST ){
          digitalWrite(GREEN_LED, LOW);
          Is_ST = false; return;  
        }
      }  
      if ( i_ST == last_ST ) {
        inbyte = Parse_ST( ST[0] );
        if ( inbyte ) {
          line_1 = 1; 
          i_1 = inbyte;      
        }
        Is_ST = false;
        digitalWrite(GREEN_LED, LOW);   
        return;
      }  
      i_ST = i_ST + 1;
    }
    if ( Is_ST == false ) {
      if ( highByte(inbyte) ) {
        ST[0] = lowByte(inbyte); 
        last_ST = GetLast_ST(ST[0]);
        if ( last_ST ) {
          i_ST = 1;
          Is_ST = true;
          digitalWrite(GREEN_LED, HIGH);            
        }   
      } 
    } 
  } 
}

uint8_t GetLast_ST( byte b ) {
  switch (b) {
    case 0x00: return 4; break; 
    case 0x10: return 3; break; 
    case 0x11: return 3; break; 
    case 0x20: return 3; break; 
    case 0x21: return 4; break; 
    case 0x22: return 4; break; 
    case 0x23: return 3; break;
    case 0x25: return 6; break;
    case 0x26: return 6; break; 
    case 0x27: return 3; break; 
    case 0x50: return 4; break; 
    case 0x51: return 4; break; 
    case 0x52: return 3; break; 
    case 0x53: return 2; break; 
    case 0x54: return 3; break; 
    case 0x56: return 3; break;  
    case 0x58: return 7; break; 
    case 0x84: return 8; break; 
    case 0x89: return 4; break; 
    case 0x99: return 2; break; 
    case 0x9C: return 3; break;  
    return 0;     
  }
}

// following are variables that are stored and later
// combined to construct NMEA sentences

char AppWindAng[8] = ",";         // ex:  "3276.5,"

char TotalMil[10] = ",N,";        // ex:   "6553.6,N,"
char TripMil[11]  = ",N";         // ex:   "10485.75,N"

boolean Is_MagVar = false;
char MagVar[6] = ",";          // ex:   "90,E"

// minutes have 2 decimal points
char GPS_lat0[11] = ",,";      // ex:  "4104.33,N," meaning N41 4.33
char GPS_lon0[12] = ",,"; 
boolean Is_GPS0 = false;
boolean Is_GPS0Lat = false;
boolean Is_GPS0Lon = false;


// minutes have 3 decimal points
// will be used except if Is_GPS1 == false
char GPS_lat1[12] = ",,";
char GPS_lon1[13] = ",,";
boolean Is_GPS1 = false;

char GPS_time[10] = ",,";      // ex: "hhmmss,A,"
char GPS_date[8] = ",";        // ex: "ddmmyy," 
char GPS_sog[8] = ",";         // ex: "6553.5,"

// to know if Compass Heading is recently available
boolean Is_CompHead = false;
//uint32_t CompHead_Date = 0;
//const uint32_t CompHead_Recent = 20000; // value in miliseconds
uint16_t CompHead;

uint16_t Parse_ST( byte b ) {
  switch (b) {
    case 0x00: return Parse00(); break; 
    case 0x10: return Parse10(); break; 
    case 0x11: return Parse11(); break; 
    case 0x20: return Parse20(); break; 
    case 0x21: return Parse21(); break; 
    case 0x22: return Parse22(); break; 
    case 0x23: return Parse23(); break; 
    case 0x25: return Parse25(); break; 
    case 0x26: return Parse26(); break; 
    case 0x27: return Parse27(); break; 
    case 0x50: return Parse50(); break; 
    case 0x51: return Parse51(); break; 
    case 0x52: return Parse52(); break; 
    case 0x53: return Parse53(); break; 
    case 0x54: return Parse54(); break; 
    case 0x56: return Parse56(); break; 
    case 0x58: return Parse58(); break; 
    case 0x84: return Parse84(); break; 
    case 0x89: return Parse89(); break; 
    case 0x99: return Parse99(); break; 
    case 0x9C: return Parse84(); break; // same as 84
  }  
}

int checkSum( char msg[] ) {
  int XOR = 0;
  int len = strlen(msg) - 1;
  for (int i = 1; i < len; i++) {
    XOR = XOR ^ msg[i];
  }
  return XOR;
}

// DBT using integers
// ==================
uint16_t Parse00() {
  const char DBT[] = "$SDDBT,";
  uint16_t len = 0;
  len += sprintf(nmea_1, DBT);
  uint16_t ii = (ST[4] << 8) | ST[3] ;
  uint16_t DD = ii / 10;
  uint8_t F = ii - DD * 10;
  len += sprintf(nmea_1 + len, "%u.%u,f,,,,*", DD, F ); 
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;
}

uint16_t Parse10() { 
  // only stores AppWindAng returns 0 no NMEA!
  uint16_t ii = (ST[2] << 8) | ST[3];
  char Z5 = '0'; if ( ii % 2 ) { Z5 = '5'; }
  ii = ii / 2;
  sprintf(AppWindAng, "%u.%c,", ii, Z5 );
  return 0;  
}

uint16_t Parse11() {
  const char MWV[] = "$WIMWV,";
  uint16_t len = 0;
  len += sprintf(nmea_1, MWV);
  char AppWindSpeed[7];   // ex: "127.9," 
  uint8_t F = ST[3];
  uint8_t DD = (ST[2] & 0x7F);                         // knots
  len += sprintf(nmea_1 + len, "%sR,%u.%u,N,A*", AppWindAng, DD, F );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;
}

uint16_t Parse20() {
  const char VHW[] = "$VWVHW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, VHW);
  uint16_t ii = (ST[3] << 8) | ST[2] ;
  uint16_t DD = ii / 10;
  uint8_t F = ii - DD * 10; 
  boolean flag = false; 
  len += sprintf(nmea_1 + len, ",,,,%u.%u,N,,*" , DD, F );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;  
}

uint16_t Parse21() {
  const char VLW[] = "$IIVLW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, VLW);
  uint32_t iiii = (ST[3] << 8) | ST[2] ;
  iiii = (ST[4] << 16) | iiii ;
  uint16_t DD = iiii / 100;
  uint16_t FF = iiii - DD * 100;
  sprintf(TripMil, "%u.%u,N" , DD, FF );
  len += sprintf(nmea_1 + len, "%s%u.%u,N*" , TotalMil, DD, FF );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;  
}

uint16_t Parse22() {
  const char VLW[] = "$IIVLW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, VLW); 
  uint16_t ii = (ST[3] << 8) | ST[2];
  uint16_t DD = ii / 10;
  uint8_t F = ii - DD * 10;
  sprintf(TotalMil, "%u.%u,N," , DD, F );
  len += sprintf(nmea_1 + len, "%u.%u,N,%s*" , DD, F, TripMil );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;  
}

uint16_t Parse23() {
  const char MTW[] = "$IIMTW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, MTW); 
  int8_t WaterTemperature = ST[2]; 
  len += sprintf(nmea_1 + len, "%i,C*" , WaterTemperature );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;  
}

uint16_t Parse25() {
  const char VLW[] = "$IIVLW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, VLW);
  uint8_t i = ST[1] >> 4; 
  uint32_t iiii = i * 65536 + ST[3] * 256 + ST[2];
  uint32_t D_Tot = iiii / 10;
  uint8_t F_Tot = iiii - D_Tot * 10;
  i = ST[6]; 
  iiii = i * 65536 + ST[5] * 256 + ST[4];
  uint32_t D_Tri = iiii / 100;
  uint8_t F_Tri = iiii - D_Tri * 100;  
  len += sprintf(nmea_1 + len, "%u.%.1u,N,%u.%.2u,N*" , D_Tot, F_Tot, D_Tri, F_Tri );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1; 
}

uint16_t Parse26() {
  const char VHW[] = "$VWVHW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, VHW);
  uint16_t ii = (ST[3] << 8) | ST[2] ;
  uint16_t DD = ii / 100;
  uint16_t FF = ii - DD * 100;
  boolean flag = false; 
  len += sprintf(nmea_1 + len, ",,,,%u.%.2u,N,,*" , DD, FF );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;  
}

uint16_t Parse27() {
  const char MTW[] = "$IIMTW,";
  uint16_t len = 0;
  len += sprintf(nmea_1, MTW);
  int16_t ii = (ST[3] << 8) | ST[2];
//  int16_t ii = iii;
  ii = ii - 100;
  int16_t DD;
  int8_t F;
  if ( ii > 0 ) {
    DD = ii / 10;
    F = ii - DD * 10; 
  }
  else {
    DD = ii / 10;
    F = DD * 10 - ii;
  }
  len += sprintf(nmea_1 + len, "%i.%.1i,C*" , DD, F );  
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1;  
}

uint16_t Parse50() {
  uint16_t DD = ST[2];  // LatDegrees
  char LatNS = 'N'; if ( ST[4] & 0x80 ) { LatNS = 'S'; }  
  uint16_t ii = (ST[4] << 8) | ST[3];
  ii = ii & 0x7FFF;
  if ( ii > 6000 ) { ii = 6000; }
  uint16_t MM = ii / 100;
  uint16_t FF = ii - MM * 100;
  sprintf(GPS_lat0, "%u%.2u.%u,%c," , DD, MM, FF, LatNS ); 
  Is_GPS0Lat = true;
  if ( Is_GPS0Lon ) { Is_GPS0 = true;}
  return 0;
}

uint16_t Parse51() {
  uint16_t DD = ST[2];
  char LonWE = 'W'; if ( ST[4] & 0x80 ) { LonWE = 'E'; }
  uint16_t ii = (ST[4] << 8) | ST[3];
  ii = ii & 0x7FFF;
  if ( ii > 6000 ) { ii = 6000; }  
  uint16_t MM = ii / 100;
  uint16_t FF = ii - MM * 100;
  sprintf(GPS_lon0, "%u%.2u.%u,%c," , DD, MM, FF, LonWE ); 
  Is_GPS0Lon = true;
  if ( Is_GPS0Lat ) { Is_GPS0 = true;}
  return 0;
}

uint16_t Parse52() {
  uint16_t ii = (ST[3] << 8) | ST[2];
  uint8_t SS = ii / 10;
  uint8_t FF = ii - SS * 10; 
  sprintf(GPS_sog, "%u.%u," , SS, FF );
  return 0;  
}

uint16_t Parse53() {
  if ( ( Is_GPS0 == false ) && ( Is_GPS1 == false ) )  { return 0; } 
  const char RMC[] = "$GPRMC,";
  uint16_t len = 0;
  len += sprintf(nmea_1, RMC); 
  len += sprintf(nmea_1 + len, GPS_time );;
  if ( Is_GPS1 ) {
    len += sprintf(nmea_1 + len, "%s%s", GPS_lat1, GPS_lon1 );  
  }
  else {
    len += sprintf(nmea_1 + len, "%s%s", GPS_lat0, GPS_lon0 );      
  }
  len += sprintf(nmea_1 + len, GPS_sog ); 
  uint16_t ii = ( ST[1] & 0x30 ); ii = (ii >> 4) * 90 ;
  uint16_t jj = ( ST[2] & 0x7F ); jj = jj << 1;
  uint16_t kk = ( ST[1] & 0xC0 ); kk = kk >> 7;
  uint16_t COG = ii + jj + kk;
  len += sprintf(nmea_1 + len, "%u,%s,%s*", COG, GPS_date, MagVar ); 
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1; 
}
uint16_t Parse54() {
  uint8_t HH = ST[3];
  uint8_t i = ( ST[2] & 0xFC );
  uint8_t MM = i >> 2;
  i = ( ST[2] & 0x03 ); i = i << 4;
  uint8_t j = ( ST[1] & 0xF0 ); j = j >> 4;
  uint8_t SS = i | j;
  sprintf(GPS_time, "%u%.2u%.2u,A," , HH, MM, SS ); 
  return 0;  
}

uint16_t Parse56() {
  uint8_t YY = ST[3];
  uint8_t DD = ST[2];
  uint8_t MM = ST[1] & 0xF0;  
  MM = MM >> 4; 
  sprintf(GPS_date, "%.2u%.2u%.2u" , DD, MM, YY );  
  return 0;  
}

uint16_t Parse58() {
  char LatNS, LonWE;
  ( ST[1] & 0x10 ) ? LatNS = 'S' : LatNS = 'N'; 
  ( ST[1] & 0x20 ) ? LonWE = 'E' : LonWE = 'W';
  uint16_t DD = ST[2];
  uint16_t ii = ST[3] << 8; ii = ii + ST[4];
  uint16_t MM = ii / 1000;
  uint16_t FF = ii - MM * 1000;
  sprintf(GPS_lat1, "%u%.2u.%.3u,%c," , DD, MM, FF, LatNS ); 
  // now longitude
  DD = ST[5]; 
  ii = ST[6] << 8; ii = ii + ST[7];
  MM = ii / 1000;
  FF = ii - MM * 1000;
  sprintf(GPS_lon1, "%u%.2u.%.3u,%c," , DD, MM, FF, LonWE );
  Is_GPS1 = true;  
  return 0;  
}

uint16_t Parse84() {
  uint8_t i, j;
  i = ( ST[1] & 0x30 ); i = (i >> 4);
  CompHead = i * 90 ;
  i = ( ST[2] & 0x3F ); i = i << 1;
  CompHead += i;
  i = ST[1] & 0xC0; i = i >> 6;
  j = 1;
  if (i == 0) { j = 0; }
  if (i == 3) { j = 2; }
  CompHead += j;
  Is_CompHead = true; // CompHead_Date = millis();
  uint16_t len = 0;
  if ( Is_MagVar ) {
    const char HDG[] = "$HCHDG,";
    len += sprintf(nmea_1, HDG);
    len += sprintf(nmea_1 + len, "%u,,,%s*", CompHead , MagVar );     
  }
  else {
    const char HDM[] = "$HCHDM,";
    len += sprintf(nmea_1, HDM);
    len += sprintf(nmea_1 + len, "%u,M*", CompHead );  
  }
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1; 
}

uint16_t Parse89() {
  uint8_t i, j;
  i = ( ST[1] & 0x30 ); i = (i >> 4);
  CompHead = i * 90 ;
  i = ( ST[2] & 0x3F ); i = i << 1;
  CompHead += i;
  i = ST[1] & 0xC0; i = i >> 6;
  j = i / 2;
  CompHead += j;
  Is_CompHead = true; // CompHead_Date = millis();
  uint16_t len = 0;
  if ( Is_MagVar ) {
    const char HDG[] = "$HCHDG,";
    len += sprintf(nmea_1, HDG);
    len += sprintf(nmea_1 + len, "%u,,,%s*", CompHead , MagVar );     
  }
  else {
    const char HDM[] = "$HCHDM,";
    len += sprintf(nmea_1, HDM);
    len += sprintf(nmea_1 + len, "%u,M*", CompHead );  
  }
  int XOR = checkSum( nmea_1 );
  len += sprintf(nmea_1 + len, "%.2X", XOR );
  return len + 1; 
}

uint16_t Parse99() {
  int8_t i = ST[2];
  char EW = 'E' ; if ( i >= 0 ) { EW = 'W' ; } 
  i = abs(i);
  sprintf(MagVar, "%u,%c", i, EW );
  Is_MagVar = true;
  return 0;  
}

Code: Select all

void loop() {

  httpServer.handleClient();
  // check if TCP connection is available
  IsTcpClient = false;
  if ( tcpport ) { IsTcpClient = Test_TCP_Connection(); }

  Test_WebClient();                    // Check if a web client has connected
  if (digitalRead(RESET_PIN) == LOW) { Test_Reset(); }   // check if reset pin is LOW 
  if ((millis() - timer) > twdg) {  DoWatchDog(); }      // check state of the system 

  // test inputs and output
  if ( Input_1 ) {
    Test_Serial_1();                     // check if Software 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(); }          // output to wifi and/or serial  
  }
  if ( Input_U ) {
    Test_UDP();                          // check if udp packet is available
    if (line_UDP) { Output_UDP(); }      // output to serial and/or to TCP
  } 
  if ( Input_T ) {
    if ( IsTcpClient ) {
      Test_TCP();                        // check if tcp packet is available
      if (line_TCP) { Output_TCP(); }    // output to serial and/or to UDP
    }
  } 
  yield();
}

Code: Select all

void Test_Serial_1() {     // Software rxUart port #1
  
  if ( SimMode ) {
    line_1 = 0;
    if ((millis() - timer_nmea) > inter_nmea) {
      digitalWrite(GREEN_LED, HIGH);
      timer_nmea = millis();
      index_nmea = index_nmea + 1;
      if ( index_nmea > 24 ) { index_nmea = 0; }
      strcpy( nmea_1 , nmea[index_nmea] );
      line_1 = 1;
    }  
    if ((millis() - timer_nmea) > led_off) {  digitalWrite(GREEN_LED, LOW); }
  return;
  }
 
  byte b;
  if ( IsSeaTalk ) {
    TestSeaTalk();
    return;
  }
  while (AvailableRxSerial() > 0) {    // get the character
    b = ReadRxSerial();
    if ( Isnmea_1 ) {
      nmea_1[i_1] = b; 
      i_1 = i_1 + 1;
      if (i_1 == 20) { digitalWrite(GREEN_LED, LOW); }
      if (b == 0x0D) {        //0D is CR
        i_1 = i_1 - 1;
        nmea_1[i_1] = 0x00; 
        line_1 = 1;      
        Isnmea_1 = false;  
        digitalWrite(GREEN_LED, LOW);    
        return;
      }
    }
    if ( Isnmea_1 == false ) {
      if ( b == 0x24 ) {      //  test for $  ( AIS ! not possible)
        nmea_1[0] = b; 
        i_1 = 1;
        Isnmea_1 = true;
        digitalWrite(GREEN_LED, HIGH);
      } 
    }
    if (i_1 > 81) { // line too long
      line_1 = 0;   // reset buffer & flag
      i_1 = 0;
      Isnmea_1 = false;
      return;  
    } 
  }
}

Regards, Luis

Post Reply