Skip to content

Commit

Permalink
Merge pull request #390 from lsoltero/master
Browse files Browse the repository at this point in the history
Ensure that AIS fixed strings are ITU-R M.1371-1 compliant
  • Loading branch information
ttlappalainen authored Mar 7, 2024
2 parents f904812 + 27d5488 commit 29338ce
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 29 deletions.
12 changes: 12 additions & 0 deletions Documents/src/changes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# Changes to the Library {#changes}
\tableofcontents

## 06.03.2024

-- reduced memory footprint for N2kMsg::AddAISStr
-- bumped library version
-- Ensure that strings added by N2kMsg::AddAISStr are 6 bit ASCII ITU-R M.1371-1 table 14 compliant

## 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.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"url": "http://www.kave.fi",
"maintainer": true
},
"version": "4.21.1",
"version": "4.21.2",
"license": "MIT",
"frameworks": "*",
"platforms": "*"
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
20 changes: 10 additions & 10 deletions src/N2kMessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1611,18 +1611,18 @@ bool AppendN2kPGN129285(tN2kMsg &N2kMsg, uint16_t ID, const char* Name, double L
//*****************************************************************************
// AIS static data A
void SetN2kPGN129794(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
uint32_t IMOnumber, char *Callsign, char *Name, uint8_t VesselType, double Length,
uint32_t IMOnumber, const char *Callsign, const char *Name, uint8_t VesselType, double Length,
double Beam, double PosRefStbd, double PosRefBow, uint16_t ETAdate, double ETAtime,
double Draught, char *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
double Draught, const char *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
tN2kAISDTE DTE, tN2kAISTransceiverInformation AISinfo)
{
N2kMsg.SetPGN(129794L);
N2kMsg.Priority=6;
N2kMsg.AddByte((Repeat & 0x03)<<6 | (MessageID & 0x3f));
N2kMsg.Add4ByteUInt(UserID);
N2kMsg.Add4ByteUInt(IMOnumber);
N2kMsg.AddStr(Callsign, 7, false, '@');
N2kMsg.AddStr(Name, 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 @@ -1631,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(Destination, 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 @@ -1670,13 +1670,13 @@ 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, char *Name)
void SetN2kPGN129809(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID, const char *Name)
{
N2kMsg.SetPGN(129809L);
N2kMsg.Priority=6;
N2kMsg.AddByte((Repeat & 0x03)<<6 | (MessageID & 0x3f));
N2kMsg.Add4ByteUInt(UserID);
N2kMsg.AddStr(Name, 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 @@ -1696,16 +1696,16 @@ bool ParseN2kPGN129809(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat
//*****************************************************************************
// AIS static data class B part B
void SetN2kPGN129810(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
uint8_t VesselType, char *Vendor, char *Callsign, double Length, double Beam,
uint8_t VesselType, const char *Vendor, const char *Callsign, double Length, double Beam,
double PosRefStbd, double PosRefBow, uint32_t MothershipID)
{
N2kMsg.SetPGN(129810L);
N2kMsg.Priority=6;
N2kMsg.AddByte((Repeat & 0x03)<<6 | (MessageID & 0x3f));
N2kMsg.Add4ByteUInt(UserID);
N2kMsg.AddByte(VesselType);
N2kMsg.AddStr(Vendor, 7, false, '@');
N2kMsg.AddStr(Callsign, 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
39 changes: 22 additions & 17 deletions src/N2kMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -4287,12 +4287,13 @@ 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 - Max. 7 chars will be used. Input string will be converted to contain only SixBit ASCII character set (see. ITU-R M.1371-1)
* \param Name Name of the vessel;
* Maximum 20 characters 6 bit ASCII;
* Maximum 20 characters;
* For SAR aircraft, it should be set
* to “SAR AIRCRAFT NNNNNNN” where NNNNNNN equals
* the aircraft registration number
* Input string will be converted to contain only SixBit ASCII character set (see. ITU-R M.1371-1)
* \param VesselType Vessel Type
* 0 = not available or no ship = default
* 1-99 = as defined in § 3.3.2
Expand All @@ -4307,7 +4308,8 @@ inline bool ParseN2kPGNSatellitesInView(const tN2kMsg& N2kMsg, uint8_t SVIndex,
* \param ETAtime EstimatedTimeOfArrival -seconds since midnight (UTC)
* \param Draught Maximum present static draught
* \param Destination Destination -
* Maximum 20 characters using 6-bit ASCII
* Maximum 20 characters
* Input string will be converted to contain only SixBit ASCII character set (see. ITU-R M.1371-1)
* \param AISversion AIS version, see \ref tN2kAISVersion
* \param GNSStype Type of GNSS, see \ref tN2kGNSStype
* \param DTE Data terminal equipment (DTE) ready
Expand All @@ -4317,9 +4319,9 @@ inline bool ParseN2kPGNSatellitesInView(const tN2kMsg& N2kMsg, uint8_t SVIndex,
* see \ref tN2kAISTransceiverInformation
*/
void SetN2kPGN129794(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
uint32_t IMOnumber, char *Callsign, char *Name, uint8_t VesselType, double Length,
uint32_t IMOnumber, const char *Callsign, const char *Name, uint8_t VesselType, double Length,
double Beam, double PosRefStbd, double PosRefBow, uint16_t ETAdate, double ETAtime,
double Draught, char *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
double Draught, const char *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
tN2kAISDTE DTE, tN2kAISTransceiverInformation AISinfo);

/************************************************************************//**
Expand All @@ -4330,9 +4332,9 @@ void SetN2kPGN129794(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, u
* of the source code. See parameter details on \ref SetN2kPGN129794
*/
inline void SetN2kAISClassAStatic(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
uint32_t IMOnumber, char *Callsign, char *Name, uint8_t VesselType, double Length,
uint32_t IMOnumber, const char *Callsign, const char *Name, uint8_t VesselType, double Length,
double Beam, double PosRefStbd, double PosRefBow, uint16_t ETAdate, double ETAtime,
double Draught, char *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
double Draught, char const *Destination, tN2kAISVersion AISversion, tN2kGNSStype GNSStype,
tN2kAISDTE DTE, tN2kAISTransceiverInformation AISinfo) {
SetN2kPGN129794(N2kMsg, MessageID, Repeat, UserID, IMOnumber, Callsign, Name, VesselType, Length,
Beam, PosRefStbd, PosRefBow, ETAdate, ETAtime, Draught, Destination, AISversion, GNSStype, DTE, AISinfo);
Expand All @@ -4359,7 +4361,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 @@ -4437,13 +4439,14 @@ inline bool ParseN2kAISClassAStatic(const tN2kMsg &N2kMsg, uint8_t &MessageID, t
* see \ref tN2kAISRepeat
* \param UserID MMSI Number
* \param Name Name of the vessel;
* Maximum 20 characters 6 bit ASCII;
* Maximum 20 characters;
* For SAR aircraft, it should be set
* to “SAR AIRCRAFT NNNNNNN” where NNNNNNN equals
* the aircraft registration number
* Input string will be converted to contain only SixBit ASCII character set (see. ITU-R M.1371-1)
*
*/
void SetN2kPGN129809(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID, char *Name);
void SetN2kPGN129809(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID, const char *Name);

/************************************************************************//**
* \brief Setting up Message "AIS static data class B part A" - PGN 129809
Expand All @@ -4452,7 +4455,7 @@ void SetN2kPGN129809(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, u
* Alias of PGN 129809. This alias was introduced to improve the readability
* of the source code. See parameter details on \ref SetN2kPGN129809
*/
inline void SetN2kAISClassBStaticPartA(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID, char *Name) {
inline void SetN2kAISClassBStaticPartA(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID, const char *Name) {
SetN2kPGN129809(N2kMsg, MessageID, Repeat, UserID, Name);
}

Expand All @@ -4475,10 +4478,11 @@ inline void SetN2kAISClassBStaticPartA(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kA
* see \ref tN2kAISRepeat
* \param UserID MMSI Number
* \param Name Name of the vessel;
* Maximum 20 characters 6 bit ASCII;
* Maximum 20 characters;
* For SAR aircraft, it should be set
* to “SAR AIRCRAFT NNNNNNN” where NNNNNNN equals
* the aircraft registration number
* Input string will be converted to contain only SixBit ASCII character set (see. ITU-R M.1371-1)
* \param NameBufSize size of Name buffer
*
* \return true Parsing of PGN Message successful
Expand Down Expand Up @@ -4524,7 +4528,8 @@ 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
* Max. 7 chars will be used. Input string will be converted to contain only SixBit ASCII character set (see. ITU-R M.1371-1)
* \param Callsign Call Sign - Max. 7 chars will be used. Input string will be converted to contain only SixBit ASCII character set (see. 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 All @@ -4533,7 +4538,7 @@ inline bool ParseN2kAISClassBStaticPartA(const tN2kMsg &N2kMsg, uint8_t &Message
*
*/
void SetN2kPGN129810(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
uint8_t VesselType, char *Vendor, char *Callsign, double Length, double Beam,
uint8_t VesselType, const char *Vendor, const char *Callsign, double Length, double Beam,
double PosRefStbd, double PosRefBow, uint32_t MothershipID);

/************************************************************************//**
Expand All @@ -4544,7 +4549,7 @@ void SetN2kPGN129810(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, u
* of the source code. See parameter details on \ref SetN2kPGN129810
*/
inline void SetN2kAISClassBStaticPartB(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kAISRepeat Repeat, uint32_t UserID,
uint8_t VesselType, char *Vendor, char *Callsign, double Length, double Beam,
uint8_t VesselType, const char *Vendor, const char *Callsign, double Length, double Beam,
double PosRefStbd, double PosRefBow, uint32_t MothershipID) {
SetN2kPGN129810(N2kMsg, MessageID, Repeat, UserID, VesselType, Vendor, Callsign, Length, Beam,
PosRefStbd, PosRefBow, MothershipID);
Expand Down Expand Up @@ -4578,7 +4583,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 All @@ -4591,7 +4596,7 @@ inline void SetN2kAISClassBStaticPartB(tN2kMsg &N2kMsg, uint8_t MessageID, tN2kA
*
*/
bool ParseN2kPGN129810(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID,
uint8_t &VesselType, char *Vendor, size_t VendorBufSize, char *Callsign, size_t CallsignBufSize,double &Length, double &Beam,
uint8_t &VesselType, const char *Vendor, size_t VendorBufSize, const char *Callsign, size_t CallsignBufSize,double &Length, double &Beam,
double &PosRefStbd, double &PosRefBow, uint32_t &MothershipID);

/************************************************************************//**
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) {
unsigned char *buf=Data+DataLen;
for (; len>0 && *str!=0 && DataLen<MaxDataLen; len--, DataLen++, buf++, str++) {
char c = toupper((int)*str);
*buf=(c >= 0x20 && c <= 0x5F) ? c : '?';
}

if ( len > MaxDataLen-DataLen ) len=MaxDataLen-DataLen;
if ( len>0 ) memset(buf,'@',len);
}


//*****************************************************************************
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 29338ce

Please sign in to comment.