Skip to content

Commit

Permalink
Ensure that AIS strings are ITU-R M.1371-1 compliant
Browse files Browse the repository at this point in the history
  • Loading branch information
Luis Soltero committed Feb 26, 2024
1 parent c998950 commit 97f9926
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 33 deletions.
6 changes: 6 additions & 0 deletions Documents/src/changes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changes to the Library {#changes}
\tableofcontents

## 26.02.2024

- changed (char *) arguments to (const char *) in Set functions for PGN 129809, 129810, 129794
- Added AddAISStr() method to N2kMsg class which filters AIS strings to make complient with ITU-R M.1371-1
- modified Set functions for PGN 129809, 129810, 129794 to use AddAISStr()

## 23.02.2024

- Compatibility change: Parsers ParseN2kPGN129809, ParseN2kPGN129810 and ParseN2kPGN129794 parameter list
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=NMEA2000
version=4.21.1
version=4.21.2
author=Timo Lappalainen
maintainer=Kave Oy <www.kave.fi>
sentence=NMEA 2000 library for building compatible devices for NMEA 2000 bus.
Expand Down
34 changes: 6 additions & 28 deletions src/N2kMessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "N2kMessages.h"
#include <string.h>
#include <ctype.h>

//*****************************************************************************
// System time
Expand Down Expand Up @@ -1609,24 +1608,6 @@ bool AppendN2kPGN129285(tN2kMsg &N2kMsg, uint16_t ID, const char* Name, double L
}
}

//*****************************************************************************
// AIS String helper
// make sure characters fall into range defined in table 14
// https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1371-1-200108-S!!PDF-E.pdf
#define MAXAISSTRBUFLEN 21
const char *StringToAISString(const char *str, char *AISStr, size_t AISStrBufSize)
{
if ( str == nullptr || AISStr == nullptr) return nullptr;
size_t i;
for (i = 0; str[i] != '\0' && i < AISStrBufSize; i++ ) {
char c = toupper((int)str[i]);
AISStr[i] = (c >= 0x20 && c <= 0x5F) ? c : '?';
}
if ( i < AISStrBufSize ) AISStr[i]='\0';

return AISStr;
}

