3084 lines
115 KiB
C
3084 lines
115 KiB
C
//-----------------------------------------------------------------------------*****************************************************************************************************
|
||
// Fichier NMEA.C
|
||
//
|
||
// Contient toutes les fonctions liées à la gestion des PGN NMEA provenant du Compagnon
|
||
// !!!!! Pour intégrer un nouveau PGN, voir PROCEDURE_PGN ci-dessous !!!!!
|
||
//-----------------------------------------------------------------------------*****************************************************************************************************/
|
||
|
||
//#define __DEBUG_NMEA //Décommenter cette ligne pour avoir les messages de debug
|
||
|
||
// Includes :
|
||
#include "main.h"
|
||
|
||
// Prototypes :
|
||
int8_t init_nmea(void);
|
||
void gestion_nmea(void);
|
||
int8_t traitement_pgn_compagnon(struct Struct_pgn_nmea pgn);
|
||
|
||
// Variables globales :
|
||
struct Struct_nmea nmea;
|
||
|
||
|
||
/**********************************************************************************************************************************************************************************
|
||
Fonction INIT_NMEA
|
||
|
||
Fonction d'initialisation du réseau NMEA
|
||
**********************************************************************************************************************************************************************************/
|
||
int8_t init_nmea(void)
|
||
{
|
||
|
||
nmea.sequenceur.etat = ETAT_SEQUENCEUR_NMEA_INIT;
|
||
nmea.sequenceur.compteur = NMEA_TEMPO_INIT;
|
||
nmea.sequenceur.compteur_time_out = 0;
|
||
|
||
init_annuaire_nmea(); // Contrairement aux autres annuaires (k-bus, Ow), il n'est pas nécessaire d'attendre l'initialisation dans 'systeme.c'
|
||
|
||
// Affichage du message de débug :
|
||
affichage_debug(__FILE__, __LINE__, "Initialisation du réseau NMEA\t: OK", TYPE_MESSAGE_DEBUG_OK);
|
||
|
||
return(0);
|
||
}
|
||
|
||
|
||
//==================================================================================================================================================================
|
||
// Fonction : Appelée en tâche de fond, cette fonction gère le réseau NMEA dans son ensemble
|
||
// Reçoit : Rien
|
||
// Renvoit : Rien
|
||
//==================================================================================================================================================================
|
||
void gestion_nmea(void)
|
||
{
|
||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||
|
||
switch(nmea.sequenceur.etat)
|
||
{
|
||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
case ETAT_SEQUENCEUR_NMEA_INIT :
|
||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
{
|
||
if (nmea.sequenceur.compteur == 0)
|
||
{
|
||
nmea.sequenceur.etat = ETAT_SEQUENCEUR_NMEA_REPOS;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
case ETAT_SEQUENCEUR_NMEA_REPOS :
|
||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
{
|
||
// if (nmea.sequenceur.compteur == 0)
|
||
// {
|
||
// nmea.sequenceur.compteur = NMEA_PERIODE_CHECK; // A priori, toutes les 100ms
|
||
// }
|
||
|
||
break;
|
||
}
|
||
|
||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
default :
|
||
//----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
{
|
||
sprintf(tmp, "L'état du séquenceur NMEA est inconnu [%i]. Il est repositionné au REPOS", nmea.sequenceur.etat);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
|
||
nmea.sequenceur.etat = ETAT_SEQUENCEUR_NMEA_REPOS;
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//==================================================================================================================================================================
|
||
// Fonction : Appelée lors de la réception d'une commande 'c_bus_up_commande_etat_pgn_nmea()' dans 'c_commandes.c', cette fonction traite un PGN reçu du Compagnon
|
||
// Reçoit : Le PGN à traiter
|
||
// Renvoit : 0 si traitement Ok, -1 si erreur.
|
||
//==================================================================================================================================================================
|
||
int8_t traitement_pgn_compagnon(struct Struct_pgn_nmea pgn)
|
||
{
|
||
uint16_t i, j;
|
||
bool flag_pgn_present_dans_annuaire;
|
||
bool flag_pgn_present_dans_catalogue;
|
||
uint16_t indice_catalogue;
|
||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||
|
||
|
||
//-----------------------------------------------------------------------------------------
|
||
// PGN déjà présent dans l'annuaire :
|
||
//-----------------------------------------------------------------------------------------
|
||
flag_pgn_present_dans_annuaire = false;
|
||
for (i = 0; i < NMEA_MAX_NOMBRE_PGN; i++)
|
||
{
|
||
if (!nmea.annuaire[i].flag_validite) continue;
|
||
|
||
if (nmea.annuaire[i].pgn == pgn.pgn)
|
||
{
|
||
flag_pgn_present_dans_annuaire = true;
|
||
|
||
// Mise à jour des dernières valeurs dans l'annuaire :
|
||
nmea.annuaire[i].priority = pgn.priority;
|
||
nmea.annuaire[i].source = pgn.source;
|
||
nmea.annuaire[i].timestamp = pgn.timestamp;
|
||
nmea.annuaire[i].lg_data = pgn.lg_data;
|
||
for (j = 0; j < pgn.lg_data; j ++) nmea.annuaire[i].data[j] = pgn.data[j];
|
||
|
||
//---------------------------
|
||
// PGN Actif :
|
||
//---------------------------
|
||
if (nmea.annuaire[i].actif == 1)
|
||
{
|
||
for (j = 0; ((j < NMEA_MAX_NOMBRE_PGN) && (catalogue_pgns[j].pgn != 0)); j ++) // Recherche des infos de config dans le catalogue (le PGN s'y trouve forcément car il a été créé dans l'annuaire...)
|
||
{
|
||
if (catalogue_pgns[j].pgn == pgn.pgn) // Le PGN a été trouvé dans le catalogue
|
||
{
|
||
// ------------------------------
|
||
// Si le PGN a déjà été détecté par le Compagnon (il est donc complètement configuré sur l'Appli et sur le Compagnon) :
|
||
if (nmea.annuaire[i].flag_presence)
|
||
{
|
||
catalogue_pgns[j].fonction_parse_pgn(i, NMEA_PARSE_MODE_MISE_A_JOUR); // Appel de la fonction de parsing de ce PGN en mode MISE A JOUR.
|
||
}
|
||
|
||
//-------------------------------
|
||
// Premier retour du Compagnon sur ce PGN :
|
||
else
|
||
{
|
||
#ifdef __DEBUG_NMEA
|
||
sprintf(tmp, "PGN %i : Ce PGN est Actif et c'est sa première apparition depuis le reset du Compagnon. Passage à Présent + config du Compagnon", nmea.annuaire[i].pgn);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
c_bus_down_commande_config_pgn_nmea(i);
|
||
nmea.annuaire[i].flag_presence = true;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//---------------------------
|
||
// PGN Inactif :
|
||
//---------------------------
|
||
else if (nmea.annuaire[i].actif == 0)
|
||
{
|
||
enregistrement_date_pgn_nmea(i);
|
||
}
|
||
|
||
//---------------------------
|
||
// PGN désactivé car non connu dans le catalogue :
|
||
//---------------------------
|
||
else ;
|
||
|
||
break; // Il est inutile de poursuivre lorsque le PGN a été trouvé.
|
||
}
|
||
}
|
||
|
||
if (flag_pgn_present_dans_annuaire) return (0); // Le traitement est terminé...
|
||
|
||
|
||
//-----------------------------------------------------------------------------------------
|
||
// PGN pas encore présent dans l'annuaire :
|
||
//-----------------------------------------------------------------------------------------
|
||
|
||
//----------------------------------
|
||
// PGN présent dans le catalogue ? :
|
||
flag_pgn_present_dans_catalogue = false;
|
||
for (i = 0; ((i < NMEA_MAX_NOMBRE_PGN) && (catalogue_pgns[i].pgn != 0)); i ++)
|
||
{
|
||
if (catalogue_pgns[i].pgn == pgn.pgn) // Le PGN a été trouvé dans le catalogue :
|
||
{
|
||
flag_pgn_present_dans_catalogue = true;
|
||
indice_catalogue = i;
|
||
|
||
break; // Sortie de la boucle du catalogue puisqu'on a trouvé l'entrée.
|
||
}
|
||
}
|
||
|
||
//----------------------------------
|
||
// Ajout à l'annuaire :
|
||
for (i = 0; i < NMEA_MAX_NOMBRE_PGN; i ++) // On recherche ensuite le premier emplacement libre :
|
||
{
|
||
if (!nmea.annuaire[i].flag_validite) // L'emplacement est libre.
|
||
{
|
||
nmea.annuaire[i].flag_validite = true;
|
||
nmea.annuaire[i].flag_presence = true;
|
||
nmea.annuaire[i].pgn = pgn.pgn;
|
||
|
||
//-----------------------------------------------
|
||
// PGN présent dans le catalogue :
|
||
//-----------------------------------------------
|
||
if (flag_pgn_present_dans_catalogue)
|
||
{
|
||
nmea.annuaire[i].actif = 0; // Par défaut, le PGN est Inactif puisqu'il ne pourra être passé à Actif que par Qt (qui a d'abord besoin qu'il soit créé...)
|
||
nmea.annuaire[i].priority = pgn.priority;
|
||
nmea.annuaire[i].source = pgn.source;
|
||
nmea.annuaire[i].timestamp = pgn.timestamp;
|
||
nmea.annuaire[i].type = catalogue_pgns[indice_catalogue].type; // Pas utile tout de suite (car Actif = 0) mais permet de ne pas le faire lors de l'activation qui se fait à plusieurs endroits (et de l'oublier - vécu...)
|
||
nmea.annuaire[i].periode_mini = catalogue_pgns[indice_catalogue].periode_mini; // Idem...
|
||
nmea.annuaire[i].lg_data = 0;
|
||
#ifdef __DEBUG_NMEA
|
||
sprintf(tmp, "Nouveau PGN enregistré en position %i : %i", i, nmea.annuaire[i].pgn);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
catalogue_pgns[indice_catalogue].fonction_parse_pgn(i, NMEA_PARSE_MODE_CREATION); // Appel de la fonction de parsing de ce PGN en mode CREATION.
|
||
// NB : on ne fait rien vers le Compagnon car, par défaut, les Fields de ce PGN sont tous créés en mode Inactifs.
|
||
}
|
||
|
||
//-----------------------------------------------
|
||
// PGN absent du catalogue :
|
||
//-----------------------------------------------
|
||
else
|
||
{
|
||
nmea.annuaire[i].actif = -1; // NB : on garde le PGN dans l'annuaire pour qu'on le repère comme étant Désactivé (Actif = -1) à l'avenir.
|
||
|
||
#ifdef __DEBUG_NMEA
|
||
sprintf(tmp, "Le PGN %i n'est pas référencé dans le catalogue NMEA2000. Il est donc désactivé (aucun traitement à l'avenir)...", pgn.pgn);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
#endif
|
||
|
||
c_bus_down_commande_config_pgn_nmea(i); // Commande de désactivation (Actif = -1) vers le Compagnon pour qe ce dernier ne le traite plus à l'avenir.
|
||
|
||
return (-1);
|
||
}
|
||
|
||
break; // Sortie de la boucle de recherche d'un emplacement libre.
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------
|
||
// Nombre de PGN trop important :
|
||
//-----------------------------------------------
|
||
if (i == NMEA_MAX_NOMBRE_PGN)
|
||
{
|
||
sprintf(tmp, "Le nombre maximal de PGN a été atteint (%i). Le PGN %i n'est pas traité...", NMEA_MAX_NOMBRE_PGN, pgn.pgn);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
|
||
// PROCEDURE_PGN :
|
||
//
|
||
// Pour intégrer un nouveau PGN, il faut :
|
||
// 1- Dans 'nmea.h', il faut créer les n° de Field qui seront utilisés par ShipHeart. L'affectation des n° est théoriquement libre mais, par principe, on réutilise
|
||
// les n° utilisés dans la doc NMEA (Liste PGN NMEA 2024 - V3.002 au moment d'écrire ces lignes)
|
||
// 2- Créer une fonction de parsing du type 'Parse_pgn_xxxxxx()'.
|
||
// Le plus simple est de dupliquer la fonction template et remplacer xxxxxx par le code du PGN.
|
||
// Renseigner la longueur minimale (LG_DATA_MINI) que la trame doit faire pour pouvoir être traitée (a minima, jusqu'au dernier field qui sera décodé car aucun contrôle n'est fait ensuite).
|
||
// Dans le case NMEA_PARSE_MODE_CREATION, ajouter les appels correspondant aux fields que l'on souhaite intégrer. Penser à renseigner la désignation (celle
|
||
// qui sera affichée par défaut dans la liste des PGNs sur Qt - en Anglais).
|
||
// Dans le case NMEA_PARSE_MODE_MISE_A_JOUR, ajouter les différents fields dans l'ordre de lecture. Généralement, après SID. Prendre exemple sur les PGN existants
|
||
// pour dupliquer un traitement approchant. IMPORTANT : la valeur retournée DOIT être un nombre (float).
|
||
// 3- Ajouter le nouveau PGN dans le "Catalogue des PGNs" (plus bas, dans ce fichier).
|
||
// Ajouter une ligne dans l'ordre chrono des PGNs. Les valeurs à renseigner sont :
|
||
// - le code du Pgn,
|
||
// - le Type (pour cela, s'aider de la liste située en dessous, en commentaires),
|
||
// - La Période mini (x10ms). Elle permet de "limiter" les remontées de données de la part du Compagnon et, ainsi, limiter la charge (du Compagnon, de l'Appli, etc...)
|
||
// - la fonction de parsing créée au 2.
|
||
// Important : terminer la liste par une entrée avec le code de Pgn nul. C'est cette ligne qui est détectée pour terminer la liste.
|
||
// La taille maxi du catalogue est NMEA_MAX_NOMBRE_PGN mais un dépassement sera détecté par la compilation.
|
||
// 4- Compiler.
|
||
// 5- Tester avec le simulateur.
|
||
// 6- Lorsque les tests sont concluants, commenter le #define '#define DEBUG_PGN_xxxxxx' pour ne pas surcharger la sortie de debug.
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
//
|
||
// Fonctions de Parsing de PNG :
|
||
//
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
|
||
// L'aide sur les fonctions de parsing peut se trouver ici : https://ttlappalainen.github.io/NMEA2000/group__group__msg_parsers.html#ga3472b7dcf7ece7265708e20ee8bcf78a
|
||
// Rechercher sur la gauche le N° de PGN...
|
||
|
||
// Extrait de 'shipheart_sql.sql' :
|
||
// (50,2, "Capt_sans_unite", "Sans unité", " ", 1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (51,2, "Capt_tension_v", "Tension", "V", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (52,2, "Capt_tension_mv", "Tension", "mV", 10, 0, 1, "2020-01-01 00:00:00"),
|
||
// (53,2, "Capt_courant_a", "Intensité", "A", 0.01, 0, 1, "2020-01-01 00:00:00"),
|
||
// (54,2, "Capt_courant_ma", "Intensité", "mA", 0.5, 0, 1, "2020-01-01 00:00:00"),
|
||
// (55,2, "Capt_puissance_w", "Puissance", "W", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (56,2, "Capt_puissance_va", "Puissance apparente", "VA", 1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (57,2, "Capt_puissance_db", "Puissance", "dB", 0.2, 0, 1, "2020-01-01 00:00:00"),
|
||
// (58,2, "Capt_frequence", "Fréquence", "Hz", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (59,2, "Capt_resistance", "Résistance", "Ohms", 1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (60,2, "Capt_temperature", "Température", "°C", 0.1, 2, 1, "2020-01-01 00:00:00"),
|
||
// (61,2, "Capt_pression_atm", "Pression atmosphérique", "hPa", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (62,2, "Capt_humidite", "Humidité", "%HR", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (63,2, "Capt_acceleration", "Accélération", "g", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (64,2, "Capt_position", "Position", "°", 0.0001, 0, 1, "2020-01-01 00:00:00"),
|
||
// (65,2, "Capt_pourcentage", "Pourcentage", "%", 1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (66,2, "Capt_distance_m", "Distance", "m", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (67,2, "Capt_distance_km", "Distance", "km", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (68,2, "Capt_distance_nq", "Distance", "nq", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (69,2, "Capt_vitesse_kts", "Vitesse", "kts", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (70,2, "Capt_vitesse_kmh", "Vitesse", "km/h", 0.1, 0, 1, "2020-01-01 00:00:00"),
|
||
// (71,2, "Capt_angle_degres", "Angle", "°", 1, 0, 1, "2020-01-01 00:00:00");
|
||
|
||
|
||
|
||
//==================================================================================================================================================================
|
||
// PGN : 126992
|
||
// Fonction : System date/time, pri=3, period=1000
|
||
//==================================================================================================================================================================
|
||
int8_t Parse_pgn_126992(uint16_t rang, uint8_t mode)
|
||
{
|
||
// #define DEBUG_PGN_126992
|
||
const uint8_t LG_DATA_MINI = 8;
|
||
uint8_t index;
|
||
uint8_t val_u8;
|
||
uint16_t val_u16;
|
||
uint32_t val_u32;
|
||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||
|
||
|
||
if (nmea.annuaire[rang].pgn != 126992) return (-1);
|
||
|
||
switch (mode)
|
||
{
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_CREATION:
|
||
{
|
||
creation_pgn_field_nmea(rang, NMEA_126992_TIME_SOURCE, "Capt_sans_unite", 0, 0, "Time source");
|
||
creation_pgn_field_nmea(rang, NMEA_126992_SYSTEM_DATE, "Capt_sans_unite", 0, 0, "System date");
|
||
creation_pgn_field_nmea(rang, NMEA_126992_SYSTEM_TIME, "Capt_sans_unite", 0, 0, "System time");
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_MISE_A_JOUR:
|
||
{
|
||
if (nmea.annuaire[rang].lg_data < LG_DATA_MINI)
|
||
{
|
||
sprintf(tmp, "La longueur de DATA du PGN %i n'est pas correcte pour être traitée en mode MISE A JOUR (reçu : %i, attendu : %i mini)", nmea.annuaire[rang].pgn, nmea.annuaire[rang].lg_data, LG_DATA_MINI);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
return (-1);
|
||
}
|
||
|
||
index = 0;
|
||
|
||
//----------------------------------
|
||
// Sequence ID :
|
||
index ++;
|
||
|
||
//----------------------------------
|
||
// Time source :
|
||
val_u8 = nmea.annuaire[rang].data[index ++];
|
||
enregistrement_pgn_field_nmea(rang, NMEA_126992_TIME_SOURCE, (val_u8 & 0x0F) );
|
||
#ifdef DEBUG_PGN_126992
|
||
sprintf(tmp, "PGN %i : Time source = %i", nmea.annuaire[rang].pgn, (val_u8 & 0x0F) );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// System Date :
|
||
val_u16 = (uint16_t) nmea.annuaire[rang].data[index ++];
|
||
val_u16 |= ((uint16_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_126992_SYSTEM_DATE, val_u16);
|
||
#ifdef DEBUG_PGN_126992
|
||
sprintf(tmp, "PGN %i : System Date = %i", nmea.annuaire[rang].pgn, val_u16);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// System Time :
|
||
val_u32 = (uint32_t) nmea.annuaire[rang].data[index ++];
|
||
val_u32 |= ((uint32_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
val_u32 |= ((uint32_t) nmea.annuaire[rang].data[index ++]) << 16;
|
||
val_u32 |= ((uint32_t) nmea.annuaire[rang].data[index ++]) << 24;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_126992_SYSTEM_TIME, ((float) val_u32 * 0.0001) );
|
||
#ifdef DEBUG_PGN_126992
|
||
sprintf(tmp, "PGN %i : System Time = %.4f", nmea.annuaire[rang].pgn, ((float) val_u32 * 0.0001));
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_SUPPRESSION:
|
||
{
|
||
suppression_pgn_nmea(rang);
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
default: break;
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
//==================================================================================================================================================================
|
||
// PGN : 129029
|
||
// Fonction : GNSS Position Data, pri=3, period=1000
|
||
//==================================================================================================================================================================
|
||
int8_t Parse_pgn_129029(uint16_t rang, uint8_t mode)
|
||
{
|
||
// #define DEBUG_PGN_129029
|
||
const uint8_t LG_DATA_MINI = 38;
|
||
uint8_t index;
|
||
uint8_t val_u8;
|
||
uint16_t val_u16;
|
||
uint32_t val_u32;
|
||
uint64_t val_u64;
|
||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||
|
||
|
||
if (nmea.annuaire[rang].pgn != 129029) return (-1);
|
||
|
||
switch (mode)
|
||
{
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_CREATION:
|
||
{
|
||
creation_pgn_field_nmea(rang, NMEA_129029_DAYS_SINCE_1970, "Capt_sans_unite", 0, 0, "Numer of days since January 1st, 1970");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_SECONDS_SINCE_MIDNIGHT, "Capt_sans_unite", 0, 0, "Number of seconds since midnight");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_LATITUDE, "Capt_latitude", 0, 0, "Latitude");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_LONGITUDE, "Capt_longitude", 0, 0, "Longitude");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_GNSS_TYPE, "Capt_sans_unite", 0, 0, "GNSS Type");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_GNSS_METHOD, "Capt_sans_unite", 0, 0, "GNSS Method");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_SATELLITES_NUMBER, "Capt_sans_unite", 0, 0, "Satellites number");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_HDOP, "Capt_sans_unite", 1, 2, "HDOP");
|
||
creation_pgn_field_nmea(rang, NMEA_129029_PDOP, "Capt_sans_unite", 1, 2, "PDOP");
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_MISE_A_JOUR:
|
||
{
|
||
if (nmea.annuaire[rang].lg_data < LG_DATA_MINI)
|
||
{
|
||
sprintf(tmp, "La longueur de DATA du PGN %i n'est pas correcte pour être traitée en mode MISE A JOUR (reçu : %i, attendu : %i mini)", nmea.annuaire[rang].pgn, nmea.annuaire[rang].lg_data, LG_DATA_MINI);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
return (-1);
|
||
}
|
||
|
||
index = 0;
|
||
|
||
//----------------------------------
|
||
// Sequence ID :
|
||
index ++;
|
||
|
||
//----------------------------------
|
||
// Number of days since 1970 :
|
||
val_u16 = (uint16_t) nmea.annuaire[rang].data[index ++];
|
||
val_u16 |= ((uint16_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_DAYS_SINCE_1970, val_u16);
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : Number of days since 1970 = %i", nmea.annuaire[rang].pgn, val_u16);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Seconds since midnight :
|
||
val_u32 = (uint32_t) nmea.annuaire[rang].data[index ++];
|
||
val_u32 |= ((uint32_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
val_u32 |= ((uint32_t) nmea.annuaire[rang].data[index ++]) << 16;
|
||
val_u32 |= ((uint32_t) nmea.annuaire[rang].data[index ++]) << 24;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_SECONDS_SINCE_MIDNIGHT, ((float) val_u32 * 0.0001) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : Number of seconds since midnight = %.4f", nmea.annuaire[rang].pgn, ((float) val_u32 * 0.0001));
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Latitude :
|
||
val_u64 = (uint64_t) nmea.annuaire[rang].data[index ++];
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 16;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 24;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 32;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 40;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 48;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 56;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_LATITUDE, ((float) val_u64) * (1e-16) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : Latitude = %f", nmea.annuaire[rang].pgn, ((float) val_u64) * (1e-16) );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Longitude :
|
||
val_u64 = (uint64_t) nmea.annuaire[rang].data[index ++];
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 16;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 24;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 32;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 40;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 48;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 56;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_LONGITUDE, ((float) val_u64) * (1e-16) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : Longitude = %f", nmea.annuaire[rang].pgn, ((float) val_u64) * (1e-16));
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Altitude :
|
||
val_u64 = (uint64_t) nmea.annuaire[rang].data[index ++];
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 16;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 24;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 32;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 40;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 48;
|
||
val_u64 |= ((uint64_t) nmea.annuaire[rang].data[index ++]) << 56;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_ALTITUDE, ((float) val_u64) * (1e-6) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : Altitude = %f", nmea.annuaire[rang].pgn, ((float) val_u64) * (1e-6));
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// GNSS Type et GNSS Methode :
|
||
val_u8 = nmea.annuaire[rang].data[index ++];
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_GNSS_TYPE, (val_u8 & 0x0F) );
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_GNSS_METHOD, ((val_u8 >> 4) & 0x0F) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : GNSS Type = %i", nmea.annuaire[rang].pgn, (val_u8 & 0x0F) );
|
||
sprintf(tmp, "PGN %i : GNSS Method = %i", nmea.annuaire[rang].pgn, ((val_u8 >> 4) & 0x0F) );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Integrity 2 bit, reserved 6 bits :
|
||
index ++;
|
||
|
||
//----------------------------------
|
||
// Nb satellites :
|
||
val_u8 = nmea.annuaire[rang].data[index ++];
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_SATELLITES_NUMBER, val_u8 );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : Satellites Number = %i", nmea.annuaire[rang].pgn, val_u8 );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// HDOP :
|
||
val_u16 = (uint16_t) nmea.annuaire[rang].data[index ++];
|
||
val_u16 |= ((uint16_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_HDOP, ((float) val_u16 * 0.01) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : HDOP = %.4f", nmea.annuaire[rang].pgn, ((float) val_u16 * 0.01));
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// PDOP :
|
||
val_u16 = (uint16_t) nmea.annuaire[rang].data[index ++];
|
||
val_u16 |= ((uint16_t) nmea.annuaire[rang].data[index ++]) << 8;
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129029_PDOP, ((float) val_u16 * 0.01) );
|
||
#ifdef DEBUG_PGN_129029
|
||
sprintf(tmp, "PGN %i : PDOP = %.4f", nmea.annuaire[rang].pgn, ((float) val_u16 * 0.01));
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Non traités :
|
||
// GeoidalSeparation=N2kMsg.Get4ByteDouble(0.01,Index);
|
||
// nReferenceStations=N2kMsg.GetByte(Index);
|
||
// if (nReferenceStations!=N2kUInt8NA && nReferenceStations>0)
|
||
// {
|
||
// Note that we return real number of stations, but we only have variabes for one.
|
||
// vi=N2kMsg.Get2ByteUInt(Index);
|
||
// ReferenceStationType=(tN2kGNSStype)(vi & 0x0f);
|
||
// ReferenceSationID=(vi>>4);
|
||
// AgeOfCorrection=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
// }
|
||
// else
|
||
// {
|
||
// ReferenceStationType = N2kGNSSt_GPS;
|
||
// ReferenceSationID = N2kInt16NA;
|
||
// AgeOfCorrection = N2kDoubleNA;
|
||
// }
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_SUPPRESSION:
|
||
{
|
||
suppression_pgn_nmea(rang);
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
default: break;
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
|
||
//==================================================================================================================================================================
|
||
// PGN : 129540
|
||
// Fonction : GNSS Sats in View
|
||
//==================================================================================================================================================================
|
||
int8_t Parse_pgn_129540(uint16_t rang, uint8_t mode)
|
||
{
|
||
//#define DEBUG_PGN_129540
|
||
const uint8_t LG_DATA_MINI = 3;
|
||
uint8_t index;
|
||
uint8_t val_u8;
|
||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||
|
||
|
||
if (nmea.annuaire[rang].pgn != 129540) return (-1);
|
||
|
||
switch (mode)
|
||
{
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_CREATION:
|
||
{
|
||
creation_pgn_field_nmea(rang, NMEA_129540_SATELLITES_IN_VIEW, "Capt_sans_unite", 0, 0, "Satellites in view");
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_MISE_A_JOUR:
|
||
{
|
||
if (nmea.annuaire[rang].lg_data < LG_DATA_MINI)
|
||
{
|
||
sprintf(tmp, "La longueur de DATA du PGN %i n'est pas correcte pour être traitée en mode MISE A JOUR (reçu : %i, attendu : %i mini)", nmea.annuaire[rang].pgn, nmea.annuaire[rang].lg_data, LG_DATA_MINI);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
return (-1);
|
||
}
|
||
|
||
index = 0;
|
||
|
||
//----------------------------------
|
||
// Sequence ID :
|
||
index ++;
|
||
|
||
//----------------------------------
|
||
// Mode :
|
||
index ++;
|
||
|
||
//----------------------------------
|
||
// Satellites in view :
|
||
val_u8 = nmea.annuaire[rang].data[index ++];
|
||
enregistrement_pgn_field_nmea(rang, NMEA_129540_SATELLITES_IN_VIEW, val_u8 );
|
||
#ifdef DEBUG_PGN_129540
|
||
sprintf(tmp, "PGN %i : Satellites in view = %i", nmea.annuaire[rang].pgn, val_u8 );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_SUPPRESSION:
|
||
{
|
||
suppression_pgn_nmea(rang);
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
default: break;
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
//==================================================================================================================================================================
|
||
// PGN : 130306
|
||
// Fonction : Wind Data
|
||
//==================================================================================================================================================================
|
||
int8_t Parse_pgn_130306(uint16_t rang, uint8_t mode)
|
||
{
|
||
// #define DEBUG_PGN_130306
|
||
const uint8_t LG_DATA_MINI = 6;
|
||
uint8_t index;
|
||
uint16_t val_u16;
|
||
uint8_t wind_ref;
|
||
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
|
||
|
||
|
||
if (nmea.annuaire[rang].pgn != 130306) return (-1);
|
||
|
||
switch (mode)
|
||
{
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_CREATION:
|
||
{
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_SPEED_TRUE_NORTH, "Capt_vitesse_kts", 1, 1, "Wind Speed [True North]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_ANGLE_TRUE_NORTH, "Capt_angle_degres", 0, 1, "Wind Angle [True North]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_SPEED_MAGNETIC, "Capt_vitesse_kts", 1, 1, "Wind Speed [Magnetic]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_ANGLE_MAGNETIC, "Capt_angle_degres", 0, 1, "Wind Angle [Magnetic]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_SPEED_APPARENT, "Capt_vitesse_kts", 1, 1, "Wind Speed [Apparent]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_ANGLE_APPARENT, "Capt_angle_degres", 0, 1, "Wind Angle [Apparent]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_SPEED_TRUE_BOAT, "Capt_vitesse_kts", 1, 1, "Wind Speed [True boat]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_ANGLE_TRUE_BOAT, "Capt_angle_degres", 0, 1, "Wind Angle [True boat]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_SPEED_TRUE_WATER, "Capt_vitesse_kts", 1, 1, "Wind Speed [True water]");
|
||
creation_pgn_field_nmea(rang, NMEA_130306_WIND_ANGLE_TRUE_WATER, "Capt_angle_degres", 0, 1, "Wind Angle [True water]");
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_MISE_A_JOUR:
|
||
{
|
||
if (nmea.annuaire[rang].lg_data < LG_DATA_MINI)
|
||
{
|
||
sprintf(tmp, "La longueur de DATA du PGN %i n'est pas correcte pour être traitée en mode MISE A JOUR (reçu : %i, attendu : %i mini)", nmea.annuaire[rang].pgn, nmea.annuaire[rang].lg_data, LG_DATA_MINI);
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
return (-1);
|
||
}
|
||
|
||
// Recherche de la référence des infos de vent (vitesse et direction) qui suivent :
|
||
// True_North=0, Magnetic=1, Apparent=2, True_boat=3, True_water=4, Error=6, Unavailable=7
|
||
wind_ref = nmea.annuaire[rang].data[5] & 0x07;
|
||
if (wind_ref > 4)
|
||
{
|
||
#ifdef DEBUG_PGN_130306
|
||
sprintf(tmp, "La référence de vent du PGN %i n'est pas correcte (reçu : %i, attendu : 4 maxi). Le traitement de mise à jour est annulé...", nmea.annuaire[rang].pgn, wind_ref );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
|
||
#endif
|
||
return(-1);
|
||
}
|
||
|
||
#ifdef DEBUG_PGN_130306
|
||
char wind_ref_name[40];
|
||
switch(wind_ref)
|
||
{
|
||
case 0: { strcpy(wind_ref_name, "True North"); break; }
|
||
case 1: { strcpy(wind_ref_name, "Magnetic"); break; }
|
||
case 2: { strcpy(wind_ref_name, "Apparent"); break; }
|
||
case 3: { strcpy(wind_ref_name, "True boat"); break; }
|
||
case 4: { strcpy(wind_ref_name, "True water"); break; }
|
||
case 6: { strcpy(wind_ref_name, "Error"); break; }
|
||
case 7: { strcpy(wind_ref_name, "Unavailable"); break; }
|
||
default: { strcpy(wind_ref_name, "True North"); break; }
|
||
}
|
||
#endif
|
||
// Parse des data :
|
||
index = 0;
|
||
|
||
//----------------------------------
|
||
// Sequence ID :
|
||
index ++;
|
||
|
||
//----------------------------------
|
||
// Wind Speed :
|
||
val_u16 = (uint16_t) nmea.annuaire[rang].data[index ++];
|
||
val_u16 |= ((uint16_t) nmea.annuaire[rang].data[index ++]) << 8; // En m/s
|
||
enregistrement_pgn_field_nmea(rang, (NMEA_130306_WIND_SPEED_TRUE_NORTH + wind_ref), (((float) val_u16 * 0.01) * CONVERSION_MS_TO_KNOTS) ); // En Knots
|
||
#ifdef DEBUG_PGN_130306
|
||
sprintf(tmp, "PGN %i : Vitesse du vent [%s] = %.2Lf Kts", nmea.annuaire[rang].pgn, wind_ref_name, (((float) val_u16 * 0.01) * CONVERSION_MS_TO_KNOTS) );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
//----------------------------------
|
||
// Wind Angle :
|
||
val_u16 = (uint16_t) nmea.annuaire[rang].data[index ++];
|
||
val_u16 |= ((uint16_t) nmea.annuaire[rang].data[index ++]) << 8; // En Radians
|
||
enregistrement_pgn_field_nmea(rang, (NMEA_130306_WIND_ANGLE_TRUE_NORTH + wind_ref), (((float) val_u16 * 0.0001) * CONVERSION_RAD_TO_DEG) ); // En Degrés
|
||
#ifdef DEBUG_PGN_130306
|
||
sprintf(tmp, "PGN %i : Angle du vent [%s] = %.1Lf° ", nmea.annuaire[rang].pgn, wind_ref_name, (((float) val_u16 * 0.0001) * CONVERSION_RAD_TO_DEG) );
|
||
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
|
||
#endif
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
case NMEA_PARSE_MODE_SUPPRESSION:
|
||
{
|
||
suppression_pgn_nmea(rang);
|
||
|
||
break;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
default: break;
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
//
|
||
// Catalogue des PGNs :
|
||
//
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
//-----------------------------------------------------------------------------**************************************************************************************
|
||
|
||
// Pgn, Type, Période mini (x10ms), Fonction de parsing
|
||
const struct Struct_entree_catalogue_pgn_nmea catalogue_pgns[NMEA_MAX_NOMBRE_PGN + 1] = {
|
||
{ 126992, NMEA_PGN_TYPE_DEFAULT_SINGLE_FRAME, 1000, &Parse_pgn_126992 }, // System date/time, pri=3, period=1000
|
||
{ 129029, NMEA_PGN_TYPE_DEFAULT_FAST_PACKET, 480, &Parse_pgn_129029 }, // GNSS Position Data, pri=3, period=1000
|
||
{ 129540, NMEA_PGN_TYPE_DEFAULT_FAST_PACKET, 480, &Parse_pgn_129540 }, // GNSS Sats in View, pri=6, period=1000
|
||
{ 130306, NMEA_PGN_TYPE_DEFAULT_SINGLE_FRAME, 100, &Parse_pgn_130306 }, // Wind Speed, pri=2, period=100
|
||
{ 0, 0, 0, NULL } // Ligne de fin de catalogue (PGN = 0)
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// Fonctions issues de NMEA2000.cpp : https://ttlappalainen.github.io/NMEA2000/_n_m_e_a2000_8cpp_source.html
|
||
|
||
/*
|
||
//-----------------------------------------------------------------------------
|
||
const unsigned long DefTransmitMessages[] PROGMEM = {
|
||
59392L, // ISO Acknowledgement, pri=6, period=NA
|
||
59904L, // ISO Request, pri=6, period=NA
|
||
#if !defined(N2K_NO_ISO_MULTI_PACKET_SUPPORT)
|
||
TP_DT, // Multi packet data transfer, TP.DT, pri=6, period=NA
|
||
TP_CM, // Multi packet connection management, TP.CM, pri=6, period=NA
|
||
#endif
|
||
60928L, // ISO Address Claim, pri=6, period=NA
|
||
#if !defined(N2K_NO_GROUP_FUNCTION_SUPPORT)
|
||
126208L, // NMEA Request/Command/Acknowledge group function, pri=3, period=NA
|
||
#endif
|
||
126464L, // PGN List (Transmit and Receive), pri=6, period=NA
|
||
#if !defined(N2K_NO_HEARTBEAT_SUPPORT)
|
||
126993L, // Heartbeat, pri=7, period=60000
|
||
#endif
|
||
126996L, // Product information, pri=6, period=NA
|
||
126998L, // Configuration information, pri=6, period=NA
|
||
0};
|
||
|
||
//-----------------------------------------------------------------------------
|
||
const unsigned long DefReceiveMessages[] PROGMEM = {
|
||
59392L, // ISO Acknowledgement, pri=6, period=NA
|
||
59904L, // ISO Request, pri=6, period=NA
|
||
#if !defined(N2K_NO_ISO_MULTI_PACKET_SUPPORT)
|
||
TP_DT, // Multi packet data transfer, TP.DT
|
||
TP_CM, // Multi packet connection management, TP.CM
|
||
#endif
|
||
60928L, // ISO Address Claim
|
||
65240L, // Commanded Address
|
||
#if !defined(N2K_NO_GROUP_FUNCTION_SUPPORT)
|
||
126208L, // NMEA Request/Command/Acknowledge group function
|
||
#endif
|
||
0};
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool IsSingleFrameSystemMessage(unsigned long PGN) {
|
||
switch (PGN) {
|
||
case 59392L: // ISO Acknowledgement
|
||
case TP_DT: // Multi packet data transfer, TP.DT
|
||
case TP_CM: // Multi packet connection management, TP.CM
|
||
case 59904L: // ISO Request
|
||
case 60928L: // ISO Address Claim
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool IsFastPacketSystemMessage(unsigned long PGN) {
|
||
switch (PGN) {
|
||
case 65240L: // Commanded Address
|
||
case 126208L: // NMEA Request/Command/Acknowledge group function
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool IsDefaultSingleFrameMessage(unsigned long PGN) {
|
||
switch (PGN) {
|
||
case 126993L: // Heartbeat, pri=7, period=60000
|
||
case 127245L: // Rudder, pri=2, period=100
|
||
case 127250L: // Vessel Heading, pri=2, period=100
|
||
case 127251L: // Rate of Turn, pri=2, period=100
|
||
case 127257L: // Attitude, pri=3, period=1000
|
||
case 127488L: // Engine parameters rapid, rapid Update, pri=2, period=100
|
||
case 127493L: // Transmission parameters: dynamic, pri=2, period=100
|
||
case 127501L: // Binary status report, pri=3, period=NA
|
||
case 127505L: // Fluid level, pri=6, period=2500
|
||
case 127508L: // Battery Status, pri=6, period=1500
|
||
case 128259L: // Boat speed, pri=2, period=1000
|
||
case 128267L: // Water depth, pri=3, period=1000
|
||
case 129025L: // Lat/lon rapid, pri=2, period=100
|
||
case 129026L: // COG SOG rapid, pri=2, period=250
|
||
case 129283L: // Cross Track Error, pri=3, period=1000
|
||
case 130310L: // Outside Environmental parameters, pri=5, period=500
|
||
case 130311L: // Environmental parameters, pri=5, period=500
|
||
case 130312L: // Temperature, pri=5, period=2000
|
||
case 130313L: // Humidity, pri=5, period=2000
|
||
case 130314L: // Pressure, pri=5, period=2000
|
||
case 130316L: // Temperature extended range, pri=5, period=2000
|
||
case 130576L: // Small Craft Status (Trim Tab position), pri=2, period=200
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool IsMandatoryFastPacketMessage(unsigned long PGN) {
|
||
switch (PGN) {
|
||
case 126464L: // PGN List (Transmit and Receive), pri=6, period=NA
|
||
case 126996L: // Product information, pri=6, period=NA
|
||
case 126998L: // Configuration information, pri=6, period=NA
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool IsDefaultFastPacketMessage(unsigned long PGN) {
|
||
switch (PGN) {
|
||
case 126983L: // Alert, pri=2, period=1000
|
||
case 126984L: // Alert Response, pri=2, period=NA
|
||
case 126985L: // Alert Text, pri=2, period=10000
|
||
case 126986L: // Alert Configuration, pri=2, period=NA
|
||
case 126987L: // Alert Threshold, pri=2, period=NA
|
||
case 126988L: // Alert Value, pri=2, period=10000
|
||
case 127233L: // Man Overboard Notification(MOB), pri=3, period=NA
|
||
case 127237L: // Heading/Track control, pri=2, period=250
|
||
case 127489L: // Engine parameters dynamic, pri=2, period=500
|
||
case 127490L: // Electric Drive Status (Dynamic), pri=1, period=1500
|
||
case 127491L: // Electric Energy Storage Status (Dynamic), pri=7, period=1500
|
||
case 127494L: // Electric Drive Information, pri=4, period=NA
|
||
case 127495L: // Electric Energy Storage Information, pri=6, period=NA
|
||
case 127496L: // Trip fuel consumption, vessel, pri=5, period=1000
|
||
case 127497L: // Trip fuel consumption, engine, pri=5, period=1000
|
||
case 127498L: // Engine parameters static, pri=5, period=NA
|
||
case 127503L: // AC Input Status, pri=6, period=1500
|
||
case 127504L: // AC Output Status, pri=6, period=1500
|
||
case 127506L: // DC Detailed status, pri=6, period=1500
|
||
case 127507L: // Charger status, pri=6, period=1500
|
||
case 127509L: // Inverter status, pri=6, period=1500
|
||
case 127510L: // Charger configuration status, pri=6, period=NA
|
||
case 127511L: // Inverter Configuration Status, pri=6, period=NA
|
||
case 127512L: // AGS configuration status, pri=6, period=NA
|
||
case 127513L: // Battery configuration status, pri=6, period=NA
|
||
case 127514L: // AGS Status, pri=6, period=1500
|
||
case 128275L: // Distance log, pri=6, period=1000
|
||
case 128520L: // Tracked Target Data, pri=2, period=1000
|
||
case 128538L: // Elevator car status, pri=6, period=100
|
||
case 129038L: // AIS Class A Position Report, pri=4, period=NA
|
||
case 129039L: // AIS Class B Position Report, pri=4, period=NA
|
||
case 129040L: // AIS Class B Extended Position Report, pri=4, period=NA
|
||
case 129041L: // AIS Aids to Navigation (AtoN) Report, pri=4, period=NA
|
||
case 129044L: // Datum, pri=6, period=10000
|
||
case 129045L: // User Datum Settings, pri=6, period=NA
|
||
case 129284L: // Navigation info, pri=3, period=1000
|
||
case 129285L: // Waypoint list, pri=3, period=NA
|
||
case 129301L: // Time to/from Mark, pri=3, period=1000
|
||
case 129302L: // Bearing and Distance between two Marks, pri=6, period=NA
|
||
case 129538L: // GNSS Control Status, pri=6, period=NA
|
||
case 129541L: // GPS Almanac Data, pri=6, period=NA
|
||
case 129542L: // GNSS Pseudorange Noise Statistics, pri=6, period=1000
|
||
case 129545L: // GNSS RAIM Output, pri=6, period=NA
|
||
case 129547L: // GNSS Pseudorange Error Statistics, pri=6, period=NA
|
||
case 129549L: // DGNSS Corrections, pri=6, period=NA
|
||
case 129551L: // GNSS Differential Correction Receiver Signal, pri=6, period=NA
|
||
case 129556L: // GLONASS Almanac Data, pri=6, period=NA
|
||
case 129792L: // AIS DGNSS Broadcast Binary Message, pri=6, period=NA
|
||
case 129793L: // AIS UTC and Date Report, pri=7, period=NA
|
||
case 129794L: // AIS Class A Static data, pri=6, period=NA
|
||
case 129795L: // AIS Addressed Binary Message, pri=5, period=NA
|
||
case 129796L: // AIS Acknowledge, pri=7, period=NA
|
||
case 129797L: // AIS Binary Broadcast Message, pri=5, period=NA
|
||
case 129798L: // AIS SAR Aircraft Position Report, pri=4, period=NA
|
||
case 129799L: // Radio Frequency/Mode/Power, pri=3, period=NA
|
||
case 129800L: // AIS UTC/Date Inquiry, pri=7, period=NA
|
||
case 129801L: // AIS Addressed Safety Related Message, pri=5, period=NA
|
||
case 129802L: // AIS Safety Related Broadcast Message, pri=5, period=NA
|
||
case 129803L: // AIS Interrogation PGN, pri=7, period=NA
|
||
case 129804L: // AIS Assignment Mode Command, pri=7, period=NA
|
||
case 129805L: // AIS Data Link Management Message, pri=7, period=NA
|
||
case 129806L: // AIS Channel Management, pri=7, period=NA
|
||
case 129807L: // AIS Group Assignment, pri=7, period=NA
|
||
case 129808L: // DSC Call Information, pri=8, period=NA
|
||
case 129809L: // AIS Class B Static Data: Part A, pri=6, period=NA
|
||
case 129810L: // AIS Class B Static Data Part B, pri=6, period=NA
|
||
case 129811L: // AIS Single Slot Binary Message, pri=5, period=NA
|
||
case 129812L: // AIS Multi Slot Binary Message, pri=5, period=NA
|
||
case 129813L: // AIS Long-Range Broadcast Message, pri=5, period=NA
|
||
case 130052L: // Loran-C TD Data, pri=3, period=1000
|
||
case 130053L: // Loran-C Range Data, pri=3, period=1000
|
||
case 130054L: // Loran-C Signal Data, pri=3, period=1000
|
||
case 130060L: // Label, pri=7, period=NA
|
||
case 130061L: // Channel Source Configuration, pri=7, period=NA
|
||
case 130064L: // Route and WP Service - Database List, pri=7, period=NA
|
||
case 130065L: // Route and WP Service - Route List, pri=7, period=NA
|
||
case 130066L: // Route and WP Service - Route/WP-List Attributes, pri=7, period=NA
|
||
case 130067L: // Route and WP Service - Route - WP Name & Position, pri=7, period=NA
|
||
case 130068L: // Route and WP Service - Route - WP Name, pri=7, period=NA
|
||
case 130069L: // Route and WP Service - XTE Limit & Navigation Method, pri=7, period=NA
|
||
case 130070L: // Route and WP Service - WP Comment, pri=7, period=NA
|
||
case 130071L: // Route and WP Service - Route Comment, pri=7, period=NA
|
||
case 130072L: // Route and WP Service - Database Comment, pri=7, period=NA
|
||
case 130073L: // Route and WP Service - Radius of Turn, pri=7, period=NA
|
||
case 130074L: // Route and WP Service - WP List - WP Name & Position, pri=7, period=NA
|
||
case 130320L: // Tide Station Data, pri=6, period=1000
|
||
case 130321L: // Salinity Station Data, pri=6, period=1000
|
||
case 130322L: // Current Station Data, pri=6, period=1000
|
||
case 130323L: // Meteorological Station Data, pri=6, period=1000
|
||
case 130324L: // Moored Buoy Station Data, pri=6, period=1000
|
||
case 130330L: // Lighting system settings, pri=7, period=NA
|
||
case 130561L: // Lighting zone, pri=7, period=NA
|
||
case 130562L: // Lighting scene, pri=7, period=NA
|
||
case 130563L: // Lighting device, pri=7, period=NA
|
||
case 130564L: // Lighting device enumeration, pri=7, period=NA
|
||
case 130565L: // Lighting color sequence, pri=7, period=NA
|
||
case 130566L: // Lighting program, pri=7, period=NA
|
||
case 130567L: // Watermaker Input Setting and Status, pri=6, period=2500
|
||
case 130577L: // Direction Data PGN, pri=3, period=1000
|
||
case 130578L: // Vessel Speed Components, pri=2, period=250
|
||
// Entertainment PGNs
|
||
case 130569L: // Current File and Status, pri=6, period=500
|
||
case 130570L: // Library Data File, pri=6, period=NA
|
||
case 130571L: // Library Data Group, pri=6, period=NA
|
||
case 130572L: // Library Data Search, pri=6, period=NA
|
||
case 130573L: // Supported Source Data, pri=6, period=NA
|
||
case 130574L: // Supported Zone Data, pri=6, period=NA
|
||
case 130580L: // System Configuration Status, pri=6, period=NA
|
||
case 130581L: // Zone Configuration Status, pri=6, period=NA
|
||
case 130583L: // Available Audio EQ Presets, pri=6, period=NA
|
||
case 130584L: // Bluetooth Devices, pri=6, period=NA
|
||
case 130586L: // Zone Configuration Status, pri=6, period=NA
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool IsProprietaryFastPacketMessage(unsigned long PGN) {
|
||
return ( PGN==126720L ) || ( 130816L<=PGN && PGN<=131071L );
|
||
}
|
||
|
||
bool tNMEA2000::IsProprietaryMessage(unsigned long PGN) {
|
||
return IsProprietaryFastPacketMessage(PGN) || ( PGN==61184L ) || ( 65280L<=PGN && PGN<=65535L );
|
||
}
|
||
|
||
*/
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// Fonctions issues de :
|
||
// https://ttlappalainen.github.io/NMEA2000/_n2k_messages_8cpp_source.html
|
||
// https://ttlappalainen.github.io/NMEA2000/_n2k_maretron_8cpp_source.html
|
||
// https://ttlappalainen.github.io/NMEA2000/_n_m_e_a2000_8cpp_source.html (en fin de fichier)
|
||
|
||
|
||
// Voir peut-être N2kMessagesEnumToStr.h : https://ttlappalainen.github.io/NMEA2000/_n2k_messages_enum_to_str_8h_source.html
|
||
// const char* tN2kTimeSourceStrs[] = { "GPS", "GLONASS", "radio station", "local cesium clock", "local rubidium clock", "local crystal clock" };
|
||
// const char* tN2kFluidTypeStrs[] = { "Fuel", "Water", "Gray water", "Live well", "Oil", "Black water", "Gasoline Fuel", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Error", "Unavailable",};
|
||
|
||
/*
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// ISO Request
|
||
bool ParseN2kPGN59904(const tN2kMsg &N2kMsg,
|
||
unsigned long &RequestedPGN)
|
||
{
|
||
int result=((N2kMsg.DataLen>=3) && (N2kMsg.DataLen<=8));
|
||
RequestedPGN=0;
|
||
if (result) {
|
||
int Index=0;
|
||
RequestedPGN=N2kMsg.Get3ByteUInt(Index);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// System time
|
||
bool ParseN2kPGN126992(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
uint16_t &SystemDate,
|
||
double &SystemTime,
|
||
tN2kTimeSource &TimeSource)
|
||
{
|
||
if (N2kMsg.PGN!=126992L) return false;
|
||
|
||
int Index=0;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
TimeSource=(tN2kTimeSource)(N2kMsg.GetByte(Index) & 0x0f);
|
||
SystemDate=N2kMsg.Get2ByteUInt(Index);
|
||
SystemTime=N2kMsg.Get4ByteUDouble(0.0001,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS Safety Related Broadcast Message
|
||
bool ParseN2kPGN129802(const tN2kMsg &N2kMsg,
|
||
uint8_t &MessageID,
|
||
tN2kAISRepeat &Repeat,
|
||
uint32_t &SourceID,
|
||
tN2kAISTransceiverInformation &AISTransceiverInformation,
|
||
char * SafetyRelatedText,
|
||
size_t &SafetyRelatedTextMaxSize)
|
||
{
|
||
if (N2kMsg.PGN!=129802L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb=N2kMsg.GetByte(Index);
|
||
MessageID=(vb & 0x3f);
|
||
Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
SourceID = N2kMsg.Get4ByteUInt(Index) & 0x3fffffff;
|
||
AISTransceiverInformation = (tN2kAISTransceiverInformation)(N2kMsg.GetByte(Index) & 0x1f);
|
||
N2kMsg.GetVarStr(SafetyRelatedTextMaxSize, SafetyRelatedText, Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Product Information
|
||
bool ParseN2kPGN126996(const tN2kMsg& N2kMsg,
|
||
unsigned short &N2kVersion,
|
||
unsigned short &ProductCode,
|
||
int ModelIDSize,
|
||
char *ModelID,
|
||
int SwCodeSize,
|
||
char *SwCode,
|
||
int ModelVersionSize,
|
||
char *ModelVersion,
|
||
int ModelSerialCodeSize,
|
||
char *ModelSerialCode,
|
||
unsigned char &CertificationLevel,
|
||
unsigned char &LoadEquivalency)
|
||
{
|
||
if (N2kMsg.PGN!=N2kPGNProductInformation) return false;
|
||
|
||
int Index=0;
|
||
N2kVersion=N2kMsg.Get2ByteUInt(Index);
|
||
ProductCode=N2kMsg.Get2ByteUInt(Index);
|
||
N2kMsg.GetStr(ModelIDSize,ModelID,Max_N2kModelID_len,0xff,Index);
|
||
N2kMsg.GetStr(SwCodeSize,SwCode,Max_N2kSwCode_len,0xff,Index);
|
||
N2kMsg.GetStr(ModelVersionSize,ModelVersion,Max_N2kModelVersion_len,0xff,Index);
|
||
N2kMsg.GetStr(ModelSerialCodeSize,ModelSerialCode,Max_N2kModelSerialCode_len,0xff,Index);
|
||
CertificationLevel=N2kMsg.GetByte(Index);
|
||
LoadEquivalency=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Configuration Information
|
||
bool ParseN2kPGN126998(const tN2kMsg& N2kMsg,
|
||
size_t &ManufacturerInformationSize,
|
||
char *ManufacturerInformation,
|
||
size_t &InstallationDescription1Size,
|
||
char *InstallationDescription1,
|
||
size_t &InstallationDescription2Size,
|
||
char *InstallationDescription2)
|
||
{
|
||
if (N2kMsg.PGN!=N2kPGNConfigurationInformation) return false;
|
||
|
||
int Index=0;
|
||
return ( N2kMsg.GetVarStr(InstallationDescription1Size,InstallationDescription1,Index) &&
|
||
N2kMsg.GetVarStr(InstallationDescription2Size,InstallationDescription2,Index) &&
|
||
N2kMsg.GetVarStr(ManufacturerInformationSize,ManufacturerInformation,Index) );
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Man Overboard Notification
|
||
bool ParseN2kPGN127233(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
uint32_t &MobEmitterId,
|
||
tN2kMOBStatus &MOBStatus,
|
||
double &ActivationTime,
|
||
tN2kMOBPositionSource &PositionSource,
|
||
uint16_t &PositionDate,
|
||
double &PositionTime,
|
||
double &Latitude,
|
||
double &Longitude,
|
||
tN2kHeadingReference &COGReference,
|
||
double &COG,
|
||
double &SOG,
|
||
uint32_t &MMSI,
|
||
tN2kMOBEmitterBatteryStatus &MOBEmitterBatteryStatus)
|
||
{
|
||
if (N2kMsg.PGN!=127233L) return false;
|
||
int Index = 0;
|
||
SID = N2kMsg.GetByte(Index);
|
||
MobEmitterId = N2kMsg.Get4ByteUInt(Index);
|
||
MOBStatus = (tN2kMOBStatus)(N2kMsg.GetByte(Index) & 0x07);
|
||
ActivationTime = N2kMsg.Get4ByteUDouble(0.0001,Index);
|
||
PositionSource = (tN2kMOBPositionSource)(N2kMsg.GetByte(Index) & 0x07);
|
||
PositionDate = N2kMsg.Get2ByteUInt(Index);
|
||
PositionTime = N2kMsg.Get4ByteUDouble(0.0001,Index);
|
||
Latitude = N2kMsg.Get4ByteDouble(1e-7,Index);
|
||
Longitude = N2kMsg.Get4ByteDouble(1e-7,Index);
|
||
COGReference = (tN2kHeadingReference)(N2kMsg.GetByte(Index) & 0x03);
|
||
COG = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
SOG = N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
MMSI = N2kMsg.Get4ByteUInt(Index);
|
||
MOBEmitterBatteryStatus = (tN2kMOBEmitterBatteryStatus)(N2kMsg.GetByte(Index) & 0x07);
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Heading/Track control
|
||
// Angles should be in radians
|
||
bool ParseN2kPGN127237(const tN2kMsg &N2kMsg,
|
||
tN2kOnOff &RudderLimitExceeded,
|
||
tN2kOnOff &OffHeadingLimitExceeded,
|
||
tN2kOnOff &OffTrackLimitExceeded,
|
||
tN2kOnOff &Override,
|
||
tN2kSteeringMode &SteeringMode,
|
||
tN2kTurnMode &TurnMode,
|
||
tN2kHeadingReference &HeadingReference,
|
||
tN2kRudderDirectionOrder &CommandedRudderDirection,
|
||
double &CommandedRudderAngle,
|
||
double &HeadingToSteerCourse,
|
||
double &Track,
|
||
double &RudderLimit,
|
||
double &OffHeadingLimit,
|
||
double &RadiusOfTurnOrder,
|
||
double &RateOfTurnOrder,
|
||
double &OffTrackLimit,
|
||
double &VesselHeading)
|
||
{
|
||
|
||
if (N2kMsg.PGN!=127237L) return false;
|
||
int Index = 0;
|
||
unsigned char v;
|
||
v = N2kMsg.GetByte(Index);
|
||
RudderLimitExceeded = (tN2kOnOff)(v & 0x03);
|
||
OffHeadingLimitExceeded = (tN2kOnOff)((v >> 2) & 0x03);
|
||
OffTrackLimitExceeded = (tN2kOnOff)((v >> 4) & 0x03);
|
||
Override = (tN2kOnOff)((v >> 6) & 0x03);
|
||
v = N2kMsg.GetByte(Index);
|
||
SteeringMode = (tN2kSteeringMode)(v & 0x07);
|
||
TurnMode = (tN2kTurnMode)((v >> 3) & 0x07);
|
||
HeadingReference = (tN2kHeadingReference)((v >> 6) & 0x03);
|
||
CommandedRudderDirection = (tN2kRudderDirectionOrder)((N2kMsg.GetByte(Index) >> 5) & 0x07);
|
||
CommandedRudderAngle = N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
HeadingToSteerCourse = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
Track = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
RudderLimit = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
OffHeadingLimit = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
RadiusOfTurnOrder = N2kMsg.Get2ByteDouble(1,Index);
|
||
RateOfTurnOrder = N2kMsg.Get2ByteDouble(3.125e-5,Index);
|
||
OffTrackLimit = N2kMsg.Get2ByteDouble(1,Index);
|
||
VesselHeading = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Rudder
|
||
// Angles should be in radians
|
||
bool ParseN2kPGN127245(const tN2kMsg &N2kMsg,
|
||
double &RudderPosition,
|
||
unsigned char &Instance,
|
||
tN2kRudderDirectionOrder &RudderDirectionOrder,
|
||
double &AngleOrder)
|
||
{
|
||
if (N2kMsg.PGN!=127245L) return false;
|
||
|
||
int Index=0;
|
||
Instance=N2kMsg.GetByte(Index);
|
||
RudderDirectionOrder=(tN2kRudderDirectionOrder)(N2kMsg.GetByte(Index)&0x7);
|
||
AngleOrder=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
RudderPosition=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Vessel Heading
|
||
// Angles should be in radians
|
||
bool ParseN2kPGN127250(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &Heading,
|
||
double &Deviation,
|
||
double &Variation,
|
||
tN2kHeadingReference &ref)
|
||
{
|
||
if (N2kMsg.PGN!=127250L) return false;
|
||
|
||
int Index=0;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
Heading=N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
Deviation=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
Variation=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
ref=(tN2kHeadingReference)(N2kMsg.GetByte(Index)&0x03);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Rate of turn
|
||
// Angles should be in radians
|
||
bool ParseN2kPGN127251(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &RateOfTurn)
|
||
{
|
||
if (N2kMsg.PGN!=127251L) return false;
|
||
|
||
int Index=0;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
RateOfTurn=N2kMsg.Get4ByteDouble(3.125E-08,Index); //1e-6/32.0
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Heave
|
||
// - SID Sequence ID. If your device is e.g. boat speed and heading at same time, you can set same SID for different messages
|
||
// to indicate that they are measured at same time.
|
||
// - Heave Vertical displacement perpendicular to the earth’s surface in meters
|
||
// - Delay Delay added by calculations in seconds
|
||
// - DelaySource tN2kDelaySource
|
||
// Output:
|
||
// - N2kMsg NMEA2000 message ready to be send.
|
||
bool ParseN2kPGN127252(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &Heave,
|
||
double &Delay,
|
||
tN2kDelaySource &DelaySource)
|
||
{
|
||
if (N2kMsg.PGN!=127252L) return false;
|
||
int Index = 0;
|
||
SID = N2kMsg.GetByte(Index);
|
||
Heave = N2kMsg.Get2ByteDouble(0.01,Index);
|
||
Delay = N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
uint8_t v=N2kMsg.GetByte(Index);
|
||
DelaySource=(tN2kDelaySource)(v & 0x0f);
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Attitude
|
||
// Input:
|
||
// - SID Sequence ID. If your device is e.g. boat speed and heading at same time, you can set same SID for different messages
|
||
// to indicate that they are measured at same time.
|
||
// - Yaw Heading in radians.
|
||
// - Pitch Pitch in radians. Positive, when your bow rises.
|
||
// - Roll Roll in radians. Positive, when tilted right.
|
||
// Output:
|
||
// - N2kMsg NMEA2000 message ready to be send.
|
||
bool ParseN2kPGN127257(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &Yaw,
|
||
double &Pitch,
|
||
double &Roll)
|
||
{
|
||
if (N2kMsg.PGN!=127257L) return false;
|
||
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
Yaw=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
Pitch=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
Roll=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Magnetic variation
|
||
bool ParseN2kPGN127258(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
tN2kMagneticVariation &Source,
|
||
uint16_t &DaysSince1970,
|
||
double &Variation)
|
||
{
|
||
if (N2kMsg.PGN!=127258L) return false;
|
||
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
Source=(tN2kMagneticVariation) (N2kMsg.GetByte(Index) & 0x0f);
|
||
DaysSince1970=N2kMsg.Get2ByteUInt(Index);
|
||
Variation=N2kMsg.Get2ByteDouble(0.0001, Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Engine rapid param
|
||
bool ParseN2kPGN127488(const tN2kMsg &N2kMsg,
|
||
unsigned char &EngineInstance,
|
||
double &EngineSpeed,
|
||
double &EngineBoostPressure,
|
||
int8_t &EngineTiltTrim)
|
||
{
|
||
if (N2kMsg.PGN!=127488L) return false;
|
||
|
||
int Index=0;
|
||
|
||
EngineInstance=N2kMsg.GetByte(Index);
|
||
EngineSpeed=N2kMsg.Get2ByteUDouble(0.25,Index);
|
||
EngineBoostPressure=N2kMsg.Get2ByteUDouble(100,Index);
|
||
EngineTiltTrim=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Engine parameters dynamic
|
||
bool ParseN2kPGN127489(const tN2kMsg &N2kMsg,
|
||
unsigned char &EngineInstance,
|
||
double &EngineOilPress,
|
||
double &EngineOilTemp,
|
||
double &EngineCoolantTemp,
|
||
double &AltenatorVoltage,
|
||
double &FuelRate,
|
||
double &EngineHours,
|
||
double &EngineCoolantPress,
|
||
double &EngineFuelPress,
|
||
int8_t &EngineLoad,
|
||
int8_t &EngineTorque,
|
||
tN2kEngineDiscreteStatus1 &Status1,
|
||
tN2kEngineDiscreteStatus2 &Status2)
|
||
{
|
||
if (N2kMsg.PGN != 127489L) return false;
|
||
|
||
int Index = 0;
|
||
|
||
EngineInstance = N2kMsg.GetByte(Index);
|
||
EngineOilPress = N2kMsg.Get2ByteUDouble(100, Index);
|
||
EngineOilTemp = N2kMsg.Get2ByteUDouble(0.1, Index);
|
||
EngineCoolantTemp = N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
AltenatorVoltage = N2kMsg.Get2ByteDouble(0.01, Index);
|
||
FuelRate = N2kMsg.Get2ByteDouble(0.1, Index);
|
||
EngineHours = N2kMsg.Get4ByteUDouble(1, Index);
|
||
EngineCoolantPress=N2kMsg.Get2ByteUDouble(100, Index);
|
||
EngineFuelPress=N2kMsg.Get2ByteUDouble(1000, Index);
|
||
N2kMsg.GetByte(Index); // reserved
|
||
Status1=N2kMsg.Get2ByteUInt(Index); // Discrete Status 1
|
||
Status2=N2kMsg.Get2ByteUInt(Index); // Discrete Status 2
|
||
EngineLoad=N2kMsg.GetByte(Index);
|
||
EngineTorque=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Transmission parameters, dynamic
|
||
bool ParseN2kPGN127493(const tN2kMsg &N2kMsg,
|
||
unsigned char &EngineInstance,
|
||
tN2kTransmissionGear &TransmissionGear,
|
||
double &OilPressure,
|
||
double &OilTemperature,
|
||
unsigned char &DiscreteStatus1)
|
||
{
|
||
if (N2kMsg.PGN!=127493L) return false;
|
||
|
||
int Index=0;
|
||
|
||
EngineInstance=N2kMsg.GetByte(Index);
|
||
TransmissionGear=(tN2kTransmissionGear)(N2kMsg.GetByte(Index) & 0x03);
|
||
OilPressure=N2kMsg.Get2ByteUDouble(100,Index);
|
||
OilTemperature=N2kMsg.Get2ByteUDouble(0.1,Index);
|
||
DiscreteStatus1=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Trip Parameters, Engine
|
||
bool ParseN2kPGN127497(const tN2kMsg &N2kMsg,
|
||
unsigned char &EngineInstance,
|
||
double &TripFuelUsed,
|
||
double &FuelRateAverage,
|
||
double &FuelRateEconomy,
|
||
double &InstantaneousFuelEconomy)
|
||
{
|
||
if (N2kMsg.PGN!=127497L) return false;
|
||
|
||
int Index=0;
|
||
|
||
EngineInstance=N2kMsg.GetByte(Index);
|
||
TripFuelUsed=N2kMsg.Get2ByteUDouble(1,Index);
|
||
FuelRateAverage=N2kMsg.Get2ByteDouble(0.1,Index);
|
||
FuelRateEconomy=N2kMsg.Get2ByteDouble(0.1,Index);
|
||
InstantaneousFuelEconomy=N2kMsg.Get2ByteDouble(0.1,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Binary status
|
||
|
||
//-----------------------------------------------------------------------------
|
||
tN2kOnOff N2kGetStatusOnBinaryStatus(tN2kBinaryStatus BankStatus, uint8_t ItemIndex) {
|
||
ItemIndex--;
|
||
if (ItemIndex>27) return N2kOnOff_Unavailable;
|
||
|
||
return (tN2kOnOff)((BankStatus >> (2*ItemIndex)) & 0x03);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void N2kSetStatusBinaryOnStatus(tN2kBinaryStatus &BankStatus, tN2kOnOff ItemStatus, uint8_t ItemIndex) {
|
||
ItemIndex--;
|
||
if (ItemIndex>27) return;
|
||
|
||
tN2kBinaryStatus Mask = ~((tN2kBinaryStatus)3 << (2*ItemIndex));
|
||
|
||
BankStatus = (BankStatus & Mask) | ((tN2kBinaryStatus)ItemStatus << (2*ItemIndex));
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void SetN2kPGN127501(tN2kMsg &N2kMsg, unsigned char DeviceBankInstance, tN2kBinaryStatus BankStatus) {
|
||
N2kMsg.SetPGN(127501L);
|
||
N2kMsg.Priority=3;
|
||
BankStatus = (BankStatus << 8) | DeviceBankInstance;
|
||
N2kMsg.AddUInt64(BankStatus);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Binary status report
|
||
void SetN2kPGN127501(tN2kMsg &N2kMsg, unsigned char DeviceBankInstance
|
||
,tN2kOnOff Status1
|
||
,tN2kOnOff Status2
|
||
,tN2kOnOff Status3
|
||
,tN2kOnOff Status4
|
||
) {
|
||
tN2kBinaryStatus BankStatus;
|
||
|
||
N2kResetBinaryStatus(BankStatus);
|
||
BankStatus = (BankStatus << 2) | Status4;
|
||
BankStatus = (BankStatus << 2) | Status3;
|
||
BankStatus = (BankStatus << 2) | Status2;
|
||
BankStatus = (BankStatus << 2) | Status1;
|
||
SetN2kPGN127501(N2kMsg,DeviceBankInstance,BankStatus);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool ParseN2kPGN127501(const tN2kMsg &N2kMsg,
|
||
unsigned char &DeviceBankInstance,
|
||
tN2kOnOff &Status1,
|
||
tN2kOnOff &Status2,
|
||
tN2kOnOff &Status3,
|
||
tN2kOnOff &Status4)
|
||
{
|
||
if (N2kMsg.PGN!=127501L) return false;
|
||
|
||
int Index=0;
|
||
DeviceBankInstance=N2kMsg.GetByte(Index);
|
||
unsigned char b=N2kMsg.GetByte(Index);
|
||
Status1=(tN2kOnOff)(b & 0x03);
|
||
b>>=2; Status2=(tN2kOnOff)(b & 0x03);
|
||
b>>=2; Status3=(tN2kOnOff)(b & 0x03);
|
||
b>>=2; Status4=(tN2kOnOff)(b & 0x03);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool ParseN2kPGN127501(const tN2kMsg &N2kMsg,
|
||
unsigned char &DeviceBankInstance,
|
||
tN2kBinaryStatus &BankStatus)
|
||
{
|
||
if (N2kMsg.PGN!=127501L) return false;
|
||
|
||
int Index=0;
|
||
BankStatus=N2kMsg.GetUInt64(Index);
|
||
DeviceBankInstance = BankStatus & 0xff;
|
||
BankStatus>>=8;
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// PGN 127502 - Switch Bank Control
|
||
bool ParseN2kPGN127502(const tN2kMsg &N2kMsg,
|
||
unsigned char &TargetBankInstance,
|
||
tN2kBinaryStatus &BankStatus)
|
||
{
|
||
if (N2kMsg.PGN!=127502L) return false;
|
||
|
||
int Index=0;
|
||
BankStatus=N2kMsg.GetUInt64(Index);
|
||
TargetBankInstance = BankStatus & 0xff;
|
||
BankStatus>>=8;
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Fluid level
|
||
bool ParseN2kPGN127505(const tN2kMsg &N2kMsg,
|
||
unsigned char &Instance,
|
||
tN2kFluidType &FluidType,
|
||
double &Level,
|
||
double &Capacity)
|
||
{
|
||
if (N2kMsg.PGN!=127505L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char IFt=N2kMsg.GetByte(Index);
|
||
|
||
Instance=IFt&0x0f;
|
||
FluidType=(tN2kFluidType)((IFt>>4)&0x0f);
|
||
Level=N2kMsg.Get2ByteDouble(0.004,Index);
|
||
Capacity=N2kMsg.Get4ByteUDouble(0.1,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// DC Detailed Status
|
||
bool ParseN2kPGN127506(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &DCInstance,
|
||
tN2kDCType &DCType,
|
||
uint8_t &StateOfCharge,
|
||
uint8_t &StateOfHealth,
|
||
double &TimeRemaining,
|
||
double &RippleVoltage,
|
||
double &Capacity)
|
||
{
|
||
if (N2kMsg.PGN!=127506L) return false;
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
DCInstance=N2kMsg.GetByte(Index);
|
||
DCType=(tN2kDCType)(N2kMsg.GetByte(Index));
|
||
StateOfCharge=N2kMsg.GetByte(Index);
|
||
StateOfHealth=N2kMsg.GetByte(Index);
|
||
TimeRemaining=N2kMsg.Get2ByteUDouble(60,Index);
|
||
RippleVoltage=N2kMsg.Get2ByteUDouble(0.001,Index);
|
||
Capacity=N2kMsg.Get2ByteUDouble(3600,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Charger Status
|
||
// Input:
|
||
// - Instance ChargerInstance.
|
||
// - BatteryInstance BatteryInstance.
|
||
// - Operating State see. tN2kChargeState
|
||
// - Charger Mode see. tN2kChargerMode
|
||
// - Charger Enable/Disable boolean
|
||
// - Equalization Pending boolean
|
||
// - Equalization Time Remaining double seconds
|
||
//
|
||
bool ParseN2kPGN127507(const tN2kMsg &N2kMsg,
|
||
unsigned char &Instance,
|
||
unsigned char &BatteryInstance,
|
||
tN2kChargeState &ChargeState,
|
||
tN2kChargerMode &ChargerMode,
|
||
tN2kOnOff &Enabled,
|
||
tN2kOnOff &EqualizationPending,
|
||
double &EqualizationTimeRemaining)
|
||
{
|
||
if (N2kMsg.PGN!=127507UL) return false;
|
||
int Index=0;
|
||
Instance=N2kMsg.GetByte(Index);
|
||
BatteryInstance=N2kMsg.GetByte(Index);
|
||
unsigned char v;
|
||
v=N2kMsg.GetByte(Index);
|
||
ChargeState=(tN2kChargeState)(v&0x0f);
|
||
ChargerMode=(tN2kChargerMode)((v>>4)&0x0f);
|
||
v=N2kMsg.GetByte(Index);
|
||
Enabled=(tN2kOnOff)(v&0x03);
|
||
EqualizationPending=(tN2kOnOff)((v>>2)&0x03);
|
||
EqualizationTimeRemaining=N2kMsg.Get2ByteUDouble(60,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Battery Status
|
||
// Temperatures should be in Kelvins
|
||
bool ParseN2kPGN127508(const tN2kMsg &N2kMsg,
|
||
unsigned char &BatteryInstance,
|
||
double &BatteryVoltage,
|
||
double &BatteryCurrent,
|
||
double &BatteryTemperature,
|
||
unsigned char &SID)
|
||
{
|
||
if (N2kMsg.PGN!=127508L) return false;
|
||
int Index=0;
|
||
BatteryInstance=N2kMsg.GetByte(Index);
|
||
BatteryVoltage=N2kMsg.Get2ByteDouble(0.01,Index);
|
||
BatteryCurrent=N2kMsg.Get2ByteDouble(0.1,Index);
|
||
BatteryTemperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
SID=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Battery Configuration Status
|
||
bool ParseN2kPGN127513(const tN2kMsg &N2kMsg,
|
||
unsigned char &BatInstance,
|
||
tN2kBatType &BatType,
|
||
tN2kBatEqSupport &SupportsEqual,
|
||
tN2kBatNomVolt &BatNominalVoltage,
|
||
tN2kBatChem &BatChemistry,
|
||
double &BatCapacity,
|
||
int8_t &BatTemperatureCoefficient,
|
||
double &PeukertExponent,
|
||
int8_t &ChargeEfficiencyFactor)
|
||
{
|
||
if (N2kMsg.PGN!=127513L) return false;
|
||
int Index=0;
|
||
unsigned char v;
|
||
BatInstance = N2kMsg.GetByte(Index);
|
||
v = N2kMsg.GetByte(Index); BatType=(tN2kBatType)(v & 0x0f); SupportsEqual=(tN2kBatEqSupport)((v>>4) & 0x03);
|
||
v = N2kMsg.GetByte(Index); BatNominalVoltage=(tN2kBatNomVolt)(v & 0x0f); BatChemistry=(tN2kBatChem)((v>>4) & 0x0f);
|
||
BatCapacity=N2kMsg.Get2ByteDouble(3600,Index);
|
||
BatTemperatureCoefficient=N2kMsg.GetByte(Index);
|
||
PeukertExponent=N2kMsg.Get1ByteUDouble(0.002,Index); PeukertExponent+=1;
|
||
ChargeEfficiencyFactor=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Leeway
|
||
bool ParseN2kPGN128000(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &Leeway)
|
||
{
|
||
if (N2kMsg.PGN!=128000L) return false;
|
||
|
||
int Index=0;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
Leeway=N2kMsg.Get2ByteDouble(0.0001,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Boat speed
|
||
bool ParseN2kPGN128259(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &WaterReferenced,
|
||
double &GroundReferenced,
|
||
tN2kSpeedWaterReferenceType &SWRT)
|
||
{
|
||
if (N2kMsg.PGN!=128259L) return false;
|
||
|
||
int Index=0;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
WaterReferenced=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
GroundReferenced=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
SWRT=(tN2kSpeedWaterReferenceType)(N2kMsg.GetByte(Index)&0x0F);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Water depth
|
||
bool ParseN2kPGN128267(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &DepthBelowTransducer,
|
||
double &Offset,
|
||
double &Range)
|
||
{
|
||
if (N2kMsg.PGN!=128267L) return false;
|
||
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
DepthBelowTransducer=N2kMsg.Get4ByteUDouble(0.01,Index);
|
||
Offset=N2kMsg.Get2ByteDouble(0.001,Index);
|
||
Range=N2kMsg.Get1ByteUDouble(10,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Distance log
|
||
bool ParseN2kPGN128275(const tN2kMsg &N2kMsg,
|
||
uint16_t &DaysSince1970,
|
||
double &SecondsSinceMidnight,
|
||
uint32_t &Log,
|
||
uint32_t &TripLog)
|
||
{
|
||
if (N2kMsg.PGN!=128275L) return false;
|
||
|
||
int Index=0;
|
||
|
||
DaysSince1970=N2kMsg.Get2ByteUInt(Index);
|
||
SecondsSinceMidnight=N2kMsg.Get4ByteUDouble(0.0001,Index);
|
||
Log=N2kMsg.Get4ByteUDouble(1,Index);
|
||
TripLog=N2kMsg.Get4ByteUDouble(1,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// PGN128776 - Windlass Control Status
|
||
//
|
||
bool ParseN2kPGN128776(
|
||
const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &WindlassIdentifier,
|
||
tN2kWindlassDirectionControl &WindlassDirectionControl,
|
||
unsigned char &SpeedControl,
|
||
tN2kSpeedType &SpeedControlType,
|
||
tN2kGenericStatusPair &AnchorDockingControl,
|
||
tN2kGenericStatusPair &PowerEnable,
|
||
tN2kGenericStatusPair &MechanicalLock,
|
||
tN2kGenericStatusPair &DeckAndAnchorWash,
|
||
tN2kGenericStatusPair &AnchorLight,
|
||
double &CommandTimeout,
|
||
tN2kWindlassControlEvents &WindlassControlEvents)
|
||
{
|
||
if (N2kMsg.PGN!=128776L) return false;
|
||
int Index = 0;
|
||
unsigned char field;
|
||
SID = N2kMsg.GetByte(Index);
|
||
WindlassIdentifier = N2kMsg.GetByte(Index);
|
||
field = N2kMsg.GetByte(Index);
|
||
WindlassDirectionControl = (tN2kWindlassDirectionControl) (field & 0x03);
|
||
AnchorDockingControl = (tN2kGenericStatusPair) ((field >> 2) & 0x03);
|
||
SpeedControlType = (tN2kSpeedType) ((field >> 4) & 0x03);
|
||
SpeedControl = N2kMsg.GetByte(Index);
|
||
field = N2kMsg.GetByte(Index);
|
||
PowerEnable = (tN2kGenericStatusPair) (field & 0x03);
|
||
MechanicalLock = (tN2kGenericStatusPair) ((field >> 2) & 0x03);
|
||
DeckAndAnchorWash = (tN2kGenericStatusPair) ((field >> 4) & 0x03);
|
||
AnchorLight = (tN2kGenericStatusPair) ((field >> 6) & 0x03);
|
||
CommandTimeout = N2kMsg.Get1ByteUDouble(0.005, Index);
|
||
WindlassControlEvents.SetEvents(N2kMsg.GetByte(Index));
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// PGN128777 Windlass Operating Status
|
||
//
|
||
bool ParseN2kPGN128777(
|
||
const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &WindlassIdentifier,
|
||
double &RodeCounterValue,
|
||
double &WindlassLineSpeed,
|
||
tN2kWindlassMotionStates &WindlassMotionStatus,
|
||
tN2kRodeTypeStates &RodeTypeStatus,
|
||
tN2kAnchorDockingStates &AnchorDockingStatus,
|
||
tN2kWindlassOperatingEvents &WindlassOperatingEvents)
|
||
{
|
||
if (N2kMsg.PGN!=128777L) return false;
|
||
int Index = 0;
|
||
unsigned char field;
|
||
SID = N2kMsg.GetByte(Index);
|
||
WindlassIdentifier = N2kMsg.GetByte(Index);
|
||
field = N2kMsg.GetByte(Index);
|
||
WindlassMotionStatus = (tN2kWindlassMotionStates) (field & 0x03);
|
||
RodeTypeStatus = (tN2kRodeTypeStates) ((field >> 2) & 0x03);
|
||
RodeCounterValue = N2kMsg.Get2ByteUDouble(0.1, Index);
|
||
WindlassLineSpeed = N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
field = N2kMsg.GetByte(Index);
|
||
AnchorDockingStatus = (tN2kAnchorDockingStates) (field & 0x03);
|
||
WindlassOperatingEvents.SetEvents(field >> 2);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// PGN128778 - Windlass Monitoring Status
|
||
//
|
||
bool ParseN2kPGN128778(
|
||
const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &WindlassIdentifier,
|
||
double &TotalMotorTime,
|
||
double &ControllerVoltage,
|
||
double &MotorCurrent,
|
||
tN2kWindlassMonitoringEvents &WindlassMonitoringEvents)
|
||
{
|
||
if (N2kMsg.PGN!=128778L) return false;
|
||
int Index = 0;
|
||
SID = N2kMsg.GetByte(Index);
|
||
WindlassIdentifier = N2kMsg.GetByte(Index);
|
||
WindlassMonitoringEvents.SetEvents(N2kMsg.GetByte(Index));
|
||
ControllerVoltage = N2kMsg.Get1ByteUDouble(0.2, Index);
|
||
MotorCurrent = N2kMsg.Get1ByteUDouble(1.0, Index);
|
||
TotalMotorTime = N2kMsg.Get2ByteUDouble(60.0, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Lat long rapid
|
||
bool ParseN2kPGN129025(const tN2kMsg &N2kMsg,
|
||
double &Latitude,
|
||
double &Longitude)
|
||
{
|
||
if (N2kMsg.PGN!=129025L) return false;
|
||
|
||
int Index = 0;
|
||
Latitude=N2kMsg.Get4ByteDouble(1e-7, Index);
|
||
Longitude=N2kMsg.Get4ByteDouble(1e-7, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// COG SOG rapid
|
||
// COG should be in radians
|
||
// SOG should be in m/s
|
||
bool ParseN2kPGN129026(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
tN2kHeadingReference &ref,
|
||
double &COG,
|
||
double &SOG)
|
||
{
|
||
if (N2kMsg.PGN!=129026L) return false;
|
||
int Index=0;
|
||
unsigned char b;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
b=N2kMsg.GetByte(Index); ref=(tN2kHeadingReference)( b & 0x03 );
|
||
COG=N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
SOG=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// GNSS Position Data
|
||
bool ParseN2kPGN129029(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
uint16_t &DaysSince1970,
|
||
double &SecondsSinceMidnight,
|
||
double &Latitude,
|
||
double &Longitude,
|
||
double &Altitude,
|
||
tN2kGNSStype &GNSStype,
|
||
tN2kGNSSmethod &GNSSmethod,
|
||
uint8_t &nSatellites,
|
||
double &HDOP,
|
||
double &PDOP,
|
||
double &GeoidalSeparation,
|
||
uint8_t &nReferenceStations,
|
||
tN2kGNSStype &ReferenceStationType,
|
||
uint16_t &ReferenceSationID,double &AgeOfCorrection)
|
||
{
|
||
if (N2kMsg.PGN!=129029L) return false;
|
||
int Index=0;
|
||
unsigned char vb;
|
||
int16_t vi;
|
||
|
||
SID=N2kMsg.GetByte(Index);
|
||
DaysSince1970=N2kMsg.Get2ByteUInt(Index);
|
||
SecondsSinceMidnight=N2kMsg.Get4ByteUDouble(0.0001,Index);
|
||
Latitude=N2kMsg.Get8ByteDouble(1e-16,Index);
|
||
Longitude=N2kMsg.Get8ByteDouble(1e-16,Index);
|
||
Altitude=N2kMsg.Get8ByteDouble(1e-6,Index);
|
||
vb=N2kMsg.GetByte(Index); GNSStype=(tN2kGNSStype)(vb & 0x0f); GNSSmethod=(tN2kGNSSmethod)((vb>>4) & 0x0f);
|
||
vb=N2kMsg.GetByte(Index); // Integrity 2 bit, reserved 6 bits
|
||
nSatellites=N2kMsg.GetByte(Index);
|
||
HDOP=N2kMsg.Get2ByteDouble(0.01,Index);
|
||
PDOP=N2kMsg.Get2ByteDouble(0.01,Index);
|
||
GeoidalSeparation=N2kMsg.Get4ByteDouble(0.01,Index);
|
||
nReferenceStations=N2kMsg.GetByte(Index);
|
||
if (nReferenceStations!=N2kUInt8NA && nReferenceStations>0) {
|
||
// Note that we return real number of stations, but we only have variabes for one.
|
||
vi=N2kMsg.Get2ByteUInt(Index); ReferenceStationType=(tN2kGNSStype)(vi & 0x0f); ReferenceSationID=(vi>>4);
|
||
AgeOfCorrection=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
} else {
|
||
ReferenceStationType = N2kGNSSt_GPS;
|
||
ReferenceSationID = N2kInt16NA;
|
||
AgeOfCorrection = N2kDoubleNA;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Date,Time & Local offset
|
||
bool ParseN2kPGN129033(const tN2kMsg &N2kMsg,
|
||
uint16_t &DaysSince1970,
|
||
double &SecondsSinceMidnight,
|
||
int16_t &LocalOffset)
|
||
{
|
||
if ( N2kMsg.PGN != 129033L ) return false;
|
||
|
||
int Index = 0;
|
||
|
||
DaysSince1970 = N2kMsg.Get2ByteUInt(Index);
|
||
SecondsSinceMidnight = N2kMsg.Get4ByteUDouble(0.0001, Index);
|
||
LocalOffset = N2kMsg.Get2ByteInt(Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// GNSS DOP data
|
||
bool ParseN2kPgn129539(const tN2kMsg& N2kMsg,
|
||
unsigned char& SID,
|
||
tN2kGNSSDOPmode& DesiredMode,
|
||
tN2kGNSSDOPmode& ActualMode,
|
||
double& HDOP,
|
||
double& VDOP,
|
||
double& TDOP)
|
||
{
|
||
if(N2kMsg.PGN != 129539L) return false;
|
||
|
||
unsigned char modes;
|
||
int Index = 0;
|
||
|
||
SID = N2kMsg.GetByte(Index);
|
||
modes = N2kMsg.GetByte(Index);
|
||
DesiredMode = (tN2kGNSSDOPmode)( modes & 0x07 );
|
||
ActualMode = (tN2kGNSSDOPmode)( (modes>>3) & 0x07 );
|
||
HDOP = N2kMsg.Get2ByteDouble(0.01, Index);
|
||
VDOP = N2kMsg.Get2ByteDouble(0.01, Index);
|
||
TDOP = N2kMsg.Get2ByteDouble(0.01, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// GNSS Satellites in View
|
||
#define MaxSatelliteInfoCount 18 // Fast packet can hold this max stellites. Maybe later more with TP message.
|
||
bool ParseN2kPGN129540(const tN2kMsg& N2kMsg,
|
||
unsigned char& SID,
|
||
tN2kRangeResidualMode &Mode,
|
||
uint8_t& NumberOfSVs)
|
||
{
|
||
if(N2kMsg.PGN != 129540L) return false;
|
||
|
||
int Index = 0;
|
||
|
||
SID = N2kMsg.GetByte(Index);
|
||
Mode = (tN2kRangeResidualMode)(N2kMsg.GetByte(Index) & 0x03);
|
||
NumberOfSVs = N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool ParseN2kPGN129540(const tN2kMsg& N2kMsg,
|
||
uint8_t SVIndex,
|
||
tSatelliteInfo& SatelliteInfo)
|
||
{
|
||
if(N2kMsg.PGN != 129540L) return false;
|
||
|
||
int Index = 2;
|
||
uint8_t NumberOfSVs=N2kMsg.GetByte(Index);
|
||
bool ret=( NumberOfSVs<MaxSatelliteInfoCount && SVIndex<NumberOfSVs );
|
||
|
||
if ( ret ) {
|
||
Index=3+SVIndex*12;
|
||
SatelliteInfo.PRN=N2kMsg.GetByte(Index);
|
||
SatelliteInfo.Elevation=N2kMsg.Get2ByteDouble(1e-4L,Index);
|
||
SatelliteInfo.Azimuth=N2kMsg.Get2ByteUDouble(1e-4L,Index);
|
||
SatelliteInfo.SNR=N2kMsg.Get2ByteDouble(1e-2L,Index);
|
||
SatelliteInfo.RangeResiduals=N2kMsg.Get4ByteDouble(1e-5L,Index);;
|
||
SatelliteInfo.UsageStatus=(tN2kPRNUsageStatus)(N2kMsg.GetByte(Index) & 0x0f);
|
||
} else {
|
||
SatelliteInfo.PRN=0xff;
|
||
SatelliteInfo.Elevation=N2kDoubleNA;
|
||
SatelliteInfo.Azimuth=N2kDoubleNA;
|
||
SatelliteInfo.SNR=N2kDoubleNA;
|
||
SatelliteInfo.RangeResiduals=N2kDoubleNA;
|
||
SatelliteInfo.UsageStatus=N2kDD124_Unavailable;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS position report (class A 129038)
|
||
// Latitude and Longitude in degrees (1e7)
|
||
// COG and Heading in radians (1e4)
|
||
bool ParseN2kPGN129038(const tN2kMsg &N2kMsg,
|
||
uint8_t &MessageID,
|
||
tN2kAISRepeat &Repeat,
|
||
uint32_t &UserID,
|
||
double &Latitude,
|
||
double &Longitude,
|
||
bool &Accuracy,
|
||
bool &RAIM,
|
||
uint8_t &Seconds,
|
||
double &COG,
|
||
double &SOG,
|
||
double &Heading,
|
||
double &ROT,
|
||
tN2kAISNavStatus &NavStatus)
|
||
{
|
||
if (N2kMsg.PGN!=129038L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb=N2kMsg.GetByte(Index); MessageID=(vb & 0x3f); Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
UserID=N2kMsg.Get4ByteUInt(Index);
|
||
Longitude=N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
Latitude=N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
vb=N2kMsg.GetByte(Index); Accuracy=(vb & 0x01); RAIM=(vb>>1 & 0x01); Seconds=(vb>>2 & 0x3f);
|
||
COG=N2kMsg.Get2ByteUDouble(1e-04, Index);
|
||
SOG=N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
vb=N2kMsg.GetByte(Index); // Communication State (19 bits)
|
||
vb=N2kMsg.GetByte(Index);
|
||
vb=N2kMsg.GetByte(Index); // AIS transceiver information (5 bits)
|
||
Heading=N2kMsg.Get2ByteUDouble(1e-04, Index);
|
||
ROT=N2kMsg.Get2ByteDouble(3.125E-05, Index); // 1e-3/32.0
|
||
vb=N2kMsg.GetByte(Index); NavStatus=(tN2kAISNavStatus)(vb & 0x0f);
|
||
vb=N2kMsg.GetByte(Index); // Reserved
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS position report (class B 129039)
|
||
bool ParseN2kPGN129039(const tN2kMsg &N2kMsg,
|
||
uint8_t &MessageID,
|
||
tN2kAISRepeat &Repeat,
|
||
uint32_t &UserID,
|
||
double &Latitude,
|
||
double &Longitude,
|
||
bool &Accuracy,
|
||
bool &RAIM,
|
||
uint8_t &Seconds,
|
||
double &COG,
|
||
double &SOG,
|
||
tN2kAISTransceiverInformation &AISTransceiverInformation,
|
||
double &Heading,
|
||
tN2kAISUnit &Unit,
|
||
bool &Display,
|
||
bool &DSC,
|
||
bool &Band,
|
||
bool &Msg22,
|
||
tN2kAISMode &Mode, bool &State)
|
||
{
|
||
if (N2kMsg.PGN!=129039L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb=N2kMsg.GetByte(Index); MessageID=(vb & 0x3f); Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
UserID=N2kMsg.Get4ByteUInt(Index);
|
||
Longitude=N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
Latitude=N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
vb=N2kMsg.GetByte(Index); Accuracy=(vb & 0x01); RAIM=(vb>>1 & 0x01); Seconds=(vb>>2 & 0x3f);
|
||
COG=N2kMsg.Get2ByteUDouble(1e-04, Index);
|
||
SOG=N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
vb=N2kMsg.GetByte(Index); // Communication State (19 bits)
|
||
vb=N2kMsg.GetByte(Index);
|
||
vb=N2kMsg.GetByte(Index); // AIS transceiver information (5 bits)
|
||
AISTransceiverInformation = (tN2kAISTransceiverInformation)((vb >> 3) & 0x1f);
|
||
Heading=N2kMsg.Get2ByteUDouble(1e-04, Index);
|
||
vb=N2kMsg.GetByte(Index); // Regional application
|
||
vb=N2kMsg.GetByte(Index);
|
||
Unit=(tN2kAISUnit)(vb>>2 & 0x01); Display=(vb>>3 & 0x01); DSC=(vb>>4 & 0x01);
|
||
Band=(vb>>5 & 0x01); Msg22=(vb>>6 & 0x01); Mode=(tN2kAISMode)(vb>>7 & 0x01);
|
||
vb=N2kMsg.GetByte(Index); State=(vb & 0x01);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS Aids to Navigation (AtoN) Report (PGN 129041)
|
||
bool ParseN2kPGN129041(const tN2kMsg &N2kMsg,
|
||
tN2kAISAtoNReportData &N2kData)
|
||
{
|
||
if (N2kMsg.PGN!=129041L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
vb=N2kMsg.GetByte(Index); N2kData.MessageID=(vb & 0x3f); N2kData.Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
N2kData.UserID=N2kMsg.Get4ByteUInt(Index);
|
||
N2kData.Longitude=N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
N2kData.Latitude=N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
vb=N2kMsg.GetByte(Index); N2kData.Accuracy=(vb & 0x01); N2kData.RAIM=(vb>>1 & 0x01); N2kData.Seconds=(vb>>2 & 0x3f);
|
||
N2kData.Length=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
N2kData.Beam=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
N2kData.PositionReferenceStarboard=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
N2kData.PositionReferenceTrueNorth=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
vb=N2kMsg.GetByte(Index);
|
||
N2kData.AtoNType=(tN2kAISAtoNType)(vb & 0x1f);
|
||
N2kData.OffPositionIndicator=(vb >> 5 & 0x01);
|
||
N2kData.VirtualAtoNFlag=(vb >> 6 & 0x01);
|
||
N2kData.AssignedModeFlag=(vb >> 7 & 0x01);
|
||
N2kData.GNSSType = (tN2kGNSStype)((N2kMsg.GetByte(Index) >> 1) & 0x0f);
|
||
N2kData.AtoNStatus=N2kMsg.GetByte(Index);
|
||
N2kData.AISTransceiverInformation = (tN2kAISTransceiverInformation)(N2kMsg.GetByte(Index) & 0x1f);
|
||
size_t AtoNNameSize = sizeof(N2kData.AtoNName);
|
||
N2kMsg.GetVarStr(AtoNNameSize, (char*)N2kData.AtoNName, Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Cross Track Error
|
||
bool ParseN2kPGN129283(const tN2kMsg &N2kMsg,
|
||
unsigned char& SID,
|
||
tN2kXTEMode& XTEMode,
|
||
bool& NavigationTerminated,
|
||
double& XTE)
|
||
{
|
||
if(N2kMsg.PGN != 129283L)
|
||
return false;
|
||
|
||
int Index = 0;
|
||
unsigned char c;
|
||
SID = N2kMsg.GetByte(Index);
|
||
c = N2kMsg.GetByte(Index);
|
||
XTEMode = (tN2kXTEMode)(c & 0x0F);
|
||
NavigationTerminated = c & 0x40;
|
||
XTE = N2kMsg.Get4ByteDouble(0.01, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Navigation info
|
||
bool ParseN2kPGN129284(const tN2kMsg &N2kMsg,
|
||
unsigned char& SID,
|
||
double& DistanceToWaypoint,
|
||
tN2kHeadingReference& BearingReference,
|
||
bool& PerpendicularCrossed,
|
||
bool& ArrivalCircleEntered,
|
||
tN2kDistanceCalculationType& CalculationType,
|
||
double& ETATime,
|
||
int16_t& ETADate,
|
||
double& BearingOriginToDestinationWaypoint,
|
||
double& BearingPositionToDestinationWaypoint,
|
||
uint32_t& OriginWaypointNumber,
|
||
uint32_t& DestinationWaypointNumber,
|
||
double& DestinationLatitude,
|
||
double& DestinationLongitude,
|
||
double& WaypointClosingVelocity)
|
||
{
|
||
if(N2kMsg.PGN != 129284L)
|
||
return false;
|
||
|
||
int Index=0;
|
||
unsigned char c;
|
||
SID = N2kMsg.GetByte(Index);
|
||
DistanceToWaypoint = N2kMsg.Get4ByteUDouble(0.01, Index);
|
||
c = N2kMsg.GetByte(Index);
|
||
BearingReference = c & 0x01 ? N2khr_magnetic : N2khr_true;
|
||
PerpendicularCrossed = c & 0x04;
|
||
ArrivalCircleEntered = c & 0x10;
|
||
CalculationType = c & 0x40 ? N2kdct_RhumbLine : N2kdct_GreatCircle;
|
||
ETATime = N2kMsg.Get4ByteUDouble(0.0001, Index);
|
||
ETADate = N2kMsg.Get2ByteUInt(Index);
|
||
BearingOriginToDestinationWaypoint = N2kMsg.Get2ByteUDouble(0.0001, Index);
|
||
BearingPositionToDestinationWaypoint = N2kMsg.Get2ByteUDouble(0.0001, Index);
|
||
OriginWaypointNumber = N2kMsg.Get4ByteUInt(Index);
|
||
DestinationWaypointNumber = N2kMsg.Get4ByteUInt(Index);
|
||
DestinationLatitude = N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
DestinationLongitude = N2kMsg.Get4ByteDouble(1e-07, Index);
|
||
WaypointClosingVelocity = N2kMsg.Get2ByteDouble(0.01, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Waypoint list : PGN129285
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS static data A
|
||
bool ParseN2kPGN129794(const tN2kMsg &N2kMsg,
|
||
uint8_t &MessageID,
|
||
tN2kAISRepeat &Repeat,
|
||
uint32_t &UserID,
|
||
uint32_t &IMOnumber,
|
||
char *Callsign,
|
||
size_t CallsignBufSize,
|
||
char *Name,
|
||
size_t NameBufSize,
|
||
uint8_t &VesselType,
|
||
double &Length,
|
||
double &Beam,
|
||
double &PosRefStbd,
|
||
double &PosRefBow,
|
||
uint16_t &ETAdate,
|
||
double &ETAtime,
|
||
double &Draught,
|
||
char *Destination,
|
||
size_t DestinationBufSize,
|
||
tN2kAISVersion &AISversion,
|
||
tN2kGNSStype &GNSStype,
|
||
tN2kAISDTE &DTE,
|
||
tN2kAISTransceiverInformation &AISinfo)
|
||
{
|
||
if (N2kMsg.PGN!=129794L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb=N2kMsg.GetByte(Index); MessageID=(vb & 0x3f); Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
UserID=N2kMsg.Get4ByteUInt(Index);
|
||
IMOnumber=N2kMsg.Get4ByteUInt(Index);
|
||
N2kMsg.GetStr(CallsignBufSize, Callsign, 7, '@', Index);
|
||
N2kMsg.GetStr(NameBufSize, Name, 20, '@', Index);
|
||
VesselType=N2kMsg.GetByte(Index);
|
||
Length=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
Beam=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
PosRefStbd=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
PosRefBow=N2kMsg.Get2ByteDouble(0.1, Index);
|
||
ETAdate=N2kMsg.Get2ByteUInt(Index);
|
||
ETAtime=N2kMsg.Get4ByteUDouble(0.0001, Index);
|
||
Draught=N2kMsg.Get2ByteDouble(0.01, Index);
|
||
N2kMsg.GetStr(DestinationBufSize, Destination, 20, '@', Index);
|
||
vb=N2kMsg.GetByte(Index); AISversion=(tN2kAISVersion)(vb & 0x03); GNSStype=(tN2kGNSStype)(vb>>2 & 0x0f); DTE=(tN2kAISDTE)(vb>>6 & 0x01);
|
||
vb=N2kMsg.GetByte(Index); AISinfo=(tN2kAISTransceiverInformation)(vb & 0x1f);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS static data class B part A
|
||
bool ParseN2kPGN129809(const tN2kMsg &N2kMsg,
|
||
uint8_t &MessageID,
|
||
tN2kAISRepeat &Repeat,
|
||
uint32_t &UserID,
|
||
char *Name,
|
||
size_t NameBufSize)
|
||
{
|
||
if (N2kMsg.PGN!=129809L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb=N2kMsg.GetByte(Index); MessageID=(vb & 0x3f); Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
UserID=N2kMsg.Get4ByteUInt(Index);
|
||
N2kMsg.GetStr(NameBufSize, Name, 20, '@', Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// AIS static data class B part B
|
||
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,
|
||
double &PosRefStbd,
|
||
double &PosRefBow,
|
||
uint32_t &MothershipID)
|
||
{
|
||
if (N2kMsg.PGN!=129810L) return false;
|
||
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb=N2kMsg.GetByte(Index); MessageID=(vb & 0x3f); Repeat=(tN2kAISRepeat)(vb>>6 & 0x03);
|
||
UserID=N2kMsg.Get4ByteUInt(Index);
|
||
VesselType=N2kMsg.GetByte(Index);
|
||
N2kMsg.GetStr(VendorBufSize, Vendor, 7, '@', Index);
|
||
N2kMsg.GetStr(CallsignBufSize, Callsign, 7, '@', Index);
|
||
Length = N2kMsg.Get2ByteUDouble(0.1, Index);
|
||
Beam = N2kMsg.Get2ByteUDouble(0.1, Index);
|
||
PosRefStbd = N2kMsg.Get2ByteUDouble(0.1, Index);
|
||
PosRefBow = N2kMsg.Get2ByteUDouble(0.1, Index);
|
||
MothershipID = N2kMsg.Get4ByteUInt(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Waypoint list PGN130074
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Wind Speed
|
||
bool ParseN2kPGN130306(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &WindSpeed,
|
||
double &WindAngle,
|
||
tN2kWindReference &WindReference)
|
||
{
|
||
if (N2kMsg.PGN!=130306L) return false;
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
WindSpeed=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
WindAngle=N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
WindReference=(tN2kWindReference)(N2kMsg.GetByte(Index)&0x07);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Outside Environmental parameters
|
||
bool ParseN2kPGN130310(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
double &WaterTemperature,
|
||
double &OutsideAmbientAirTemperature,
|
||
double &AtmosphericPressure)
|
||
{
|
||
if (N2kMsg.PGN!=130310L) return false;
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
WaterTemperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
OutsideAmbientAirTemperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
AtmosphericPressure=N2kMsg.Get2ByteUDouble(100,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Environmental parameters
|
||
bool ParseN2kPGN130311(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
tN2kTempSource &TempSource,
|
||
double &Temperature,
|
||
tN2kHumiditySource &HumiditySource,
|
||
double &Humidity,
|
||
double &AtmosphericPressure)
|
||
{
|
||
if (N2kMsg.PGN!=130311L) return false;
|
||
unsigned char vb;
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
vb=N2kMsg.GetByte(Index); TempSource=(tN2kTempSource)(vb & 0x3f); HumiditySource=(tN2kHumiditySource)(vb>>6 & 0x03);
|
||
Temperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
Humidity=N2kMsg.Get2ByteDouble(0.004,Index);
|
||
AtmosphericPressure=N2kMsg.Get2ByteUDouble(100,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Temperature
|
||
// Temperatures should be in Kelvins
|
||
bool ParseN2kPGN130312(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &TempInstance,
|
||
tN2kTempSource &TempSource,
|
||
double &ActualTemperature,
|
||
double &SetTemperature)
|
||
{
|
||
if (N2kMsg.PGN!=130312L) return false;
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
TempInstance=N2kMsg.GetByte(Index);
|
||
TempSource=(tN2kTempSource)(N2kMsg.GetByte(Index));
|
||
ActualTemperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
SetTemperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Humidity
|
||
// Humidity should be in percent
|
||
bool ParseN2kPGN130313(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &HumidityInstance,
|
||
tN2kHumiditySource &HumiditySource,
|
||
double &ActualHumidity,
|
||
double &SetHumidity)
|
||
{
|
||
if (N2kMsg.PGN != 130313L) return false;
|
||
int Index = 0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
HumidityInstance=N2kMsg.GetByte(Index);
|
||
HumiditySource=(tN2kHumiditySource)N2kMsg.GetByte(Index);
|
||
ActualHumidity=N2kMsg.Get2ByteDouble(0.004, Index);
|
||
SetHumidity=N2kMsg.Get2ByteDouble(0.004, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Actual Pressure
|
||
// Pressure should be in Pascals
|
||
bool ParseN2kPGN130314(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &PressureInstance,
|
||
tN2kPressureSource &PressureSource,
|
||
double &ActualPressure)
|
||
{
|
||
if (N2kMsg.PGN != 130314L) return false;
|
||
int Index = 0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
PressureInstance=N2kMsg.GetByte(Index);
|
||
PressureSource=(tN2kPressureSource)N2kMsg.GetByte(Index);
|
||
ActualPressure=N2kMsg.Get4ByteDouble(0.1, Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Set Pressure
|
||
// Pressure should be in Pascals PGN130315
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Temperature extended range
|
||
// Temperatures should be in Kelvins
|
||
bool ParseN2kPGN130316(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &TempInstance,
|
||
tN2kTempSource &TempSource,
|
||
double &ActualTemperature,
|
||
double &SetTemperature)
|
||
{
|
||
if (N2kMsg.PGN!=130316L) return false;
|
||
int Index=0;
|
||
SID=N2kMsg.GetByte(Index);
|
||
TempInstance=N2kMsg.GetByte(Index);
|
||
TempSource=(tN2kTempSource)(N2kMsg.GetByte(Index));
|
||
ActualTemperature=N2kMsg.Get3ByteDouble(0.001,Index);
|
||
SetTemperature=N2kMsg.Get2ByteUDouble(0.1,Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Meteorological Station Data
|
||
bool ParseN2kPGN130323(const tN2kMsg &N2kMsg,
|
||
tN2kMeteorlogicalStationData &N2kData)
|
||
{
|
||
if (N2kMsg.PGN!=130323L) return false;
|
||
int Index=0;
|
||
unsigned char vb;
|
||
|
||
vb = N2kMsg.GetByte(Index);
|
||
N2kData.Mode=(tN2kAISMode)(vb & 0x0f);
|
||
N2kData.SystemDate = N2kMsg.Get2ByteUInt(Index);
|
||
N2kData.SystemTime = N2kMsg.Get4ByteUDouble(0.0001,Index);
|
||
N2kData.Latitude = N2kMsg.Get4ByteDouble(1e-7,Index);
|
||
N2kData.Longitude = N2kMsg.Get4ByteDouble(1e-7,Index);
|
||
N2kData.WindSpeed = N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
N2kData.WindDirection = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
vb = N2kMsg.GetByte(Index);
|
||
N2kData.WindReference = (tN2kWindReference)(vb & 0x07);
|
||
N2kData.WindGusts = N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
N2kData.AtmosphericPressure = N2kMsg.Get2ByteUDouble(100,Index);
|
||
N2kData.OutsideAmbientAirTemperature=N2kMsg.Get2ByteUDouble(0.01,Index);
|
||
size_t StationIDSize = sizeof(N2kData.StationID);
|
||
size_t StationNameSize = sizeof(N2kData.StationName);
|
||
N2kMsg.GetVarStr(StationIDSize, (char*)N2kData.StationID, Index);
|
||
N2kMsg.GetVarStr(StationNameSize, (char*)N2kData.StationName, Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Trim Tab Position
|
||
// Trim tab position is a percentage 0 to 100% where 0 is fully retracted and 100 is fully extended
|
||
bool ParseN2kPGN130576(const tN2kMsg &N2kMsg,
|
||
int8_t &PortTrimTab,
|
||
int8_t &StbdTrimTab)
|
||
{
|
||
if (N2kMsg.PGN!=130576L) return false;
|
||
int Index=0;
|
||
PortTrimTab=N2kMsg.GetByte(Index);
|
||
StbdTrimTab=N2kMsg.GetByte(Index);
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Direction Data
|
||
bool ParseN2kPGN130577(const tN2kMsg &N2kMsg,
|
||
tN2kDataMode &DataMode,
|
||
tN2kHeadingReference &CogReference,
|
||
unsigned char &SID,
|
||
double &COG,
|
||
double &SOG,
|
||
double &Heading,
|
||
double &SpeedThroughWater,
|
||
double &Set,
|
||
double &Drift)
|
||
{
|
||
if (N2kMsg.PGN!=130577L) return false;
|
||
int Index=0;
|
||
unsigned char v;
|
||
v = N2kMsg.GetByte(Index);
|
||
DataMode = (tN2kDataMode)(v & 0x0F);
|
||
CogReference = (tN2kHeadingReference)((v >> 4) & 0x03);
|
||
SID = N2kMsg.GetByte(Index);
|
||
COG = N2kMsg.Get2ByteUDouble(0.0001,Index);
|
||
SOG = N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
Heading = N2kMsg.Get2ByteUDouble(0.0001, Index);
|
||
SpeedThroughWater= N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
Set = N2kMsg.Get2ByteUDouble(0.0001, Index);
|
||
Drift = N2kMsg.Get2ByteUDouble(0.01, Index);
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Temperature High Range [MARETRON TMP100]
|
||
// Temperatures should be in Kelvin
|
||
bool ParseN2kMaretronPGN130823(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &TempInstance,
|
||
tN2kTempSource &TempSource,
|
||
double &ActualTemperature,
|
||
double &SetTemperature)
|
||
{
|
||
if (N2kMsg.PGN!=130823L) return false;
|
||
int Index=0;
|
||
if (N2kMsg.Get2ByteUInt(Index)!=MaretronProprietary ) return false;
|
||
SID=N2kMsg.GetByte(Index);
|
||
TempInstance=N2kMsg.GetByte(Index);
|
||
TempSource=(tN2kTempSource)(N2kMsg.GetByte(Index));
|
||
ActualTemperature=N2kMsg.Get2ByteUDouble(0.1,Index);
|
||
SetTemperature=N2kMsg.Get2ByteUDouble(0.1,Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Fluid Flow Rate [MARETRON FFM100]
|
||
// Flow unit is 1 lt/hour
|
||
bool ParseN2kMaretronPGN65286(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &FlowRateInstance,
|
||
tN2kFluidType &FluidType,
|
||
double &FluidFlowRate)
|
||
{
|
||
if (N2kMsg.PGN!=65286L) return false;
|
||
int Index=0;
|
||
if (N2kMsg.Get2ByteUInt(Index)!=MaretronProprietary ) return false;
|
||
SID=N2kMsg.GetByte(Index);
|
||
FlowRateInstance=N2kMsg.GetByte(Index);
|
||
FluidType=(tN2kFluidType)(N2kMsg.GetByte(Index));
|
||
FluidFlowRate=N2kMsg.Get3ByteDouble(0.1,Index);
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Trip Volume [MARETRON FFM100]
|
||
// Volume unit is 1 litre
|
||
bool ParseN2kMaretronPGN65287(const tN2kMsg &N2kMsg,
|
||
unsigned char &SID,
|
||
unsigned char &VolumeInstance,
|
||
tN2kFluidType &FluidType,
|
||
double &TripVolume)
|
||
{
|
||
if (N2kMsg.PGN!=65287L) return false;
|
||
int Index=0;
|
||
if (N2kMsg.Get2ByteUInt(Index)!=MaretronProprietary ) return false;
|
||
SID=N2kMsg.GetByte(Index);
|
||
VolumeInstance=N2kMsg.GetByte(Index);
|
||
FluidType=(tN2kFluidType)(N2kMsg.GetByte(Index));
|
||
TripVolume=N2kMsg.Get3ByteDouble(1,Index);
|
||
return true;
|
||
}
|
||
|
||
|
||
*/
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//===========================================================================================================================================
|
||
|
||
// Foonctions provenant de N2kMsg.cpp : https://ttlappalainen.github.io/NMEA2000/_n2k_msg_8cpp_source.html
|
||
|
||
|
||
/*
|
||
//-----------------------------------------------------------------------------
|
||
unsigned char tN2kMsg::GetByte(int &Index) const {
|
||
if (Index<DataLen) {
|
||
return Data[Index++];
|
||
} else return 0xff;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
int16_t tN2kMsg::Get2ByteInt(int &Index, int16_t def) const {
|
||
if (Index+2<=DataLen) {
|
||
return GetBuf2ByteInt(Index,Data);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint16_t tN2kMsg::Get2ByteUInt(int &Index, uint16_t def) const {
|
||
if (Index+2<=DataLen) {
|
||
return GetBuf2ByteUInt(Index,Data);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint32_t tN2kMsg::Get3ByteUInt(int &Index, uint32_t def) const {
|
||
if (Index+3<=DataLen) {
|
||
return GetBuf3ByteUInt(Index,Data);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint32_t tN2kMsg::Get4ByteUInt(int &Index, uint32_t def) const {
|
||
if (Index+4<=DataLen) {
|
||
return GetBuf4ByteUInt(Index,Data);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint64_t tN2kMsg::GetUInt64(int &Index, uint64_t def) const {
|
||
if (Index+8<=DataLen) {
|
||
return GetBuf8ByteUInt(Index,Data);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get1ByteDouble(double precision, int &Index, double def) const {
|
||
if (Index<DataLen) {
|
||
return GetBuf1ByteDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get1ByteUDouble(double precision, int &Index, double def) const {
|
||
if (Index<DataLen) {
|
||
return GetBuf1ByteUDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get2ByteDouble(double precision, int &Index, double def) const {
|
||
if (Index+2<=DataLen) {
|
||
return GetBuf2ByteDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get2ByteUDouble(double precision, int &Index, double def) const {
|
||
if (Index+2<=DataLen) {
|
||
return GetBuf2ByteUDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get3ByteDouble(double precision, int &Index, double def) const {
|
||
if (Index+3<=DataLen) {
|
||
return GetBuf3ByteDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get4ByteDouble(double precision, int &Index, double def) const {
|
||
if (Index+4<=DataLen) {
|
||
return GetBuf4ByteDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get4ByteUDouble(double precision, int &Index, double def) const {
|
||
if (Index+4<=DataLen) {
|
||
return GetBuf4ByteUDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double tN2kMsg::Get8ByteDouble(double precision, int &Index, double def) const {
|
||
if (Index+8<=DataLen) {
|
||
return GetBuf8ByteDouble(precision,Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
float tN2kMsg::GetFloat(int &Index, float def) const {
|
||
if (Index+4<=DataLen) {
|
||
return GetBufFloat(Index,Data,def);
|
||
} else return def;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool tN2kMsg::GetStr(char *StrBuf, size_t Length, int &Index) const {
|
||
unsigned char vb;
|
||
bool nullReached = false;
|
||
StrBuf[0] = '\0';
|
||
if ((size_t)Index+Length<=(size_t)DataLen) {
|
||
for (size_t i=0; i<Length; i++) {
|
||
vb = GetByte(Index);
|
||
if (! nullReached) {
|
||
if (vb == 0x00 || vb == '@') {
|
||
nullReached = true; // either null or '@' (AIS null character)
|
||
StrBuf[i] = '\0';
|
||
StrBuf[i+1] = '\0';
|
||
} else {
|
||
StrBuf[i] = vb;
|
||
StrBuf[i+1] = '\0';
|
||
}
|
||
} else {
|
||
StrBuf[i] = '\0';
|
||
StrBuf[i+1] = '\0';
|
||
}
|
||
}
|
||
return true;
|
||
} else return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool tN2kMsg::GetStr(size_t StrBufSize, char *StrBuf, size_t Length, unsigned char nulChar, int &Index) const {
|
||
unsigned char vb;
|
||
bool nullReached = false;
|
||
if ( StrBufSize==0 || StrBuf==0 ) {
|
||
Index+=Length;
|
||
return true;
|
||
}
|
||
StrBuf[0] = '\0';
|
||
if ((size_t)Index+Length<=(size_t)DataLen) {
|
||
size_t i;
|
||
for (i=0; i<Length && i<StrBufSize-1; i++) {
|
||
vb = GetByte(Index);
|
||
if (! nullReached) {
|
||
if (vb == 0x00 || vb == nulChar ) {
|
||
nullReached = true; // either null or '@' (AIS null character)
|
||
StrBuf[i] = '\0';
|
||
} else {
|
||
StrBuf[i] = vb;
|
||
}
|
||
} else {
|
||
StrBuf[i] = '\0';
|
||
}
|
||
}
|
||
StrBuf[i] = '\0';
|
||
for (;i<Length;i++) GetByte(Index); // Stopped by buffer size, so read out bytes from message
|
||
for (;i<StrBufSize;i++) StrBuf[i] = '\0'; // Stopped by length, fill buffer with 0
|
||
return true;
|
||
} else return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool tN2kMsg::GetVarStr(size_t &StrBufSize, char *StrBuf, int &Index) const {
|
||
size_t Len=GetByte(Index)-2;
|
||
uint8_t Type=GetByte(Index);
|
||
if ( Type!=0x01 ) { StrBufSize=0; return false; }
|
||
if ( StrBuf!=0 ) {
|
||
GetStr(StrBufSize,StrBuf,Len,0xff,Index);
|
||
} else {
|
||
Index+=Len; // Just pass this string
|
||
}
|
||
StrBufSize=Len;
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool tN2kMsg::GetBuf(void *buf, size_t Length, int &Index) const {
|
||
bool ret=true;
|
||
|
||
if ((size_t)Index+Length<=(size_t)DataLen) {
|
||
if ( buf!=0 ) {
|
||
memcpy(buf,Data+Index,Length);
|
||
} else {
|
||
Index+=Length; // Just pass this string
|
||
}
|
||
} else {
|
||
Index=DataLen;
|
||
ret=false;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
int16_t GetBuf2ByteInt(int &index, const unsigned char *buf) {
|
||
return GetBuf<int16_t>(2, index, buf);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint16_t GetBuf2ByteUInt(int &index, const unsigned char *buf) {
|
||
return GetBuf<uint16_t>(2, index, buf);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint32_t GetBuf3ByteUInt(int &index, const unsigned char *buf) {
|
||
return GetBuf<uint32_t>(3, index, buf);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint32_t GetBuf4ByteUInt(int &index, const unsigned char *buf) {
|
||
return GetBuf<uint32_t>(4, index, buf);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
uint64_t GetBuf8ByteUInt(int &index, const unsigned char *buf) {
|
||
return GetBuf<uint64_t>(8, index, buf);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf1ByteDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
int8_t vl = GetBuf<int8_t>(1, index, buf);
|
||
if (vl==0x7f) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf1ByteUDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
uint8_t vl = GetBuf<uint8_t>(1, index, buf);
|
||
if (vl==0xff) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf2ByteDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
int16_t vl = GetBuf<int16_t>(2, index, buf);
|
||
if (vl==0x7fff) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf2ByteUDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
uint16_t vl = GetBuf<uint16_t>(2, index, buf);
|
||
if (vl==0xffff) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf8ByteDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
int64_t vl = GetBuf<int64_t>(8, index, buf);
|
||
if (vl==0x7fffffffffffffffLL) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBufDouble(int &index, const unsigned char *buf, double def) {
|
||
int64_t vl = GetBuf<int64_t>(8, index, buf);
|
||
double ret;
|
||
// On avr double==float, so we test it also. Currently no handling for avr.
|
||
if ( sizeof(double)==8 && !N2kIsNA(vl) ) {
|
||
memcpy(&ret,&vl,8);
|
||
if ( isnan(ret) ) ret=def;
|
||
} else {
|
||
ret=def;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
float GetBufFloat(int &index, const unsigned char *buf, float def) {
|
||
int32_t vl = GetBuf<int32_t>(4, index, buf);
|
||
float ret;
|
||
if ( !N2kIsNA(vl) ) {
|
||
memcpy(&ret,&vl,4);
|
||
if ( isnan(ret) ) ret=def;
|
||
} else { // On avr double==float
|
||
ret=def;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf3ByteDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
int32_t vl = GetBuf<int32_t>(3, index, buf);
|
||
if (vl==0x007fffff) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf4ByteDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
int32_t vl = GetBuf<int32_t>(4, index, buf);
|
||
if (vl==0x7fffffff) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
double GetBuf4ByteUDouble(double precision, int &index, const unsigned char *buf, double def) {
|
||
uint32_t vl = GetBuf<uint32_t>(4, index, buf);
|
||
if (vl==0xffffffff) return def;
|
||
|
||
return vl * precision;
|
||
}
|
||
|
||
*/
|