//*****************************************************************************
// AIS static data A
void SetN2kPGN129794(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
Expand All @@ -1635,14 +1616,13 @@ void SetN2kPGN129794(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, u
double Draught, const char *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
tN2kAISDTE DTE, tN2kAISTransceiverInformation AISinfo)
{
char AISstrBuf[MAXAISSTRBUFLEN];
N2kMsg.SetPGN(129794L);
N2kMsg.Priority=6;
N2kMsg.AddByte((Repeat & 0x03)<<6 | (MessageID & 0x3f));
N2kMsg.Add4ByteUInt(UserID);
N2kMsg.Add4ByteUInt(IMOnumber);
N2kMsg.AddStr(StringToAISString(Callsign, AISstrBuf, sizeof(AISstrBuf)), 7, false, '@');
N2kMsg.AddStr(StringToAISString(Name, AISstrBuf, sizeof(AISstrBuf)), 20, false, '@');
N2kMsg.AddAISStr(Callsign,7);
N2kMsg.AddAISStr(Name, 20);
N2kMsg.AddByte(VesselType);
N2kMsg.Add2ByteDouble(Length, 0.1);
N2kMsg.Add2ByteDouble(Beam, 0.1);
Expand All @@ -1651,7 +1631,7 @@ void SetN2kPGN129794(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, u
N2kMsg.Add2ByteUInt(ETAdate);
N2kMsg.Add4ByteUDouble(ETAtime, 0.0001);
N2kMsg.Add2ByteDouble(Draught, 0.01);
N2kMsg.AddStr(StringToAISString(Destination, AISstrBuf, sizeof(AISstrBuf)), false, 20, '@');
N2kMsg.AddAISStr(Destination, 20);
N2kMsg.AddByte((DTE & 0x01)<<6 | (GNSStype & 0x0f)<<2 | (AISversion & 0x03));
N2kMsg.AddByte(0xe0 | (AISinfo & 0x1f));
N2kMsg.AddByte(0xff);
Expand Down Expand Up @@ -1692,12 +1672,11 @@ bool ParseN2kPGN129794(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat
// AIS static data class B part A
void SetN2kPGN129809(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID, const char *Name)
{
char AISstrBuf[MAXAISSTRBUFLEN];
N2kMsg.SetPGN(129809L);
N2kMsg.Priority=6;
N2kMsg.AddByte((Repeat & 0x03)<<6 | (MessageID & 0x3f));
N2kMsg.Add4ByteUInt(UserID);
N2kMsg.AddStr(StringToAISString(Name,AISstrBuf, sizeof(AISstrBuf)), 20, false, '@');
N2kMsg.AddAISStr(Name, 20);
}

bool ParseN2kPGN129809(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID, char *Name, size_t NameBufSize)
Expand All @@ -1720,14 +1699,13 @@ void SetN2kPGN129810(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, u
uint8_t VesselType, const char *Vendor, const char *Callsign, double Length, double Beam,
double PosRefStbd, double PosRefBow, uint32_t MothershipID)
{
char AISstrBuf[MAXAISSTRBUFLEN];
N2kMsg.SetPGN(129810L);
N2kMsg.Priority=6;
N2kMsg.AddByte((Repeat & 0x03)<<6 | (MessageID & 0x3f));
N2kMsg.Add4ByteUInt(UserID);
N2kMsg.AddByte(VesselType);
N2kMsg.AddStr(StringToAISString(Vendor, AISstrBuf, sizeof(AISstrBuf)), 7, false, '@');
N2kMsg.AddStr(StringToAISString(Callsign, AISstrBuf, sizeof(AISstrBuf)), 7, false, '@');
N2kMsg.AddAISStr(Vendor, 7);
N2kMsg.AddAISStr(Callsign, 7);
N2kMsg.Add2ByteUDouble(Length, 0.1);
N2kMsg.Add2ByteUDouble(Beam, 0.1);
N2kMsg.Add2ByteUDouble(PosRefStbd, 0.1);
Expand Down
8 changes: 4 additions & 4 deletions src/N2kMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -4287,7 +4287,7 @@ inline bool ParseN2kPGNSatellitesInView(const tN2kMsg& N2kMsg, uint8_t SVIndex,
* \param IMOnumber Ship identification number by IMO
* [1 .. 999999999]; 0 = not available = default
* Not applicable to SAR aircraft
* \param Callsign Call Sign - 7x -> 6 bit ASCII characters,
* \param Callsign Call Sign - 7x -> 6 bit ASCII characters conversion as per ITU-R M.1371-1,
* \param Name Name of the vessel;
* Maximum 20 characters 6 bit ASCII;
* For SAR aircraft, it should be set
Expand Down Expand Up @@ -4359,7 +4359,7 @@ inline void SetN2kAISClassAStatic(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRep
* \param IMOnumber Ship identification number by IMO
* [1 .. 999999999]; 0 = not available = default
* Not applicable to SAR aircraft
* \param Callsign Call Sign - 7x -> 6 bit ASCII characters,
* \param Callsign Call Sign
* \param CallsignBufSize size of Callsign buffer
* \param Name Name of the vessel;
* Maximum 20 characters 6 bit ASCII;
Expand Down Expand Up @@ -4524,7 +4524,7 @@ inline bool ParseN2kAISClassBStaticPartA(const tN2kMsg &N2kMsg, uint8_t &Message
* Not applicable to SAR aircraft
* \param Vendor Unique identification of the Unit by a number as
* defined by the manufacturer
* \param Callsign Call Sign - 7x -> 6 bit ASCII characters
* \param Callsign Call Sign - 7x -> 6 bit ASCII characters conversion as per ITU-R M.1371-1
* \param Length Length/Diameter in meters
* \param Beam Beam/Diameter in meters
* \param PosRefStbd Position Reference Point from Starboard
Expand Down Expand Up @@ -4578,7 +4578,7 @@ inline void SetN2kAISClassBStaticPartB(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kA
* \param Vendor Unique identification of the Unit by a number as
* defined by the manufacturer
* \param VendorBufSize size of Vendor buffer
* \param Callsign Call Sign - 7x -> 6 bit ASCII characters
* \param Callsign Call Sign
* \param CallsignBufSize size of Callsign buffer
* \param Length Length/Diameter in meters
* \param Beam Beam/Diameter in meters
Expand Down
17 changes: 17 additions & 0 deletions src/N2kMsg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//#include <MemoryFree.h> // For testing used memory

#define Escape 0x10
Expand Down Expand Up @@ -213,6 +214,22 @@ void tN2kMsg::AddStr(const char *str, int len, bool UsePgm, unsigned char fillCh
SetBufStr(str,len,DataLen,Data,UsePgm,fillChar);
}

//*****************************************************************************
// Add AIS String
// make sure characters fall into range defined in table 14
// https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1371-1-200108-S!!PDF-E.pdf
void tN2kMsg::AddAISStr(const char *str, int len) {
char AISStr[21]; // Max AIS strlen defined in ITU-R M.1371-1
size_t i;
for (i = 0; str[i] != '\0' && i < sizeof(AISStr); i++ ) {
char c = toupper((int)str[i]);
AISStr[i] = (c >= 0x20 && c <= 0x5F) ? c : '?';
}
AISStr[i]='\0';
AddStr(AISStr,len,false,'@');
}


//*****************************************************************************
void tN2kMsg::AddVarStr(const char *str, bool UsePgm) {
int len=(str!=0?strlen(str):0);
Expand Down
9 changes: 9 additions & 0 deletions src/N2kMsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,15 @@ class tN2kMsg
*/
void AddStr(const char *str, int len, bool UsePgm=false, unsigned char fillChar=0xff);

/************************************************************************//**
* \brief Add string value to the buffer after filtering characters as defined in ITU-R M.1371-1
* The string will be added to the end (indicated by \ref DataLen) of
* the byte array \ref Data.
* \param str String as pointer to a char array
* \param len Length of the string
*/
void AddAISStr(const char *str, int len);

/************************************************************************//**
* \brief Add string value to the buffer
* This method determines the length of the string by it self using strlen().
Expand Down

0 comments on commit 97f9926

Please sign in to comment.