Files

3329 lines
157 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//**********************************************************************************************************************************************************************************
// Fichier C_COMMANDES_.C
//
// Contient toutes les fonctions liées aux commandes envoyées et reçues sur C_Bus
//**********************************************************************************************************************************************************************************/
// #define __DEBUG_COMMANDES_C_BUS
// Includes :
#include "main.h"
// Prototypes :
// Commandes Down :
int8_t c_bus_down_commande_config_date_heure(void);
int8_t c_bus_down_commande_config_carte(uint8_t adresse_module, uint8_t mode);
int8_t c_bus_down_commande_config_circuits(uint8_t adresse_module);
int8_t c_bus_down_commande_config_level_sensors(void);
int8_t c_bus_down_commande_config_ow(void);
int8_t c_bus_down_commande_config_batteries(uint8_t adresse_module);
int8_t c_bus_down_commande_config_pgn_nmea(uint16_t rang);
int8_t c_bus_down_commande_reset(void);
int8_t c_bus_down_commande_cde_backlight(float consigne_ecran, float consigne_leds);
int8_t c_bus_down_commande_cde_circuits(uint8_t adresse_module);
int8_t c_bus_down_commande_cde_carte(uint8_t adresse_module, uint8_t cde, uint8_t consigne);
int8_t c_bus_down_commande_lecture_date_heure(void);
int8_t c_bus_down_commande_lecture_id_carte(uint8_t adresse_module);
int8_t c_bus_down_commande_annuaire_k_bus(void);
int8_t c_bus_down_commande_chargement_code(uint8_t mode, uint8_t adresse_module);
int8_t c_bus_down_commande_annuaire_ow(void);
// Réponses Down :
int8_t c_bus_down_reponse_config_date_heure(void);
int8_t c_bus_down_reponse_cde_backlight(void);
int8_t c_bus_down_reponse_lecture_date_heure(void);
int8_t c_bus_down_reponse_lecture_id_carte(void);
int8_t c_bus_down_reponse_annuaire_k_bus(void);
int8_t c_bus_down_reponse_chargement_code(void);
int8_t c_bus_down_reponse_annuaire_ow(void);
int8_t c_bus_down_reponse_generique(void);
int8_t c_bus_down_recherche_reponse(void);
// Commandes UP :
uint8_t c_bus_up_commande_etat_carte(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_circuits(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_entrees_aux(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_level_sensors(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_entrees_volt(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_entrees_ow(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_entrees_batteries(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_etat_pgn_nmea(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_config_carte(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_commande_inconnue(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse);
uint8_t c_bus_up_recherche_commande(void);
// Variables globales :
//***************************************************************************************************************************************************************
//***************************************************************************************************************************************************************
// DOWN - Commandes
//***************************************************************************************************************************************************************
//***************************************************************************************************************************************************************
//==================================================================================================================================================================
// Fonction : Fonction qui permet au master de configurer la date et l'heure courante stockée dans le RTC de la carte.
// Reçoit : Le numéro de carte concernée (0=Compagnon, >0= adresse de la carte sur K-Bus)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_date_heure(void)
{
time_t timestamp;
struct tm * t;
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_FAIBLE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
timestamp = time(NULL);
t = localtime(&timestamp);
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_DATE_HEURE;
buffer_cde->cde[buffer_cde->lg_cde ++] = t->tm_mday;
buffer_cde->cde[buffer_cde->lg_cde ++] = (t->tm_mon)+1; // tm_mon va de 0 à 11
buffer_cde->cde[buffer_cde->lg_cde ++] = t->tm_year; // Nombre d'années écoulées depuis 1900
buffer_cde->cde[buffer_cde->lg_cde ++] = t->tm_hour;
buffer_cde->cde[buffer_cde->lg_cde ++] = t->tm_min;
buffer_cde->cde[buffer_cde->lg_cde ++] = t->tm_sec;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au CM3P de configurer une carte ou le Compagnon
// Reçoit : Le numéro de carte concernée (0=Compagnon, >0= adresse de la carte sur K-Bus) et le Mode d'envoi de la commande (0= read, 1= write)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_carte(uint8_t adresse_module, uint8_t mode)
{
int16_t val;
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
if (adresse_module >= MAX_NOMBRE_MODULES) return(-1);
if (systeme.modules_config[adresse_module].flag_presence == FALSE) return(-1);
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_CARTE;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SHIPBASE : // <coeff filtrage tension alim><coeff filtrage intensité alim><coeff filtrage intensité usb><coeff filtrage température><coeff filtrage pression><coeff filtrage humidité>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage tension
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage courant d'entrée
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage courant USB
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage température
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage pression atmosphérique
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage humidité
break;
}
case TYPE_CARTE_SP812 : // <coeff filtrage tension alim><coeff filtrage température>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage tension
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage température
break;
}
case TYPE_CARTE_SP8DC : // <coeff filtrage tension alim><coeff filtrage température><courant de masses maxi>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage tension
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage température
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (systeme.courant_masses_maxi_sp8dc * 10); // Courant de masse maxi. Passage de A à dixièmes d'A // SDIR #138
break;
}
case TYPE_CARTE_SBS :
{
// Attention : dans les lignes ci-dessous, on utilise 'modules_physiques' au lieu de 'modules' car les infos d'EEPROM sont relatives au module PHYSIQUE
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage température shunt
if ((mode == C_BUS_CONFIG_WRITE_COURANTE) || (mode == C_BUS_CONFIG_WRITE_USINE))
{
val = (int16_t) (((uint16_t)systeme.modules_physiques[adresse_module].eeprom[1] << 8) + (uint16_t) systeme.modules_physiques[adresse_module].eeprom[0]);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (val & 0x00FF); // LSB de l'offset
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) ((val >> 8) & 0x00FF); // MSB de l'offset
val = (int16_t) (((uint16_t)systeme.modules_physiques[adresse_module].eeprom[3] << 8) + (uint16_t) systeme.modules_physiques[adresse_module].eeprom[2]);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (val & 0x00FF); // LSB du gain
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) ((val >> 8) & 0x00FF); // MSB du gain
}
if (mode == C_BUS_CONFIG_WRITE_USINE)
{
val = (int16_t) (((uint16_t)systeme.modules_physiques[adresse_module].eeprom[5] << 8) + (uint16_t) systeme.modules_physiques[adresse_module].eeprom[4]);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (val & 0x00FF); // LSB de l'offset usine
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) ((val >> 8) & 0x00FF); // MSB de l'offset usine
val = (int16_t) (((uint16_t)systeme.modules_physiques[adresse_module].eeprom[7] << 8) + (uint16_t) systeme.modules_physiques[adresse_module].eeprom[6]);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (val & 0x00FF); // LSB du gain usine
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) ((val >> 8) & 0x00FF); // MSB du gain usine
}
break;
}
case TYPE_CARTE_SP4AC :
{
buffer_cde->cde[buffer_cde->lg_cde ++] = 4; // Coeff filtrage température module
break;
}
default : return(-1);
}
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au master de configurer les circuits de puissance d'une carte extension
// Reçoit : Le numéro de carte dont les circuits sont configurés (>0, adresse de la carte sur K-Bus)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_circuits(uint8_t adresse_module)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
uint16_t i;
struct {
uint8_t validite;
uint8_t type;
uint8_t tension_coeff_filtrage;
uint8_t intensite_coeff_filtrage;
uint8_t frequence_coeff_filtrage;
uint16_t intensite_seuil_haut;
uint16_t intensite_seuil_haut_tempo;
uint8_t step_time;
} tmp_circuits[MAX_NOMBRE_CIRCUITS];
for (i = 0; i < MAX_NOMBRE_CIRCUITS; i ++) // Valeurs par défaut
{
tmp_circuits[i].validite = FALSE;
tmp_circuits[i].type = 0;
tmp_circuits[i].tension_coeff_filtrage = 1;
tmp_circuits[i].intensite_coeff_filtrage = 1;
tmp_circuits[i].frequence_coeff_filtrage = 1;
tmp_circuits[i].intensite_seuil_haut = 0;
tmp_circuits[i].intensite_seuil_haut_tempo = 0;
tmp_circuits[i].step_time = 50;
}
// Vérification du paramètre reçu :
if (adresse_module >= MAX_NOMBRE_MODULES) return(-1);
if (systeme.modules_config[adresse_module].flag_presence == FALSE) return(-1);
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SP8DC :
{
for (i = 0; i < circuits.nb; i ++)
{
if (circuits.circuits[i].flag_validite == FALSE) continue; // On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
if (circuits.circuits[i].adresse_module != adresse_module) continue;
if (circuits.circuits[i].no_circuit >= SP8XX_NOMBRE_CIRCUITS) return(-1); // Cas d'erreur qui ne devrait pas arriver après les tests d'initialisation...
tmp_circuits[circuits.circuits[i].no_circuit].validite = circuits.circuits[i].flag_validite;
switch(circuits.circuits[i].mode_cde)
{
case CIRCUITS_MODE_COMMANDE_ON_OFF: { tmp_circuits[circuits.circuits[i].no_circuit].type = SP8XX_TYPE_CIRCUIT_ON_OFF; break; }
case CIRCUITS_MODE_COMMANDE_ON_OFF_SOFT: { tmp_circuits[circuits.circuits[i].no_circuit].type = SP8XX_TYPE_CIRCUIT_ON_OFF_SOFT; break; }
case CIRCUITS_MODE_COMMANDE_VARIABLE_SOFT: { tmp_circuits[circuits.circuits[i].no_circuit].type = SP8XX_TYPE_CIRCUIT_VARIABLE_SOFT; break; }
case CIRCUITS_MODE_COMMANDE_CADENCE: { tmp_circuits[circuits.circuits[i].no_circuit].type = SP8XX_TYPE_CIRCUIT_ON_OFF; break; }
default: { tmp_circuits[circuits.circuits[i].no_circuit].type = SP8XX_TYPE_CIRCUIT_ON_OFF; break; }
}
tmp_circuits[circuits.circuits[i].no_circuit].intensite_coeff_filtrage = circuits.circuits[i].intensite_coeff_filtrage;
tmp_circuits[circuits.circuits[i].no_circuit].intensite_seuil_haut = 0; // circuits.circuits[i].intensite_seuil_haut; // Modif du 09/07/2022 pour que le traitement de LIMITATION soit dorénavant fait au niveau de l'appli et plus du ShipPower8xx.
tmp_circuits[circuits.circuits[i].no_circuit].intensite_seuil_haut_tempo = circuits.circuits[i].intensite_seuil_haut_tempo;
tmp_circuits[circuits.circuits[i].no_circuit].step_time = circuits.circuits[i].step_time;
if (circuits.circuits[i].no_circuit_esclave >= 0) // Cas où le circuit a un esclave
{
tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].type = tmp_circuits[circuits.circuits[i].no_circuit].type; // Utile si le traitement de l'esclave a déjà été fait
circuits.circuits[circuits.circuits[i].no_circuit_esclave].mode_cde = circuits.circuits[i].mode_cde; // Utile si le traitement de l'esclave n'a pas encore été fait
tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].intensite_coeff_filtrage = circuits.circuits[i].intensite_coeff_filtrage; // Utile si le traitement de l'esclave a déjà été fait
circuits.circuits[circuits.circuits[i].no_circuit_esclave].intensite_coeff_filtrage = circuits.circuits[i].intensite_coeff_filtrage; // Utile si le traitement de l'esclave n'a pas encore été fait
tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].intensite_seuil_haut_tempo = circuits.circuits[i].intensite_seuil_haut_tempo; // Utile si le traitement de l'esclave a déjà été fait
circuits.circuits[circuits.circuits[i].no_circuit_esclave].intensite_seuil_haut_tempo = circuits.circuits[i].intensite_seuil_haut_tempo; // Utile si le traitement de l'esclave n'a pas encore été fait
tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].step_time = circuits.circuits[i].step_time; // Utile si le traitement de l'esclave a déjà été fait
circuits.circuits[circuits.circuits[i].no_circuit_esclave].step_time = circuits.circuits[i].step_time; // Utile si le traitement de l'esclave n'a pas encore été fait
}
}
break;
}
case TYPE_CARTE_SP4AC :
{
for (i = 0; i < circuits.nb; i ++)
{
if (circuits.circuits[i].flag_validite == FALSE) continue; // On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
if (circuits.circuits[i].adresse_module != adresse_module) continue;
if (circuits.circuits[i].no_circuit >= SP4AC_NOMBRE_CIRCUITS) return(-1); // Cas d'erreur qui ne devrait pas arriver après les tests d'initialisation...
tmp_circuits[circuits.circuits[i].no_circuit].validite = circuits.circuits[i].flag_validite;
tmp_circuits[circuits.circuits[i].no_circuit].tension_coeff_filtrage = circuits.circuits[i].tension_coeff_filtrage;
tmp_circuits[circuits.circuits[i].no_circuit].intensite_coeff_filtrage = circuits.circuits[i].intensite_coeff_filtrage;
tmp_circuits[circuits.circuits[i].no_circuit].frequence_coeff_filtrage = circuits.circuits[i].frequence_coeff_filtrage;
}
break;
}
default : return(-1);
}
// Préparation de la commande :
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_CIRCUITS;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SP8DC :
{
for (i = 0; i < SP8XX_NOMBRE_CIRCUITS; i ++) // <validité 1><type 1><coeff filtrage intensité 1><seuil haut limitation 1><filtrage seuil haut limitation 1>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].validite;
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].type;
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].intensite_coeff_filtrage;
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(tmp_circuits[i].intensite_seuil_haut & 0x00FF); // LSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(tmp_circuits[i].intensite_seuil_haut >> 8); // MSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(tmp_circuits[i].intensite_seuil_haut_tempo & 0x00FF); // LSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(tmp_circuits[i].intensite_seuil_haut_tempo >> 8); // MSB
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].step_time;
#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Commande de config des circuits sur carte %i, circuit %i : val=%i, type=%i, coeff filtrage intensité=%i, seuil limitation=%i, tempo_limitation=%i",
adresse_module, i, tmp_circuits[i].validite, tmp_circuits[i].type, tmp_circuits[i].intensite_coeff_filtrage, tmp_circuits[i].intensite_seuil_haut, tmp_circuits[i].intensite_seuil_haut_tempo);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
}
break;
}
case TYPE_CARTE_SP4AC :
{
for (i = 0; i < SP4AC_NOMBRE_CIRCUITS; i ++) // <validité 1><type 1><coeff filtrage intensité 1><seuil haut limitation 1><filtrage seuil haut limitation 1>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].validite;
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].tension_coeff_filtrage;
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].intensite_coeff_filtrage;
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].frequence_coeff_filtrage;
#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Commande de config des circuits sur carte %i, circuit %i : val=%i, coeff filtrage tension=%i, coeff filtrage intensité=%i, coeff filtrage fréquence=%i,",
adresse_module, i, tmp_circuits[i].validite, tmp_circuits[i].tension_coeff_filtrage, tmp_circuits[i].intensite_coeff_filtrage, tmp_circuits[i].frequence_coeff_filtrage);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
}
break;
}
default :;
}
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au master de configurer les capteurs de niveaux
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_level_sensors(void)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
uint16_t i;
struct {
uint8_t validite;
uint8_t mode;
uint8_t coeff_filtrage;
} sensors[MAX_NOMBRE_ENTREES_LEVEL_SENSOR];
priorite = PRIORITE_CDE_C_BUS_FAIBLE;
for (i = 0; i < MAX_NOMBRE_ENTREES_LEVEL_SENSOR; i++) // Mise à jour des valeurs par défaut. Nécessaire car ensiuite on ne rempli que les positions des capteurs VALIDES
{
sensors[i].validite = FALSE;
sensors[i].mode = ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_NON_DEFINI;
sensors[i].coeff_filtrage = 1;
}
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_LEVEL_SENSORS;
for (i = 0; i < MAX_NOMBRE_ENTREES_LEVEL_SENSOR; i++) // Calcule, pour chaque capteur, les paramètres de config à adresser au Compagnon :
{
if (entrees.level_sensor.entrees[i].flag_validite != FALSE)
{
sensors[entrees.level_sensor.entrees[i].no - 1].validite = entrees.level_sensor.entrees[i].flag_validite;
sensors[entrees.level_sensor.entrees[i].no - 1].mode = entrees.level_sensor.entrees[i].mode;
sensors[entrees.level_sensor.entrees[i].no - 1].coeff_filtrage = 4;
}
}
for (i = 0; i < MAX_NOMBRE_ENTREES_LEVEL_SENSOR; i++) // Ecriture dans le buffer de la consigne pour chaque capteur :
{
buffer_cde->cde[buffer_cde->lg_cde ++] = sensors[i].validite;
buffer_cde->cde[buffer_cde->lg_cde ++] = sensors[i].mode;
buffer_cde->cde[buffer_cde->lg_cde ++] = sensors[i].coeff_filtrage;
//printf("Config level sensor # %i : validite=%i, mode=%i, coeff_filtrage=%i\n", (i+1), sensors[i].validite, sensors[i].mode, sensors[i].coeff_filtrage);
}
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au CM3+ de demander au Compagnon une nouvelle reconnaissance réseau OW
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_ow(void)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_OW;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au master de configurer les IBS connectés sur K-Bus
// Reçoit : Le numéro de carte dont les circuits sont configurés (>0, adresse de la carte sur K-Bus)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_batteries(uint8_t adresse_module)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
uint8_t type_batterie;
uint8_t temperature_coeff_filtrage;
uint8_t tension_coeff_filtrage;
uint8_t intensite_coeff_filtrage;
// Vérification du paramètre reçu :
if (adresse_module >= MAX_NOMBRE_MODULES) return(-1);
if (systeme.modules_config[adresse_module].flag_presence == FALSE) return(-1);
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SBS :
{
type_batterie = 0;
temperature_coeff_filtrage = 50; // Il est conseillé de filtrer fortement car les mesures par NTC sont assez fluctuantes...
tension_coeff_filtrage = 20;
intensite_coeff_filtrage = 10;
break;
}
default : return(-1);
}
// Préparation de la commande :
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_BATTERIES;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SBS :
{
buffer_cde->cde[buffer_cde->lg_cde ++] = type_batterie;
buffer_cde->cde[buffer_cde->lg_cde ++] = temperature_coeff_filtrage;
buffer_cde->cde[buffer_cde->lg_cde ++] = tension_coeff_filtrage;
buffer_cde->cde[buffer_cde->lg_cde ++] = intensite_coeff_filtrage;
#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Commande de config de l'IBS sur carte %i : type batterie=%i, coeff filtrage temperature=%i, coeff filtrage tension=%i, , coeff filtrage intensite=%i",
adresse_module, type_batterie, temperature_coeff_filtrage, tension_coeff_filtrage, intensite_coeff_filtrage);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
break;
}
default :;
}
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet à l'Appli de configurer un PGN NMEA2000
// Reçoit : Le rang du PGN dans l'annuaire 'nmea.annuaire[]'
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_config_pgn_nmea(uint16_t rang)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
// Vérification du paramètre reçu :
if (rang >= NMEA_MAX_NOMBRE_PGN) return (-1);
if (!nmea.annuaire[rang].flag_validite) return (-1);
if ((nmea.annuaire[rang].type < NMEA_PGN_TYPE_SYSTEM_SINGLE_FRAME) || (nmea.annuaire[rang].type > NMEA_PGN_TYPE_PROPRIETARY_FAST_PACKET)) return (-1);
// Préparation de la commande :
priorite = PRIORITE_CDE_C_BUS_FAIBLE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
//printf("Commande c_bus_down_commande_config_pgn_nmea avec PGN=%i, Actif=%i, Type=%i, Periode_mini=%i \n", nmea.annuaire[rang].pgn, nmea.annuaire[rang].actif, nmea.annuaire[rang].type, nmea.annuaire[rang].periode_mini);
// Code de la commande :
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CONFIG_PGN_NMEA;
// PGN :
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(nmea.annuaire[rang].pgn & 0x000000FF); // LLSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)((nmea.annuaire[rang].pgn >> 8) & 0x000000FF); // LSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)((nmea.annuaire[rang].pgn >> 16) & 0x000000FF); // MSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)((nmea.annuaire[rang].pgn >> 24) & 0x000000FF); // MMSB
// Actif :
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) nmea.annuaire[rang].actif;
// Type :
buffer_cde->cde[buffer_cde->lg_cde ++] = nmea.annuaire[rang].type;
// Periode_mini :
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(nmea.annuaire[rang].periode_mini & 0x00FF); // LSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(nmea.annuaire[rang].periode_mini >> 8); // MSB
// Priorité de la commande
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Fonction de demande de réinitialisation du Compagnon, donc du système.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_reset(void)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_RESET;
buffer_cde->cde[buffer_cde->lg_cde ++] = 'R';
buffer_cde->cde[buffer_cde->lg_cde ++] = 'E';
buffer_cde->cde[buffer_cde->lg_cde ++] = 'S';
buffer_cde->cde[buffer_cde->lg_cde ++] = 'E';
buffer_cde->cde[buffer_cde->lg_cde ++] = 'T';
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au master de mettre à jour la valeur de backlight à utiliser pour l'écran tactile. C'est en effet le CM3+ qui gère l'écran
// mais le pilotage de la ligne PWM commandant le backlight est délégué au Compagnon.
// Cette commande a été étendue en juillet 2021 aux LEDS afin de piloter leur luminosité indépendamment de l'écran.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_cde_backlight(float consigne_ecran, float consigne_leds)
{
uint8_t priorite;
uint16_t consigne;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CDE_BACKLIGHT;
consigne = (uint16_t) (consigne_ecran * 100);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(consigne & 0x00FF); // LSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(consigne >> 8); // MSB
consigne = (uint16_t) (consigne_leds * 100);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(consigne & 0x00FF); // LSB
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(consigne >> 8); // MSB
buffer_cde->priorite = priorite;
#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Commande backlight envoyée : consigne écran = %.2f, consigne leds = %.2f | consigne écran = %.2f, consigne leds = %.2f", consigne_ecran, consigne_leds, ecran.consigne_backlight, ecran.consigne_leds);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au master de commander un ou plusieurs circuits de puissance.
// Reçoit : Le numéro de carte dont les circuits sont commandés (>0, adresse de la carte sur K-Bus)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_cde_circuits(uint8_t adresse_module)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
uint16_t i;
struct {
uint8_t consigne;
uint8_t mode;
} tmp_circuits[MAX_NOMBRE_CIRCUITS];
for (i = 0; i < MAX_NOMBRE_CIRCUITS; i ++) // Valeurs par défaut
{
tmp_circuits[i].consigne = 0;
tmp_circuits[i].mode = SP8XX_MODE_CDE_CIRCUIT_AUTO;
}
// Vérification du paramètre reçu :
if (adresse_module >= MAX_NOMBRE_MODULES) return(-1);
if (systeme.modules_config[adresse_module].flag_presence == FALSE) return(-1);
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SP8DC :
{
for (i = 0; i < circuits.nb; i ++)
{
if (circuits.circuits[i].flag_validite == FALSE) continue; // On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
if (circuits.circuits[i].adresse_module != adresse_module) continue;
if (circuits.circuits[i].no_circuit >= SP8XX_NOMBRE_CIRCUITS) continue;
tmp_circuits[circuits.circuits[i].no_circuit].consigne = circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante;
// Attention : circuits.circuits[i].mode_cde est DIFFERENT de tmp_circuits[].mode !! Le premier est 0=On-Off, 1=On-Off soft, 2=Variable soft et 3=Cadencé. Le second est 0=TOR, 1=variable, 2= variable soft
// Il faut donc laisser la valeur envoyée via C-Bus à AUTO, ce qui permet d'utiliser le type de Circuit.
if (circuits.circuits[i].no_circuit_esclave >= 0) // Cas où le circuit a un esclave
{
tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].consigne = circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante; // Utile si le traitement de l'esclave a déjà été fait
circuits.circuits[circuits.circuits[i].no_circuit_esclave].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante = circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante; // Utile si le traitement de l'esclave n'a pas encore été fait
}
}
break;
}
case TYPE_CARTE_SP4AC :
{
for (i = 0; i < circuits.nb; i ++)
{
if (circuits.circuits[i].flag_validite == FALSE) continue; // On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
if (circuits.circuits[i].adresse_module != adresse_module) continue;
if (circuits.circuits[i].no_circuit >= SP4AC_NOMBRE_CIRCUITS) continue;
tmp_circuits[circuits.circuits[i].no_circuit].consigne = circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante;
}
break;
}
default : return(-1);
}
// Préparation de la commande :
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CDE_CIRCUITS;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SP8DC :
{
for (i = 0; i < SP8XX_NOMBRE_CIRCUITS; i ++) // <consigne 1><mode 1>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].consigne;
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].mode;
#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Commande des circuits sur carte %i, circuit %i : consigne=%i, mode=%i", adresse_module, (i+1), tmp_circuits[i].consigne, tmp_circuits[i].mode);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
}
break;
}
case TYPE_CARTE_SP4AC :
{
for (i = 0; i < SP4AC_NOMBRE_CIRCUITS; i ++) // <consigne 1>
{
buffer_cde->cde[buffer_cde->lg_cde ++] = tmp_circuits[i].consigne;
#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Commande des circuits sur carte %i, circuit %i : consigne=%i", adresse_module, (i+1), tmp_circuits[i].consigne);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
}
break;
}
default :;
}
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au CM3+ de commander le Compagnon ou une carte sur le K-Bus
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_cde_carte(uint8_t adresse_module, uint8_t cde, uint8_t consigne)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
// Vérification des paramètres :
if (adresse_module >= MAX_NOMBRE_MODULES) return(-1);
switch(cde)
{
case C_BUS_COMMANDE_CDE_CARTE_LOCALISATION : // Localisation
{
if ((consigne != 0) && (consigne != 1)) return(-1);
break;
}
case C_BUS_COMMANDE_CDE_CARTE_ETAT_SYSTEME : // Info sur l'état du système :
{
if (consigne > C_BUS_COMMANDE_CDE_CARTE_MAX_CONSIGNE) return (-1);
break;
}
default : return(-1);
}
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CDE_CARTE;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
buffer_cde->cde[buffer_cde->lg_cde ++] = cde;
buffer_cde->cde[buffer_cde->lg_cde ++] = consigne;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Fonction qui permet au CM3+ lire la date et l'heure du Compagnon.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_lecture_date_heure(void)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_FAIBLE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_LECTURE_DATE_HEURE;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Fonction qui permet au CM3+ lire les paramètres propres au Compagnon ou à une carte sur le K-Bus
// Reçoit : Le numéro de carte dont les IDs sont demandés (0=Compagnon, >0=adresse de la carte sur K-Bus)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_lecture_id_carte(uint8_t adresse_module)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
if (adresse_module != 0) // La lecture de l'ID du Compagnon est toujours possible
{
if (adresse_module >= MAX_NOMBRE_MODULES) return(-1);
if (systeme.modules_physiques[adresse_module].flag_presence == FALSE) return(-1); // Pour les autres cartes, il faut qu'elles aient préalablment été détectées (par une commande annuaire par exemple)
}
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_LECTURE_ID_CARTE;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Cette commande permet au CM3+ de demander au Compagnon la liste des cartes présentes dans le système en publiant leur adresse réseau et leur adresse MAC (y compris celle du Compagnon)
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_annuaire_k_bus(void)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_FAIBLE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_ANNUAIRE_K_BUS;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Permet au CM3+ de charger le code de l'application dans le Compagnon ou dans une carte sur K-Bus
// Reçoit : Le mode de la commande à envoyer (0: effacement de la flash, 1: chargement du bloc suivant, 2: vérification CRC, 3: activation de la MAJ)
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_chargement_code(uint8_t mode, uint8_t adresse_module)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
FILE * ptr_fic;
uint16_t i;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
if (mode > CHARGEMENT_CODE_MODE_VALIDATION_VERSION) return (-1); // Mode invalide...
chargement_code.flag_reponse = FALSE; // Permettra d'activer ce flag à la réception et d'informer ainsi le séquenceur d'upload qui gère tout l'échange.
priorite = PRIORITE_CDE_C_BUS_FAIBLE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_CHARGEMENT_CODE;
buffer_cde->cde[buffer_cde->lg_cde ++] = mode;
buffer_cde->cde[buffer_cde->lg_cde ++] = adresse_module;
switch(mode)
{
//==========================================================================
// Mode 0 : Effacement de la flash
case CHARGEMENT_CODE_MODE_EFFACEMENT_FLASH:
{
break;
}
//==========================================================================
// Mode 1 : Chargement d'un bloc de data
case CHARGEMENT_CODE_MODE_CHARGEMENT_BLOC:
{
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)chargement_code.no_bloc;
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(chargement_code.no_bloc >> 8);
if ((chargement_code.nb_transmis + MAX_TAILLE_BLOC_DATA_CHARGEMENT_CODE) <= chargement_code.taille_fichier) chargement_code.taille_bloc = MAX_TAILLE_BLOC_DATA_CHARGEMENT_CODE;
else chargement_code.taille_bloc = (uint16_t) (chargement_code.taille_fichier - chargement_code.nb_transmis);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)chargement_code.taille_bloc;
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)(chargement_code.taille_bloc >> 8);
sprintf(tmp, "%s/%s", REPERTOIRE_VERSIONS_CURRENT, chargement_code.nom_fichier[chargement_code.adresse_module]);
ptr_fic = fopen(tmp, "rb"); // Ouverture du fichier en "lecture"...
if (ptr_fic != NULL)
{
fseek (ptr_fic, chargement_code.nb_transmis, SEEK_SET); // Place le curseur à la prochaine position du fichier à transmettre
for (i = 0; i < chargement_code.taille_bloc; i ++) buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t)fgetc(ptr_fic);
}
else
{
sprintf(tmp, "L'ouverture du fichier à charger [%s/%s] n'est pas possible. Le chargement du code est abandonné...", REPERTOIRE_VERSIONS_CURRENT, chargement_code.nom_fichier[chargement_code.adresse_module]);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
}
fclose(ptr_fic); // Fermeture du fichier
chargement_code.nb_transmis += chargement_code.taille_bloc;
break;
}
//==========================================================================
// Mode 2 : Vérification CRC
case CHARGEMENT_CODE_MODE_CHECK_CRC:
{
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) chargement_code.crc_fichier;
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (chargement_code.crc_fichier >> 8);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (chargement_code.crc_fichier >> 16);
buffer_cde->cde[buffer_cde->lg_cde ++] = (uint8_t) (chargement_code.crc_fichier >> 24);
break;
}
//==========================================================================
// Mode 3 : Validation de la nouvelle version
case CHARGEMENT_CODE_MODE_VALIDATION_VERSION:
{
break;
}
//==========================================================================
default:
{
sprintf(tmp, "Commande 'c_bus_down_commande_chargement_code()' appelée avec un mode inconnu (%i)", mode);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
break;
}
}
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au CM3+ de demander au Compagnon l'annuaire des devices présents sur son bus OW
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si la commande n'a pas pu être générée et stockée dans le buffer de commandes.
//==================================================================================================================================================================
int8_t c_bus_down_commande_annuaire_ow(void)
{
uint8_t priorite;
struct Struct_commande_c_bus *buffer_cde;
priorite = PRIORITE_CDE_C_BUS_HAUTE;
if (c_bus_next_write_buffer_cdes(priorite) != -1)
{
buffer_cde = &c_bus.down.buffer_cdes[c_bus.down.ptr_fin_buffer_cdes]; // L'utilisation du pointeur de struct simplifie l'écriture ensuite...
buffer_cde->lg_cde = 0;
buffer_cde->cde[buffer_cde->lg_cde ++] = C_BUS_DOWN_COMMANDE_ANNUAIRE_OW;
buffer_cde->priorite = priorite;
return(0);
}
else return (-1);
}
//***************************************************************************************************************************************************************
//***************************************************************************************************************************************************************
// DOWN - Réponses
//***************************************************************************************************************************************************************
//***************************************************************************************************************************************************************
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_config_date_heure(void)
{
uint16_t ptr_reponse;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
//-------------------------------------------------------------
// Analyse de la réponse ;
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != 0) return(-1); // Code d'erreur qui doit être à 0
ptr_reponse += 6; // <jour><mois><année> <heures><minutes><secondes>
if (ptr_reponse != c_bus.down.reponse.lg_reponse)
{
sprintf(tmp, "La longueur de réponse reçue sur C-Bus down n'est pas conforme au décodage réalisé (décodés = %i et reçus = %i)", ptr_reponse, c_bus.down.reponse.lg_reponse);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
return(0);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_cde_backlight(void)
{
uint16_t ptr_reponse;
uint16_t consigne_backlight;
uint16_t consigne_leds;
//-------------------------------------------------------------
// Analyse de la réponse ;
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != 0) return(-1); // Code d'erreur qui doit être à 0
consigne_backlight = (uint16_t) c_bus.down.reponse.reponse[ptr_reponse ++]; // Relecture de la valeur de consigne
consigne_backlight |= (((uint16_t) c_bus.down.reponse.reponse[ptr_reponse ++]) << 8);
consigne_leds = (uint16_t) c_bus.down.reponse.reponse[ptr_reponse ++]; // Relecture de la valeur de consigne
consigne_leds |= (((uint16_t) c_bus.down.reponse.reponse[ptr_reponse ++]) << 8);
// NB : la vérification ci-dessous ne fonctionne pas bien quand la consigne de LEDs et de Backlight sont modifiées simultanément.
// En effet, on met à jour la consigne_leds puis, juste après, la consigne_backlight.
// La première maj génére une commande portant uniquement la nouvelle valeur de leds (et donc l'ancienne de backlight). La réponse revient donc avec l'ancienne valeur de backlight qui
// est comparée avec la valeur en cours de backlight qui, elle, est la nouvelle => erreur => répétition. Au final, la commande générée par le changement de backlight finit par être envoyée et tout est en ordre.
// Pour éviter ces répétitions inutile, on n'émet pas d'erreur en cas de retour non identique. Mais on garde les messages d'erreur pour ne pas oublier...
/* char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
if (systeme.veille == SYSTEME_VEILLE_AUCUNE) // On ne fait le test de relecture de la valeur reçue que si on n'est pas en veille (sinon les valeurs demandées peuvent différer de la consigne)
{
if (((uint16_t)(ecran.consigne_backlight * 100)) != consigne_backlight)
{
sprintf(tmp, "La valeur de backlight reçue du Compagnon est différente de la consigne envoyée [valeur envoyée = %.2f et valeur reçue = %.2f]", ecran.consigne_backlight, (float)consigne_backlight / 100);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
// return(-1);
return(0);
}
if (((uint16_t)(ecran.consigne_leds * 100)) != consigne_leds)
{
sprintf(tmp, "La valeur de consigne LEDs reçue du Compagnon est différente de la consigne envoyée [valeur envoyée = %.2f et valeur reçue = %.2f]", ecran.consigne_leds, (float)consigne_leds / 100);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
// return(-1);
return(0);
}
}
*/
if (ptr_reponse != c_bus.down.reponse.lg_reponse) return(-1); // Cas où le nombre d'octets reçus n'est pas correct...
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
return(0);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_lecture_date_heure(void)
{
uint16_t ptr_reponse;
struct Struct_date date;
struct Struct_heure heure;
//-------------------------------------------------------------
// Analyse de la réponse ;
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != C_BUS_ERREUR_AUCUNE) return(-1); // Code d'erreur qui doit être à 0
date.jour = c_bus.down.reponse.reponse[ptr_reponse ++]; // Jour
date.mois = c_bus.down.reponse.reponse[ptr_reponse ++]; // Mois
date.annee = c_bus.down.reponse.reponse[ptr_reponse ++]; // Année
heure.heures = c_bus.down.reponse.reponse[ptr_reponse ++]; // Heures
heure.minutes = c_bus.down.reponse.reponse[ptr_reponse ++]; // Minutes
heure.secondes = c_bus.down.reponse.reponse[ptr_reponse ++]; // Secondes
if (ptr_reponse != c_bus.down.reponse.lg_reponse) return (-1); // Cas où on a reçu trop d'octets...
if ((date.jour == 0) || (date.jour > 31)) return(-1); // On ne contrôle pas les jours vs mois/années bisextiles car ce sera fait par la fonction de mise à l'heure
if ((date.mois == 0) || (date.mois > 12)) return(-1);
if (date.annee < 120) return(-1); // La valeur reçue correspond au nombres d'années depuis 1900 donc on suppose qu'on est au moins en 2020...
if (heure.heures > 23) return(-1);
if (heure.minutes > 59) return(-1);
if (heure.secondes > 59) return(-1);
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
date.annee += 1900;
set_date_heure(date, heure); // Mise à jour de la date/heure système à partir de l'heure reçue du Compagnon qui, elle, est sauvegardée (toujours en UTC !)
//#ifdef __DEBUG_COMMANDES_C_BUS
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Réception de la date-heure du Compagnon effectuée avec succès à %02i/%02i/%04i %02i:%02i:%02i", date.jour, date.mois, date.annee, heure.heures, heure.minutes, heure.secondes);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
//#endif
return(0);
}
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_lecture_id_carte(void)
{
uint16_t ptr_reponse;
uint8_t i;
uint8_t adresse_module;
uint8_t type_carte;
uint8_t version_hard;
uint8_t unique_id[MAX_TAILLE_UNIQUE_ID];
uint16_t flash_size;
uint16_t package;
uint8_t lg_type_soft;
char type_soft[MAX_TAILLE_TYPE_SOFT];
uint8_t lg_version_soft;
char version_soft[MAX_TAILLE_VERSION_SOFT];
uint32_t crc;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
//-------------------------------------------------------------
// Analyse de la réponse :
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != 0) return(-1); // Code d'erreur qui doit être à 0
adresse_module = c_bus.down.reponse.reponse[ptr_reponse ++]; // Numéro de carte
if (adresse_module >= MAX_NOMBRE_MODULES)
{
sprintf(tmp, "Le numéro de carte reçu sur C-Bus dans la réponse à la commande LECTURE_ID_CARTE [valeur = %i] n'est pas valide [devrait être entre 0 et %i]", adresse_module, MAX_NOMBRE_MODULES);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
type_carte = c_bus.down.reponse.reponse[ptr_reponse ++]; // Type de carte
switch(type_carte)
{
case TYPE_CARTE_SHIPBASE :
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SBS :
case TYPE_CARTE_SP4AC :
case TYPE_CARTE_SP8DC :
break;
default :
{
sprintf(tmp, "Le TYPE_CARTE reçu sur C-Bus dans la réponse à la commande LECTURE_ID_CARTE [valeur = %i] n'est pas valide", type_carte);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
}
version_hard = c_bus.down.reponse.reponse[ptr_reponse ++]; // Version hard de la carte
for (i = 0; i < MAX_TAILLE_UNIQUE_ID; i ++) unique_id[i] = c_bus.down.reponse.reponse[ptr_reponse ++]; // Unique ID
flash_size = (uint16_t) c_bus.down.reponse.reponse[ptr_reponse ++]; // Taille de la flash (LSB)
flash_size |= (((uint16_t) c_bus.down.reponse.reponse[ptr_reponse ++]) << 8); // MSB
package = c_bus.down.reponse.reponse[ptr_reponse ++]; // Boitier du µC
lg_type_soft = c_bus.down.reponse.reponse[ptr_reponse ++]; // Longueur de la chaine 'Type soft'
if (lg_type_soft >= MAX_TAILLE_TYPE_SOFT)
{
sprintf(tmp, "La longueur de Type Soft reçue sur C-Bus dans la réponse à la commande LECTURE_ID_CARTE est trop importante (reçu = %i, maxi = %i)", lg_type_soft, MAX_TAILLE_TYPE_SOFT);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
for (i = 0; i < lg_type_soft; i ++) type_soft[i] = c_bus.down.reponse.reponse[ptr_reponse ++]; // Type soft
lg_version_soft = c_bus.down.reponse.reponse[ptr_reponse ++]; // Longueur de la chaine 'Version soft'
if (lg_version_soft >= MAX_TAILLE_VERSION_SOFT)
{
sprintf(tmp, "La longueur de Version Soft reçue sur C-Bus dans la réponse à la commande LECTURE_ID_CARTE est trop importante (reçu = %i, maxi = %i)", lg_version_soft, MAX_TAILLE_VERSION_SOFT);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
for (i = 0; i < lg_version_soft; i ++) version_soft[i] = c_bus.down.reponse.reponse[ptr_reponse ++]; // Version soft
crc = (uint32_t) c_bus.down.reponse.reponse[ptr_reponse ++]; // CRC (LSB)
crc |= (((uint32_t) c_bus.down.reponse.reponse[ptr_reponse ++]) << 8);
crc |= (((uint32_t) c_bus.down.reponse.reponse[ptr_reponse ++]) << 16);
crc |= (((uint32_t) c_bus.down.reponse.reponse[ptr_reponse ++]) << 24); // MSB
if (ptr_reponse != c_bus.down.reponse.lg_reponse)
{
sprintf(tmp, "La longueur de réponse reçue sur C-Bus down n'est pas conforme au décodage réalisé (décodés = %i et reçus = %i)", ptr_reponse, c_bus.down.reponse.lg_reponse);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
// systeme.modules_physiques[adresse_module].flag_validite = TRUE; // On considère que si on a reçu une réponse valide à une commande de lecture ID, la carte est valide.
systeme.modules_physiques[adresse_module].type = type_carte;
systeme.modules_physiques[adresse_module].hardware_version = version_hard;
for (i = 0; i < MAX_TAILLE_UNIQUE_ID; i ++) systeme.modules_physiques[adresse_module].hardware_unique_id[i] = unique_id[i];
systeme.modules_physiques[adresse_module].hardware_flash_size = flash_size;
systeme.modules_physiques[adresse_module].hardware_package = package;
for (i = 0; i < lg_type_soft; i ++) systeme.modules_physiques[adresse_module].soft_type[i] = type_soft[i];
for (i = 0; i < lg_version_soft; i ++) systeme.modules_physiques[adresse_module].soft_version[i] = version_soft[i];
systeme.modules_physiques[adresse_module].soft_crc = crc;
write(config_serial1.filestream, "AA", 1);
#ifdef __DEBUG_COMMANDES_C_BUS
sprintf(tmp, "ID Carte reçu : \n\t no carte \t= %i \n\t type carte \t= %i \n\t version hard \t= %i \n\t flash size \t= %iko \n\t package \t= %i \n\t unique ID \t= %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n\t type soft \t= %s \n\t version soft \t= %s \n\t CRC \t\t= %08X",
adresse_module, systeme.modules_physiques[adresse_module].type, systeme.modules_physiques[adresse_module].hardware_version,
systeme.modules_physiques[adresse_module].hardware_flash_size, systeme.modules_physiques[adresse_module].hardware_package,
systeme.modules_physiques[adresse_module].hardware_unique_id[0], systeme.modules_physiques[adresse_module].hardware_unique_id[1], systeme.modules_physiques[adresse_module].hardware_unique_id[2],
systeme.modules_physiques[adresse_module].hardware_unique_id[3], systeme.modules_physiques[adresse_module].hardware_unique_id[4], systeme.modules_physiques[adresse_module].hardware_unique_id[5],
systeme.modules_physiques[adresse_module].hardware_unique_id[6], systeme.modules_physiques[adresse_module].hardware_unique_id[7], systeme.modules_physiques[adresse_module].hardware_unique_id[8],
systeme.modules_physiques[adresse_module].hardware_unique_id[9], systeme.modules_physiques[adresse_module].hardware_unique_id[10], systeme.modules_physiques[adresse_module].hardware_unique_id[11],
systeme.modules_physiques[adresse_module].soft_type, systeme.modules_physiques[adresse_module].soft_version, systeme.modules_physiques[adresse_module].soft_crc);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
return(0);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_annuaire_k_bus(void)
{
uint16_t ptr_reponse;
uint16_t i, j;
uint8_t adresse_module;
uint8_t r_term;
uint8_t no_champ;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
struct {
uint8_t flag_presence;
uint8_t adresse_bus;
uint8_t adresse_mac[TAILLE_ADRESSE_MAC];
uint8_t flag_r_term;
} cartes[MAX_NOMBRE_MODULES];
#define C_BUS_DOWN_REPONSE_ANNUAIRE_K_BUS_SANS_R_TERM 0 // Ancienne version de commande, sans le champ R_Term
#define C_BUS_DOWN_REPONSE_ANNUAIRE_K_BUS_AVEC_R_TERM 1 // Version de commande avec R_Term (depuis V2.0.0).
for (i = 0; i < MAX_NOMBRE_MODULES; i ++)
{
cartes[i].flag_presence = FALSE;
cartes[i].flag_r_term = FALSE;
}
//-------------------------------------------------------------
// Analyse de la réponse :
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != 0) return(-1); // Code d'erreur qui doit être à 0
// Détermination du format de réponse pour s'adapter
if ((c_bus.down.reponse.lg_reponse - 10) % 8 == 0) systeme.flag_r_term_etat_carte = false; // Cas pour les Versions >= 2.0.0
else systeme.flag_r_term_etat_carte = true; // Compatibilité avec les versions < 2.0.0
#ifdef __DEBUG_COMMANDES_C_BUS
sprintf(tmp, "Réponse Annuaire reçue au format %s", systeme.flag_r_term_etat_carte ? "SANS R_Term" : "AVEC R_Term");
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
no_champ = 0;
adresse_module = 0;
while (ptr_reponse < c_bus.down.reponse.lg_reponse)
{
switch(no_champ)
{
case 0: // N° de carte :
{
adresse_module = c_bus.down.reponse.reponse[ptr_reponse ++];
if (adresse_module >= MAX_NOMBRE_MODULES)
{
sprintf(tmp, "Le numéro de carte reçu est trop élevé (reçu = %i et maxi = %i)", adresse_module, MAX_NOMBRE_MODULES);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
else cartes[adresse_module].flag_presence = TRUE;
no_champ ++;
break;
}
case 1: // Résistance de terminaison :
{
// Si la réponse est de l'ancien format, on force l'avancement d'un octet de l'analyse de la réponse pour sauter R_Term sans changer l'algo :
if (systeme.flag_r_term_etat_carte)
{
no_champ ++;
break;
}
r_term = c_bus.down.reponse.reponse[ptr_reponse ++];
if ((r_term != 0) && (r_term != 1))
{
sprintf(tmp, "L'état de Résistance de Terminaison de la carte %i n'est pas valide (reçu = %i)", adresse_module, r_term);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
else cartes[adresse_module].flag_r_term = r_term;
no_champ ++;
break;
}
case 2: // Adresse MAC #1 à #5 :
case 3:
case 4:
case 5:
case 6:
{
cartes[adresse_module].adresse_mac[no_champ - 2] = c_bus.down.reponse.reponse[ptr_reponse ++];
no_champ ++;
break;
}
case 7: // Adresse MAC #6
{
cartes[adresse_module].adresse_mac[no_champ - 2] = c_bus.down.reponse.reponse[ptr_reponse ++];
no_champ = 0;
break;
}
}
}
if (no_champ != 0) // Si la trame est conforme, on doit arriver au bout en pointant sur un no_champ = 0
{
sprintf(tmp, "La longueur de réponse reçue sur C-Bus down n'est pas conforme au décodage réalisé (décodés = %i et no_champ = %i)", ptr_reponse, no_champ);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
for (i = 0; i < MAX_NOMBRE_MODULES; i ++)
{
systeme.modules_physiques[i].flag_presence = cartes[i].flag_presence; // On met tous les flags de présence à jour (TRUE ou FALSE). NB : La mise à FALSE est normalement déjà faite dans 'bdd_init()', même en cas de reconfig
if (cartes[i].flag_presence == FALSE) continue; // Si le module n'est pas présent, il est inutile de stocker les infos du module
for (j = 0; j < TAILLE_ADRESSE_MAC; j ++) systeme.modules_physiques[i].adresse_mac[j] = cartes[i].adresse_mac[j];
systeme.modules_physiques[i].resistance_terminaison = cartes[i].flag_r_term; // NB : dans le cas d'un retour C_BUS_DOWN_REPONSE_ANNUAIRE_K_BUS_SANS_R_TERM, toutes les valeurs seront à FALSE tant que le Compagnon n'aura pas été mis à jour...
}
#ifdef __DEBUG_COMMANDES_C_BUS
char chaine[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
char chaine_adresse_mac[30];
sprintf(tmp, "Réponse Annuaire reçue de la part du Compagnon : ");
for (i = 0; i < MAX_NOMBRE_MODULES; i ++)
{
if (systeme.modules_physiques[i].flag_presence == FALSE) continue;
sprintf(chaine, "\n\tCarte à l'adresse %i\t: adresse MAC = %s, R_term = %s", i, conversion_adresse_mac_chaine(systeme.modules_physiques[i].adresse_mac, chaine_adresse_mac, ':'), (systeme.modules_physiques[i].resistance_terminaison ? "OUI" : "Non"));
strcat(tmp, chaine);
}
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
return(0);
}
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_chargement_code(void)
{
uint16_t ptr_reponse;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
uint8_t ret;
//-------------------------------------------------------------
// Analyse de la réponse :
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
ret = c_bus.down.reponse.reponse[ptr_reponse ++];
chargement_code.status_reponse = ret;
if (ret == 0)
{
chargement_code.flag_reponse = TRUE;
return(0);
}
else
{
sprintf(tmp, "Le retour de commande de chargement de bloc indique une erreur (%i). L'info d'erreur est descendue au protocole afin qu'il répète la commande", ret);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1); // Dans ce cas, le protocole va répéter la commande autantd e fois qu'il en a le droit... Si aucun de ces essais n'est concluant, il y aura déclenchement du type-out vers 'chargement_code'
}
}
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_annuaire_ow(void)
{
uint16_t ptr_reponse;
uint16_t i;
uint8_t nb_devices, nb_devices_recu;
uint8_t no_champ;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
struct {
uint8_t rom_code[TAILLE_ROM_CODE_OW];
} devices[MAX_NOMBRE_DEVICES_OW];
//-------------------------------------------------------------
// Analyse de la réponse :
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != 0) return(-1); // Code d'erreur qui doit être à 0
nb_devices_recu = c_bus.down.reponse.reponse[ptr_reponse ++]; // Nombre de devices
// Cas d'une erreur matérielle sur le bus OW :
if (nb_devices_recu == 0xFF) // Cas d'une anomalie sur le bus OW qui empêche de faire la reconnaissance réseau
{
entrees.ow.defaut_bus = OW_DEFAUT_BUS_COURT_CIRCUIT;
enregistrement_annuaire_ow(0xFF); // L'appel de la fonction avec FFh en paramètre va permettre de mettre à jour TB_One_wire avec l'info de défaut du bus
return(0); // Fin sans erreur (au niveau protocole). Il est inutile d'aller plus loin dans le traitement.
}
// Cas normal :
if (nb_devices_recu > MAX_NOMBRE_DEVICES_OW) return(-1);
no_champ = 0;
nb_devices = 0;
while (ptr_reponse < c_bus.down.reponse.lg_reponse)
{
switch(no_champ)
{
case 0: // N° de device
{
i = c_bus.down.reponse.reponse[ptr_reponse ++]; // Ce n° n'est pas utilisé en pratique. Les valeurs reçues sont stockées par ordre d'arrivée dans 'devices[]'.
// Check du nombre de devices reçus :
if (nb_devices >= MAX_NOMBRE_DEVICES_OW)
{
sprintf(tmp, "Le nombre de devices reçu est trop élevé (maxi = %i). La commande est rejetée", MAX_NOMBRE_ENTREES_OW);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
entrees.ow.defaut_bus = OW_DEFAUT_BUS_TROP_DEVICES;
enregistrement_annuaire_ow(0xFF); // L'appel de la fonction avec FFh en paramètre va permettre de mettre à jour TB_One_wire avec l'info de défaut du bus
return(-1);
}
no_champ ++;
break;
}
case 1: // ROM Code #1 à #7 :
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
{
devices[nb_devices].rom_code[no_champ - 1] = c_bus.down.reponse.reponse[ptr_reponse ++];
no_champ ++;
break;
}
case 8: // ROM Code #8
{
devices[nb_devices].rom_code[no_champ - 1] = c_bus.down.reponse.reponse[ptr_reponse ++];
no_champ = 0;
nb_devices ++;
break;
}
}
}
if (no_champ != 0) // Si la trame est conforme, on doit arriver au bout en pointant sur un no_champ = 0
{
sprintf(tmp, "La longueur de réponse reçue sur C-Bus down n'est pas conforme au décodage réalisé (décodés = %i et no_champ = %i)", ptr_reponse, no_champ);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
if (nb_devices != nb_devices_recu) // Si la trame est conforme, la valeur de nb_devices reçue doit être égale au nombre réellement reçus
{
sprintf(tmp, "Le nombre de devices reçus dans l'annuaire ne correspond pas au nombre indiqué en début de trame (décodés = %i et nombre reçu = %i)", nb_devices, nb_devices_recu);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
return(-1);
}
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
for (i = 0; i < nb_devices; i ++)
{
conversion_rom_code_chaine(devices[i].rom_code, entrees.ow.devices[i].rom_code, ':');
}
entrees.ow.defaut_bus = OW_DEFAUT_BUS_AUCUN; // Si on a reçu des devices, il ne peut pas y avoir de défat bus...
enregistrement_annuaire_ow(nb_devices);
#ifdef __DEBUG_COMMANDES_C_BUS
char chaine[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
sprintf(tmp, "Réponse Annuaire OW reçue de la part du Compagnon : ");
for (i = 0; i < nb_devices; i ++)
{
sprintf(chaine, "\n\tDevice OW n° %i avec le ROM Code = %s ", i, entrees.ow.devices[i].rom_code);
strcat(tmp, chaine);
}
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
return(0);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Est appelé après réception d'une réponse à une commande et détection du code commande valide en premier caractère.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_reponse_generique(void)
{
uint16_t ptr_reponse;
//-------------------------------------------------------------
// Analyse de la réponse ;
ptr_reponse = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
if (c_bus.down.reponse.reponse[ptr_reponse ++] != 0) return(-1); // Code d'erreur qui doit être à 0
if (ptr_reponse != c_bus.down.reponse.lg_reponse) return (-1); // Cas où on a reçu trop d'octets...
//-------------------------------------------------------------
// Traitement de la réponse si aucune erreur n'a été détectée :
return(0);
}
//==================================================================================================================================================================
// Fonction : Appelée lorsqu'une réponse a été reçue, pour déterminer le code de la commande commande concernée.
// Reçoit : Rien
// Renvoit : 0 si aucune erreur, -1 si l'analyse de la réponse a détecté une ou pluisieurs erreurs.
//==================================================================================================================================================================
int8_t c_bus_down_recherche_reponse(void)
{
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
switch(c_bus.down.reponse.reponse[0])
{
//---------------------------------------------
case C_BUS_DOWN_COMMANDE_CONFIG_DATE_HEURE : { return (c_bus_down_reponse_config_date_heure()); break; }
case C_BUS_DOWN_COMMANDE_CONFIG_CARTE : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CONFIG_CIRCUITS : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CONFIG_LEVEL_SENSORS : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CONFIG_OW : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CONFIG_BATTERIES : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CONFIG_PGN_NMEA : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_RESET : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CDE_BACKLIGHT : { return (c_bus_down_reponse_cde_backlight()); break; }
case C_BUS_DOWN_COMMANDE_CDE_CIRCUITS : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_CDE_CARTE : { return (c_bus_down_reponse_generique()); break; }
case C_BUS_DOWN_COMMANDE_LECTURE_DATE_HEURE : { return (c_bus_down_reponse_lecture_date_heure()); break; }
case C_BUS_DOWN_COMMANDE_LECTURE_ID_CARTE : { return (c_bus_down_reponse_lecture_id_carte()); break; }
case C_BUS_DOWN_COMMANDE_ANNUAIRE_K_BUS : { return (c_bus_down_reponse_annuaire_k_bus()); break; }
case C_BUS_DOWN_COMMANDE_CHARGEMENT_CODE : { return (c_bus_down_reponse_chargement_code()); break; }
case C_BUS_DOWN_COMMANDE_ANNUAIRE_OW : { return (c_bus_down_reponse_annuaire_ow()); break; }
default :
{
sprintf(tmp, "La réponse reçue sur C-Bus Down comprend un code commande inconnu [%i]", c_bus.down.reponse.reponse[0]);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
}
}
return (-1);
}
//***************************************************************************************************************************************************************
//***************************************************************************************************************************************************************
// UP
//***************************************************************************************************************************************************************
//***************************************************************************************************************************************************************
//==================================================================================================================================================================
// Fonction : Cette commande permet au Compagnon de remonter son état ou celui dune carte extension au CM3+
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_carte(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t i;
uint16_t ptr_cde;
uint8_t lsb, msb, lmsb, mlsb;
uint8_t adresse_module;
uint8_t alim_etat = 0;
uint8_t alim_cde = 0;
float in_v = 0; // Utilisé aussi pour alim_valeur ; on évite de créer deux variables pour la même valeur.
float in_i = 0;
float masses_i = 0; // SDIR #138
float usb_i = 0;
float temp = 0;
float hum = 0;
float pat = 0;
float acc_x = 0;
float acc_y = 0;
float acc_z = 0;
uint8_t orig;
uint8_t mode_test = 0; // sinon warning à la compilation
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
adresse_module = commande->cde[ptr_cde ++]; // <numéro de carte>
// if ((adresse_module >= MAX_NOMBRE_MODULES) || (systeme.modules_config[adresse_module].flag_validite == FALSE))
if (adresse_module >= MAX_NOMBRE_MODULES) // Le fait de recevoir un état carte d'un module non valide n'est pas une erreur en soit (le module peut être présent mais pas utilisé par la config)
{
sprintf(tmp, "Erreur : n° de carte = %i (Min = 0 et Max = %i ou carte dévalidée)", adresse_module, MAX_NOMBRE_MODULES);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
erreur = C_BUS_ERREUR_NO_CARTE;
break;
}
if (!systeme.modules_config[adresse_module].flag_validite) break; // Dans ce cas, on ne déclenche pas une erreur mais il est inutile d'effectuer le traitement (d'autant qu'on ne connait pas la nature du module donc on arrivera probablement à une erreur de format...)
if (adresse_module == 0) // Compagnon : <tension alim> <intensité alim><intensité USB><température> <pression><humidité><source reset><état nmea>
{
lsb = 0; // Permet d'éviter un warning que je ne comprends pas...
//-------------------------------------------------------------
// Etat de l'alimentation :
//-------------------------------------------------------------
alim_etat = commande->cde[ptr_cde ++];
//-------------------------------------------------------------
// Tension entrée ShipBase :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
in_v = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mV à V
//-------------------------------------------------------------
// Courant ShipBase :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
in_i = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mA à A
//-------------------------------------------------------------
// Courant USB :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
usb_i = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mA à A
if (usb_i < 0.010) usb_i = 0; // Plancher sur le courant dans USB pour éviter de trainer des valeurs très faibles non significatives.
//-------------------------------------------------------------
// Température :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
temp = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 100; // La valeur reçue est en centièmes de °C
if ((temp <= TEMPERATURE_VALEUR_MINI) || (temp >= TEMPERATURE_VALEUR_MAXI)) // Test de validité
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Pression :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
lmsb = commande->cde[ptr_cde ++];
mlsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
pat = ((float)((((uint32_t) msb) << 24) | (((uint32_t) mlsb) << 16) | (((uint32_t) lmsb) << 8) | ((uint32_t) lsb))) / 100; // La valeur reçue est en Pa
if ((pat < PRESSION_ATM_VALEUR_MINI) || (pat > PRESSION_ATM_VALEUR_MAXI)) // Test de validité
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Humidité :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
hum = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 100; // La valeur reçue est en centièmes de %
if ((hum < HUMIDITE_VALEUR_MINI) || (hum > HUMIDITE_VALEUR_MAXI)) // Test de validité
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Accélération X :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
acc_x = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 1000; // La valeur reçue est en mg
if ((acc_x <= ACCELERATION_VALEUR_MINI) || (acc_x >= ACCELERATION_VALEUR_MAXI)) // Test de validité
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Accélération Y :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
acc_y = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 1000; // La valeur reçue est en mg
if ((acc_y <= ACCELERATION_VALEUR_MINI) || (acc_y >= ACCELERATION_VALEUR_MAXI)) // Test de validité
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Accélération Z :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
acc_z = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 1000; // La valeur reçue est en mg
if ((acc_z <= ACCELERATION_VALEUR_MINI) || (acc_z >= ACCELERATION_VALEUR_MAXI)) // Test de validité
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Origine de la commande :
//-------------------------------------------------------------
orig = commande->cde[ptr_cde ++];
//etat_nmea = commande->cde[ptr_cde ++];
// Debug :
// printf("Etat du Compagnon reçu : Etat alim = %i, Tension = %6.3f V, Courant=%6.3f A, Courant USB=%5.3f A, Température = %5.2f °C, Humidité=%5.2f %%RH, Pression=%7.2f hPa, Origine reset = %i \n", alim_etat, in_v, in_i, usb_i, temp, hum, pat, orig);
}
else // Autre carte : <code commande><numéro de carte><tension alim> <température><mode test><source reset>
{
lsb = 0; // Permet d'éviter un warning que je ne comprends pas...
// Paramètres spécifiques à certaines cartes :
switch(systeme.modules_config[adresse_module].type)
{
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP812 :
{
//-------------------------------------------------------------
// Etat de l'alimentation :
//-------------------------------------------------------------
alim_etat = commande->cde[ptr_cde ++];
//-------------------------------------------------------------
// Tension d'alimentation :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
in_v = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mV à V
//-------------------------------------------------------------
// Température :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
temp = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 100; // La valeur reçue est en centièmes de °C
if ((temp <= TEMPERATURE_VALEUR_MINI) || (temp >= TEMPERATURE_VALEUR_MAXI)) // Test de validité
{
sprintf(tmp, "Erreur sur carte %i : Temp = %f (Min = %f et Max = %f)", adresse_module, temp, TEMPERATURE_VALEUR_MINI, TEMPERATURE_VALEUR_MAXI);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
//-------------------------------------------------------------
// Mode test :
//-------------------------------------------------------------
mode_test = commande->cde[ptr_cde ++];
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP8DC :
{
//-------------------------------------------------------------
// Etat de l'alimentation :
//-------------------------------------------------------------
alim_etat = commande->cde[ptr_cde ++];
//-------------------------------------------------------------
// Tension d'alimentation :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
in_v = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mV à V
//-------------------------------------------------------------
// Température :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
temp = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 100; // La valeur reçue est en centièmes de °C
if ((temp <= TEMPERATURE_VALEUR_MINI) || (temp >= TEMPERATURE_VALEUR_MAXI)) // Test de validité
{
sprintf(tmp, "Erreur sur carte %i : Temp = %f (Min = %f et Max = %f)", adresse_module, temp, TEMPERATURE_VALEUR_MINI, TEMPERATURE_VALEUR_MAXI);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
// SDIR #138 : Début
//-------------------------------------------------------------
// Courant de masses :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
masses_i = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mA à A
// SDIR #138 : Fin
//-------------------------------------------------------------
// Mode test :
//-------------------------------------------------------------
mode_test = commande->cde[ptr_cde ++];
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SBS :
{
//-------------------------------------------------------------
// Cde alimentation 5V2 :
//-------------------------------------------------------------
alim_cde = commande->cde[ptr_cde ++];
//-------------------------------------------------------------
// Etat de la tension d'alimentation :
//-------------------------------------------------------------
alim_etat = commande->cde[ptr_cde ++];
//-------------------------------------------------------------
// Valeur de tension d'elimentation :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
in_v = ((float)((((uint16_t) msb) << 8) | ((uint16_t) lsb))) / 1000; // Passage de mV à V
//-------------------------------------------------------------
// Température :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
temp = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 100; // La valeur reçue est en centièmes de °C
if ((temp <= TEMPERATURE_VALEUR_MINI) || (temp >= TEMPERATURE_VALEUR_MAXI)) // Test de validité
{
sprintf(tmp, "Erreur sur carte %i : Temp = %f (Min = %f et Max = %f)", adresse_module, temp, TEMPERATURE_VALEUR_MINI, TEMPERATURE_VALEUR_MAXI);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP4AC :
{
//-------------------------------------------------------------
// Température :
//-------------------------------------------------------------
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
temp = ((float)((int16_t) ((((uint16_t) msb) << 8) | ((uint16_t) lsb)))) / 100; // La valeur reçue est en centièmes de °C
if ((temp <= TEMPERATURE_VALEUR_MINI) || (temp >= TEMPERATURE_VALEUR_MAXI)) // Test de validité
{
sprintf(tmp, "Erreur sur carte %i : Temp = %f (Min = %f et Max = %f)", adresse_module, temp, TEMPERATURE_VALEUR_MINI, TEMPERATURE_VALEUR_MAXI);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
break;
}
//--------------------------------------------------------------------------------
default: break;
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
// Paramètres toujours présents en fin de commande :
if(systeme.flag_r_term_etat_carte) ptr_cde ++; // Conservé uniquement pour des raisons de compatibilité au moment des mises à jour > 2.0.0
orig = commande->cde[ptr_cde ++];
// DEBUG :
//printf("Etat de la carte %i reçu : Etat alim = %i, Tension = %6.3f V, Température = %5.2f °C, Mode test = %i, Origine reset = %i, Courant de masses = %.3f A (ptr_cde=%i et lg_cde=%i)\n",
// adresse_module, alim_etat, in_v, temp, mode_test, orig, masses_i, ptr_cde, commande->lg_cde);
}
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, retour NOK avec code d'erreur.
{
if (systeme.modules_config[adresse_module].flag_validite) // Le fait de recevoir un Etat Carte d'un module non valide n'est pas une erreur. Mais ne nécessite pas d'être traité pour autant...
{
// Version corrigée en altitude :
// uint8_t coeff_correction_pat
// coeff_correction_pat = 79 + (0.002888888 * entrees.predefinies[adresse_module].temp); // Avec 'entrees.predefinies[adresse_module].temp' exprimée en centièmes de °C
// entrees.predefinies[adresse_module].pat = pat + (entrees.predefinies[adresse_module].alt / coeff_correction_pat); // Compensation d'environ 1 hpa (soit 100pa) / 8m d'altitude
// Version non corrigée en altitude :
// entrees.predefinies[adresse_module].pat = pat;
// printf("Pression non corrigée = %i, altitude = %i, température=%i, coeff correcteur = %i, pression corrigée = %i\n", pat, entrees.predefinies[adresse_module].alt, entrees.predefinies[adresse_module].temp, entrees.predefinies[adresse_module].coeff_correction_pat, entrees.predefinies[adresse_module].pat);
// Mise à jour des entrées prédéfinies :
for (i = 0; i < entrees.predefinies.nb; i ++)
{
if (!entrees.predefinies.entrees[i].flag_validite) continue; // On ne traite que les entrées prédéfinies valides...
if (entrees.predefinies.entrees[i].module != adresse_module) continue; //... et celles affectées au module en cours.
switch(entrees.predefinies.entrees[i].no)
{
case ENTREE_PREDEFINIE_PAT: { entrees.predefinies.entrees[i].valeur = pat; break; }
case ENTREE_PREDEFINIE_HUM: { entrees.predefinies.entrees[i].valeur = hum; break; }
case ENTREE_PREDEFINIE_TEMP: { entrees.predefinies.entrees[i].valeur = temp; break; }
case ENTREE_PREDEFINIE_IN_V: { entrees.predefinies.entrees[i].valeur = in_v; break; }
case ENTREE_PREDEFINIE_IN_I: { entrees.predefinies.entrees[i].valeur = in_i; break; }
case ENTREE_PREDEFINIE_USB_I: { entrees.predefinies.entrees[i].valeur = usb_i; break; }
case ENTREE_PREDEFINIE_ACC_XYZ: // NB : On n'a PAS reçu la valeur de ACC_XYZ. Mais si on vient de recevoir l'état de ShipBase, et si l'entrée ACC_XYZ est valide, alors on calcule ACC_XYZ à partir des accélérations X, Y et Z que l'on vient de recevoir de ShipBase.
{
entrees.predefinies.entrees[i].valeur = sqrt(carre(acc_x) + carre(acc_y) + carre(acc_z)) - 1; // La soustraction de 1g permet d'avoir une valeur moyenne des chocs = 0
break;
}
case ENTREE_PREDEFINIE_ACC_X: { entrees.predefinies.entrees[i].valeur = acc_x; break; }
case ENTREE_PREDEFINIE_ACC_Y: { entrees.predefinies.entrees[i].valeur = acc_y; break; }
case ENTREE_PREDEFINIE_ACC_Z: { entrees.predefinies.entrees[i].valeur = acc_z; break; }
}
}
// Paramètres spécifiques à certaines cartes :
switch(systeme.modules_config[adresse_module].type)
{
//--------------------------------------------------------------------------------
case TYPE_CARTE_SHIPBASE :
{
// Etat de la tension d'alimentation :
systeme.modules_config[adresse_module].alim_etat = alim_etat;
// Valeur de tension d'alimentation :
systeme.modules_config[adresse_module].alim_valeur = in_v;
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP812 :
{
// Etat de la tension d'alimentation :
systeme.modules_config[adresse_module].alim_etat = alim_etat;
// Valeur de tension d'alimentation :
systeme.modules_config[adresse_module].alim_valeur = in_v;
// Mode test :
systeme.modules_config[adresse_module].mode_test = mode_test;
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP8DC :
{
// Etat de la tension d'alimentation :
systeme.modules_config[adresse_module].alim_etat = alim_etat;
// Valeur de tension d'alimentation :
systeme.modules_config[adresse_module].alim_valeur = in_v;
// SDIR #318 : Début
// Etat du courant de masses :
systeme.modules_config[adresse_module].courant_masses = masses_i;
// SDIR #318 : Fin
// Mode test :
systeme.modules_config[adresse_module].mode_test = mode_test;
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SBS :
{
// Cde alimentation 5V2 :
systeme.modules_config[adresse_module].alim_cde = alim_cde;
// Etat de la tension d'alimentation :
systeme.modules_config[adresse_module].alim_etat = alim_etat;
// Valeur de tension d'alimentation :
// Attention : sur les SBS, la tension mesurée au niveau de la carte est le 5V.
// Pour avoir la tension batterie, il faut utiliser l'état batterie (et non état carte comme ici).
systeme.modules_config[adresse_module].alim_valeur = in_v;
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP4AC :
{
break;
}
//--------------------------------------------------------------------------------
default: break;
}
// Origine du reset :
systeme.modules_config[adresse_module].origine_reset = orig;
}
}
else
{
sprintf(tmp, "La commande C_BUS_UP_COMMANDE_ETAT_CARTE reçue sur C-Bus Up de la carte %i n'est pas conforme (erreur = %i)", adresse_module, erreur);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_CARTE; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au Compagnon de remonter au CM3+ l’état des Circuits
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_circuits(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t lsb, msb;
uint8_t adresse_module;
struct {
uint8_t consigne;
uint8_t etat;
uint16_t tension;
uint16_t intensite;
uint16_t frequence;
uint8_t mode_test;
} tmp_circuits[MAX_NOMBRE_CIRCUITS];
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
adresse_module = commande->cde[ptr_cde ++]; // <numéro de carte>
if ((adresse_module >= MAX_NOMBRE_MODULES) || (systeme.modules_config[adresse_module].flag_validite == FALSE))
{
erreur = C_BUS_ERREUR_NO_CARTE;
break;
}
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SP812:
case TYPE_CARTE_SP8DC:
{
for (i = 0; i < SP8XX_NOMBRE_CIRCUITS; i++) // <consigne 1><état 1><intensité 1><mode test 1>
{
tmp_circuits[i].consigne = commande->cde[ptr_cde ++]; // Consigne
tmp_circuits[i].etat = commande->cde[ptr_cde ++]; // Etat
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
tmp_circuits[i].intensite = (((uint16_t) msb) << 8) | ((uint16_t) lsb); // Intensité
tmp_circuits[i].mode_test = commande->cde[ptr_cde ++]; // Mode test
}
break;
}
case TYPE_CARTE_SP4AC:
{
for (i = 0; i < SP4AC_NOMBRE_CIRCUITS; i++) // <consigne><état><tension><intensité><fréquence>
{
tmp_circuits[i].consigne = commande->cde[ptr_cde ++]; // Consigne
tmp_circuits[i].etat = commande->cde[ptr_cde ++]; // Etat
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
tmp_circuits[i].tension = (((uint16_t) msb) << 8) | ((uint16_t) lsb); // Tension (en dixièmes de V)
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
tmp_circuits[i].intensite = (((uint16_t) msb) << 8) | ((uint16_t) lsb); // Intensité (en mA)
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
tmp_circuits[i].frequence = (((uint16_t) msb) << 8) | ((uint16_t) lsb); // Fréquence (en centièmes de Hz)
}
break;
}
default: erreur = C_BUS_ERREUR_NO_CARTE;
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
// printf("Commande état circuit reçue pour la carte %i et erreur = %i", adresse_module, erreur);
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, prise en compte de l'état des entrées :
{
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SP812:
case TYPE_CARTE_SP8DC:
{
// char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
// sprintf(tmp, "Etat circuit reçu sur C_Bus pour la carte #%i : ", adresse_module);
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
for (i = 0; i < circuits.nb; i ++)
{
if (circuits.circuits[i].flag_validite == FALSE) continue; // On ne traite que les circuits valides... NB : On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
if (circuits.circuits[i].adresse_module != adresse_module) continue; // ... et ceux piloté par cette carte...
if (circuits.circuits[i].no_circuit >= SP8XX_NOMBRE_CIRCUITS) continue; // ... et dont le n° de circuit est valide pour cette carte
// Mise à jour de l'historique si besoin :
if ((circuits.circuits[i].etat != ETAT_CIRCUIT_LIMITATION) && // Si on est déjà en Limitation, on ne traite pas les retours du SP8XX (l'état sera RAZ lors du prochain changement de consigne).
(circuits.circuits[i].etat != ETAT_CIRCUIT_DELESTE)) // Idem pour le Delestage (Limitation et Delestage sont gérés par l'appli)
{
if (tmp_circuits[circuits.circuits[i].no_circuit].etat != circuits.circuits[i].etat)
{
enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CIRCUITS, (CIRCUIT_OK + tmp_circuits[circuits.circuits[i].no_circuit].etat), circuits.circuits[i].cle_primaire, circuits.circuits[i].intensite_seuil_haut, NULL);
circuits.circuits[i].etat = tmp_circuits[circuits.circuits[i].no_circuit].etat;
}
}
if ((!circuits.circuits[i].flag_changement_consigne_en_cours) && // SDIR #179
(circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante != tmp_circuits[circuits.circuits[i].no_circuit].consigne))
{
circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante = tmp_circuits[circuits.circuits[i].no_circuit].consigne;
char date_vide[MAX_LONGUEUR_DATE_COURANTE] = ""; // Evite un warning depuis GCC14
enregistrement_mesure(SOURCE_MESURE_CIRCUIT, i, CIRCUIT_VARIABLE_CONSIGNE, date_vide, BDD_ENREGISTREMENT_MESURE_PONCTUEL);
}
circuits.circuits[i].mode_test = tmp_circuits[circuits.circuits[i].no_circuit].mode_test;
circuits.circuits[i].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante = ((float)tmp_circuits[circuits.circuits[i].no_circuit].intensite) / 1000; // Cas normal. Le /1000 permet de passer de la valeur reçue en mA à des A
if (circuits.circuits[i].no_circuit_esclave >= 0) // Cas où le circuit a un esclave
{
circuits.circuits[i].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante += ((float)tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].intensite) / 1000; // Ne fonctionne que parce que l'esclave est FORCEMENT sur la même carte !!
tmp_circuits[circuits.circuits[circuits.circuits[i].no_circuit_esclave].no_circuit].intensite = 0; // Utile si le traitement de l'esclave n'a pas encore été fait
circuits.circuits[circuits.circuits[i].no_circuit_esclave].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante = 0; // Utile si le traitement de l'esclave a déjà été fait
}
if (circuits.circuits[i].flag_changement_consigne_en_cours) circuits.circuits[i].flag_changement_consigne_en_cours = false; // RAZ pour prochains retours d'état (SDIR #179)
// DEBUG :
// printf("module # %i | circuit #%i : courant = %i mA, soit %.3f A\n",
// circuits.circuits[i].adresse_module, circuits.circuits[i].no_circuit, tmp_circuits[circuits.circuits[i].no_circuit].intensite,
// circuits.circuits[i].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante);
}
break;
}
case TYPE_CARTE_SP4AC:
{
// sprintf(tmp, "Etat circuit reçu sur C_Bus pour la carte #%i :", adresse_module);
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
for (i = 0; i < circuits.nb; i ++)
{
if (circuits.circuits[i].flag_validite == FALSE) continue; // On ne traite que les circuits valides... NB : On teste le flag de Validité (plutôt que Disponible) car on est sûr que la carte est présente (donc si le circuit est valide, il est disponible)
if (circuits.circuits[i].adresse_module != adresse_module ) continue; // ... et ceux piloté par cette carte...
if (circuits.circuits[i].no_circuit >= SP4AC_NOMBRE_CIRCUITS) continue; // ... et dont le n° de circuit est valide pour cette carte
// Mise à jour de l'historique si besoin :
if (tmp_circuits[circuits.circuits[i].no_circuit].etat != circuits.circuits[i].etat)
{
// enregistrement_historique(TYPE_SOURCE_HISTORIQUE_CIRCUITS, (CIRCUIT_OK + tmp_circuits[circuits.circuits[i].no_circuit].etat), circuits.circuits[i].cle_primaire, circuits.circuits[i].intensite_seuil_haut, NULL);
// A VERIFIER !!!!
circuits.circuits[i].etat = tmp_circuits[circuits.circuits[i].no_circuit].etat;
}
circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante = tmp_circuits[circuits.circuits[i].no_circuit].consigne;
circuits.circuits[i].etat = tmp_circuits[circuits.circuits[i].no_circuit].etat;
circuits.circuits[i].variables[CIRCUIT_VARIABLE_TENSION_SECTEUR].valeur_courante = ((float)tmp_circuits[circuits.circuits[i].no_circuit].tension) / 10; // Pour passer de dixèmes de Volts à des Volts
circuits.circuits[i].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante = ((float)tmp_circuits[circuits.circuits[i].no_circuit].intensite) / 1000; // Pour passer de mA à A
circuits.circuits[i].variables[CIRCUIT_VARIABLE_FREQUENCE].valeur_courante = ((float)tmp_circuits[circuits.circuits[i].no_circuit].frequence) / 100; // Pour passer de centièmes de Hz à des Hertz
// DEBUG :
// printf("%i : consigne = %.0f, etat = %i, tension = %.1fV, intensite = %.3fA, frequence = %.2fHz\n",
// circuits.circuits[i].no_circuit, circuits.circuits[i].variables[CIRCUIT_VARIABLE_CONSIGNE].valeur_courante, circuits.circuits[i].etat,
// circuits.circuits[i].variables[CIRCUIT_VARIABLE_TENSION_SECTEUR].valeur_courante, circuits.circuits[i].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante,
// circuits.circuits[i].variables[CIRCUIT_VARIABLE_FREQUENCE].valeur_courante);
}
break;
}
default: erreur = C_BUS_ERREUR_NO_CARTE;
}
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_CIRCUITS; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au Compagnon de remonter au CM3+ l’état des entrées Auxiliaires.
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_entrees_aux(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t val[MAX_NOMBRE_ENTREES_AUXILIAIRES];
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
for (i=0; i < MAX_NOMBRE_ENTREES_AUXILIAIRES; i++)
{
// Lecture de la valeur de l'entrée en cours :
val[i] = commande->cde[ptr_cde ++];
// Contrôle de la valeur reçue :
if ((val[i] != ON) && (val[i] != OFF))
{
erreur = C_BUS_ERREUR_VALEUR_CONSIGNE;
break;
}
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, prise en compte de l'état des entrées :
{
/*
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
affichage_debug(__FILE__, __LINE__, "---------------------------------------------------------------------", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
for (i=0; i < MAX_NOMBRE_ENTREES_AUXILIAIRES; i++)
{
sprintf(tmp, "Etat AUX #%i : %s", (i+1), val[i] ? "=== On ===" : "Off");
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
}
affichage_debug(__FILE__, __LINE__, " ", TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
*/
for (i=0; i < MAX_NOMBRE_ENTREES_AUXILIAIRES; i++)
{
if (!entrees.aux.entrees[i].flag_validite) continue;
// NB : Le test 1 <= no d'entrées <= 32 a été fait dans 'enregistrement_annuaire_k_bus()'...
if (entrees.aux.entrees[i].logique == ENTREE_AUX_LOGIQUE_NORMALE)
{
if (val[entrees.aux.entrees[i].no - 1] == 0) entrees.aux.entrees[i].valeur = OFF;
else entrees.aux.entrees[i].valeur = ON;
}
else
{
if (val[entrees.aux.entrees[i].no - 1] == 0) entrees.aux.entrees[i].valeur = ON;
else entrees.aux.entrees[i].valeur = OFF;
}
}
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_ENTREES_AUX; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Permet de recevoir l'état des Level Sensors gérés par le Compagnon
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_level_sensors(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t lsb, msb;
int16_t val[MAX_NOMBRE_ENTREES_LEVEL_SENSOR]; // Important que ce soit un 'int' signé car les valeurs de retour en mode défaut d'isolement peuvent être négative....
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
for (i=0; i < MAX_NOMBRE_ENTREES_LEVEL_SENSOR; i++)
{
// Lecture de la valeur de l'entrée en cours :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
val[i] = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
// Contrôle de la valeur reçue :
// ????? en fonction du mode du capteur ??
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, prise en compte de l'état des entrées :
{
for (i=0; i < MAX_NOMBRE_ENTREES_LEVEL_SENSOR; i++)
{
if (!entrees.level_sensor.entrees[i].flag_validite) continue;
// NB : Le test 1 <= no d'entrées <= 8 a été fait dans 'enregistrement_annuaire_k_bus()'...
entrees.level_sensor.entrees[i].valeur = val[entrees.level_sensor.entrees[i].no - 1]; // NB : Valeur en mV si 0-10V, en µA si 4-20mA, en Ohms si 500R, en dixième de mA si Defaut d'isolement (+ ou -)
switch(entrees.level_sensor.entrees[i].mode)
{
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_0_10V : // Valeur en mV si 0-10V => V
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_4_20MA : // Valeur en µA si 4-20mA => mA
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_AUTO_TEST : // Valeur en mV si AUTO TEST => V (valeur entre 0 et 10V)
{
entrees.level_sensor.entrees[i].valeur /= 1000;
break;
}
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_MASSE : // Valeur en dixièmes de mA => mA
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_PLUS :
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_DEFAUT_ISOLEMENT_FULL :
{
entrees.level_sensor.entrees[i].valeur /= 10;
break;
}
case ENTREE_LEVEL_SENSOR_MODE_FONCTIONNEMENT_500R :
default:
break;
}
}
// printf("\nEtat des Level Sensors : ");
// for (i=0; i < MAX_NOMBRE_ENTREES_LEVEL_SENSOR; i++) printf("%i : %.3f\t", (i+1), entrees.level_sensor.entrees[i].valeur);
// printf("\n");
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_LEVEL_SENSORS; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Permet de recevoir l'état des 4 Entrées ANA gérés par le Compagnon
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_entrees_volt(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t lsb, msb;
uint16_t val[MAX_NOMBRE_ENTREES_VOLTAGE];
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
for (i=0; i < MAX_NOMBRE_ENTREES_VOLTAGE; i++)
{
// Lecture de la valeur de l'entrée en cours :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
val[i] = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
// Contrôle de la valeur reçue :
// if (val[i] > 32000) erreur = C_BUS_VALEUR_HORS_DOMAINE; // On considère que la valeur ne peut dépasser 32V
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, prise en compte de l'état des entrées :
{
for (i=0; i < MAX_NOMBRE_ENTREES_VOLTAGE; i++)
{
if (!entrees.volt.entrees[i].flag_validite) continue;
// NB : Le test 1 <= no d'entrées <= 4 a été fait dans 'enregistrement_annuaire_k_bus()'...
entrees.volt.entrees[i].valeur = val[entrees.volt.entrees[i].no - 1]; // NB : Valeur en mV
entrees.volt.entrees[i].valeur /= 1000; // Passage de mV en V
}
// printf("\nEtat des Entrées Voltage : ");
// for (i=0; i < MAX_NOMBRE_ENTREES_VOLTAGE; i++) printf("%i : %.3f V\t", (i+1), entrees.volt.entrees[i].valeur);
// printf("\n");
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_ENTREES_VOLT; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Permet de recevoir l'état des entrées OW gérés par le Compagnon
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_entrees_ow(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t nb;
uint8_t lsb, msb;
uint16_t x;
uint8_t defaut_bus;
uint8_t no_entree;
float val[MAX_NOMBRE_ENTREES_OW]; // SDIR # 176 : passage en float
int8_t etat[MAX_NOMBRE_ENTREES_OW];
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
defaut_bus = ON; // Par défaut. RAZ dès qu'on trouve au moins un device qui a pu faire sa mesure (donc qu'il n'y avait pas de défaut bus...)
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Fake loop pour permettre la sortie par simple break en cas d'erreur.
{
nb = commande->cde[ptr_cde ++];
if (nb > MAX_NOMBRE_ENTREES_OW)
{
erreur = C_BUS_VALEUR_HORS_DOMAINE;
break;
}
for (i=0; i < nb; i++)
{
// Lecture de la valeur de l'entrée en cours :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
x = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
if (x == DEVICE_OW_VALEUR_ERREUR_ETAT_GENERAL_NOK) etat[i] = OW_ETAT_BUS_NOK; // SDIR #178
else
{
defaut_bus = OFF;
if (x == DEVICE_OW_VALEUR_ERREUR_ETAT_DEVICE_NOK) etat[i] = OW_ETAT_DEVICE_NOK; // SDIR #178
else
{
etat[i] = OW_ETAT_DEVICE_OK; // SDIR #178
val[i] = ((float) ((int16_t) x)) / 100; // Le passage de UINT16_T à INT16_T avant FLOAT est "obligatoire" pour que les valeurs négatives soient correctement converties. Conversion en float et passage de centièmes de °C à °C. // SDIR # 176
}
}
// Contrôle de la valeur reçue :
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, prise en compte de l'état des entrées :
{
// Mise à jour du premier flag, indiquant qu'on a reçu les premières valeurs du Compagnon :
if (!entrees.ow.flag_premieres_valeurs_recues) entrees.ow.flag_premieres_valeurs_recues = TRUE;
if (nb > 0) // Si 'nb' != 0, c'est qu'il s'agit d'un retour normal des valeurs d'entrées OW
{
for (i=0; i < nb; i++)
{
// Mise à jour du device (qui existe toujours - si NB reste raisonnable évidemment) :
if ((entrees.ow.devices[i].valeur != val[i]) ||
(entrees.ow.devices[i].etat != etat[i]))
{
entrees.ow.devices[i].valeur = val[i];
entrees.ow.devices[i].etat = etat[i];
entrees.ow.devices[i].flag_dde_maj_bdd = TRUE;
}
// Mise à jour de l'entrée OW s'il y en a une de valide sur ce device :
if (entrees.ow.devices[i].no_entree == -1) continue; // Indique qu'aucune entrée n'est affectée à ce device...
no_entree = entrees.ow.devices[i].no_entree; // Simplifie la lecture. Lien entre le device et l'entrée si elle existe
if (!entrees.ow.entrees[no_entree].flag_validite) continue; // ne devrait pas arriver puisque le device est affecté à l'entrée...
if ((entrees.ow.entrees[no_entree].valeur != val[i]) &&
(etat[i] == OW_ETAT_DEVICE_OK)) // SDIR #178
{
// SDIR # 176 : modification des unités et donc des CAST associés.
if (( (val[i] != 0) || // Si la nouvelle valeur = 0 ET
(abs(entrees.ow.entrees[no_entree].valeur) < TEMPERATURE_DELTA_ZERO_MAXI) ) && // Si l'ancienne n'était pas comprise entre -2°C et +2°C, on jette la valeur qui ressemble à une erreur !
(val[i] < TEMPERATURE_VALEUR_MAXI) && // ... et si la nouvelle valeur est < +125°C
(val[i] > TEMPERATURE_VALEUR_MINI)) // ... et si la nouvelle valeur est > -40°C
{
entrees.ow.entrees[no_entree].valeur = val[i];
}
else
{
sprintf(tmp, "Valeur d'entrée OW rejetée : ancienne valeur = %.3f °C et nouvelle reçue = %.3f °C ", entrees.ow.entrees[no_entree].valeur, val[i]);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
}
}
// SDIR #178 [début] :
if (etat[i] != entrees.ow.entrees[no_entree].etat) // Mise à jour de l'état s'il a évolué :
{
if (etat[i] == OW_ETAT_DEVICE_OK) // Si le nouvel état n'est pas en erreur :
{
sprintf(tmp, "Le device OW #%i n'est plus en erreur. ", i);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK);
}
else
{
sprintf(tmp, "Le device OW #%i vient d'être détecté en erreur. ", i);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
}
entrees.ow.entrees[no_entree].etat = etat[i]; // Mémorisation du nouvel état dans tous les cas
}
// SDIR #178 [fin]
entrees.ow.defaut_bus = defaut_bus;
}
// printf("\nEtat des %i devices OW : \n", nb);
// for (i=0; i < nb; i++) printf("\t%i [Rom Code = %s] = %.2f °C - Etat = %s \n", i, entrees.ow.devices[i].rom_code, entrees.ow.devices[i].valeur, ((entrees.ow.devices[i].etat == 0) ? "Ok" : ((entrees.ow.devices[i].etat == OW_ETAT_DEVICE_NOK) ? "Erreur de device" : "Erreur générale OW")));
// printf("\n");
}
else c_bus_down_commande_annuaire_ow(); // Si 'nb' = 0, c'est l'info qu'une découverte réseau OW vient de se terminer et qu'il faut demander un nouvel état d'annuaire OW.
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_ENTREES_OW; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au Compagnon de remonter au CM3+ l’état des IBS
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_entrees_batteries(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t llsb, lsb, msb, mmsb;
uint8_t adresse_module;
int16_t temperature;
uint16_t tension;
int32_t courant_differentiel;
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
adresse_module = commande->cde[ptr_cde ++]; // <numéro de carte>
if ((adresse_module >= MAX_NOMBRE_MODULES) || (systeme.modules_config[adresse_module].flag_validite == FALSE))
{
erreur = C_BUS_ERREUR_NO_CARTE;
break;
}
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SBS :
{
// Température de la batteries :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
temperature = (int16_t) ((uint16_t) lsb | ((uint16_t) msb << 8));
// Tension de la batterie :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
tension = (uint16_t) ((uint16_t) lsb | ((uint16_t) msb << 8));
// Intensité du courant différentiel dans la batterie :
llsb =commande->cde[ptr_cde ++];
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
mmsb = commande->cde[ptr_cde ++];
courant_differentiel = (int32_t) ((uint32_t) llsb | ((uint32_t) lsb << 8) | ((uint32_t) msb << 16) | ((uint32_t) mmsb << 24));
break;
}
default: erreur = C_BUS_ERREUR_NO_CARTE;
}
if (erreur != C_BUS_ERREUR_AUCUNE) break;
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
// printf("Commande état batterie reçue pour la carte %i et erreur = %i", adresse_module, erreur);
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, prise en compte de l'état des entrées :
{
switch(systeme.modules_config[adresse_module].type)
{
case TYPE_CARTE_SBS :
{
for (i = 0; i < batteries.nb; i ++)
{
if (batteries.batteries[i].flag_validite == FALSE) continue; // On ne traite que les batteries valides...
if (batteries.batteries[i].adresse_module != adresse_module ) continue; // ... et ceux piloté par cette carte...
// Actuellement, une sonde non branchée renvoie une temprature d'erreur (BATTERIES_NTC_TEMPERATURE_ERREUR = -50°C dans 'batteries.h').
// Si besoin, comparer '((float)temperature)/100' à cette constante et activer un indicateur d'erreur. Surtout si la tension est simultanéement à 0.
// Idem si l'on veut ne pas prendre en compte ces valeurs d'erreur (garder l'ancienne) mais pas fait pour le moment car il semble plus utile d'alerter par une valeur ANORMALE. D'autant
// que cela pose la question du démarrage initial sans sonde : quelle valeur 'garder'...?
batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante = ((float)temperature)/100; // La valeur entière est en centièmes de °C
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante = ((float)tension)/1000; // La valeur entière est en mV
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante = ((float)courant_differentiel)/1000; // La valeur entière est en mA
// printf("Etat batterie #%i reçu pour la carte %i : température = %.2f °C, tension = %.3f V et courant diff = %.3f A \n", i, adresse_module, batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante, batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante);
}
break;
}
default: erreur = C_BUS_ERREUR_NO_CARTE;
}
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_ENTREES_BATTERIES; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au Compagnon de remonter au CM4 l’état d'un PGN NMEA2000
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_etat_pgn_nmea(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint16_t i;
uint8_t llsb, lsb, msb, mmsb;
struct Struct_pgn_nmea pgn;
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
// N° de PGN :
llsb =commande->cde[ptr_cde ++];
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
mmsb = commande->cde[ptr_cde ++];
pgn.pgn = (uint32_t) llsb | ((uint32_t) lsb << 8) | ((uint32_t) msb << 16) | ((uint32_t) mmsb << 24);
// Source :
pgn.source = commande->cde[ptr_cde ++];
// Priorite :
pgn.priority = commande->cde[ptr_cde ++];
if (pgn.priority > 7)
{
erreur = C_BUS_ERREUR_PRIORITE;
break;
}
// Timestamp :
llsb =commande->cde[ptr_cde ++];
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
mmsb = commande->cde[ptr_cde ++];
pgn.timestamp = (uint32_t) llsb | ((uint32_t) lsb << 8) | ((uint32_t) msb << 16) | ((uint32_t) mmsb << 24);
// Longueur Data :
pgn.lg_data = commande->cde[ptr_cde ++];
if (pgn.lg_data > NMEA_MAX_TAILLE_DATA_PGN)
{
erreur = C_BUS_ERREUR_VALEUR_TAILLE;
break;
}
// Data :
for (i = 0; i < pgn.lg_data; i ++) pgn.data[i] = commande->cde[ptr_cde ++];
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE)
{
pgn.flag_presence = true;
traitement_pgn_compagnon(pgn); // NB : pgn.actif n'est pas initialisé à ce stade car l'info vient de la BDD...
}
else printf("erreur %i dans réception de commande 'c_bus_up_commande_etat_pgn_nmea()' \n", erreur);
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_PGN_NMEA; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//==================================================================================================================================================================
// Fonction : Cette commande permet au Compagnon de remonter sa config ou celle dune carte extension au CM3+
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : 0 si pas d'erreur, [code d'erreur (>0)]> si erreur
//==================================================================================================================================================================
uint8_t c_bus_up_commande_config_carte(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
int8_t erreur;
uint16_t ptr_cde;
uint8_t lsb, msb;
uint8_t adresse_module;
uint16_t ptr_eeprom;
int16_t offset_intensite = 0; // Signé...!
int16_t gain_intensite = 0; // Signé...!
int16_t offset_usine_intensite = 0; // Signé...!
int16_t gain_usine_intensite = 0; // Signé...!
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
// Initialisation du traitement de la commande :
ptr_cde = 1; // La valeur 1 permet de sauter le code commande qui a été déjà testé avant d'appeler la fonction
reponse->lg_reponse = 0;
erreur = C_BUS_ERREUR_AUCUNE;
//===========================================================================================================================
// Traitement de tous les paramètres de la commande :
//===========================================================================================================================
do // Boucle factice pour permettre la sortie par simple break en cas d'erreur.
{
adresse_module = commande->cde[ptr_cde ++]; // <numéro de carte>
if ((adresse_module >= MAX_NOMBRE_MODULES) || (systeme.modules_config[adresse_module].flag_validite == FALSE))
{
sprintf(tmp, "Erreur : n° de carte = %i (Min = 0 et Max = %i ou carte dévalidée)", adresse_module, MAX_NOMBRE_MODULES);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
erreur = C_BUS_ERREUR_NO_CARTE;
break;
}
// Compagnon :
if (adresse_module == 0)
{
}
// Autre carte :
else
{
switch(systeme.modules_config[adresse_module].type)
{
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SP8DC :
{
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SBS :
{
// Offset intensité :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
offset_intensite = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
// Gain intensité :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
gain_intensite = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
// Offset usine intensité :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
offset_usine_intensite = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
// Gain usine intensité :
lsb = commande->cde[ptr_cde ++];
msb = commande->cde[ptr_cde ++];
gain_usine_intensite = (((uint16_t) msb) << 8) | ((uint16_t) lsb);
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP4AC :
{
break;
}
//--------------------------------------------------------------------------------
default: break;
}
}
//----------------------------------------------------------------------
// Vérification de la longueur de commande :
//----------------------------------------------------------------------
if (ptr_cde != commande->lg_cde) erreur = C_BUS_ERREUR_FORMAT_COMMANDE;
} while(0);
//===========================================================================================================================
// Traitement de la commande et préparation de la réponse :
//===========================================================================================================================
if (erreur == C_BUS_ERREUR_AUCUNE) // Si une erreur a déjà été trouvée, retour NOK avec code d'erreur.
{
// Compagnon :
if (adresse_module == 0)
{
}
// Autres cartes :
else
{
switch(systeme.modules_config[adresse_module].type)
{
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP812 :
case TYPE_CARTE_SP8DC :
{
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SBS :
{
ptr_eeprom = 0;
// Attention : dans les lignes ci-dessous, on utilise 'modules_physiques' au lieu de 'modules' car les infos d'EEPROM sont relatives au module PHYSIQUE.
// Offset de courant :
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) (offset_intensite & 0x00FF); // LSB de l'offset
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) ((offset_intensite >> 8) & 0x00FF); // MSB de l'offset
// Gain de courant :
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) (gain_intensite & 0x00FF); // LSB du gain
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) ((gain_intensite >> 8) & 0x00FF); // MSB du gain
// Offset usine de courant :
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) (offset_usine_intensite & 0x00FF); // LSB de l'offset usine
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) ((offset_usine_intensite >> 8) & 0x00FF); // MSB de l'offset usine
// Gain usine de courant :
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) (gain_usine_intensite & 0x00FF); // LSB du gain usine
systeme.modules_physiques[adresse_module].eeprom[ptr_eeprom ++] = (uint8_t) ((gain_usine_intensite >> 8) & 0x00FF); // MSB du gain usine
enregistrement_eeprom(adresse_module, ptr_eeprom); // Mise à jour des nouvelles valeurs dans la BDD
// DEBUG :
//printf("Config de la carte %i reçue : Offset intensité = %5i, Gain intensité = %5i, Offset intensité usine = %5i, Gain intensité usine = %5i \n", adresse_module, offset_intensite, gain_intensite, offset_usine_intensite, gain_usine_intensite);
break;
}
//--------------------------------------------------------------------------------
case TYPE_CARTE_SP4AC :
{
break;
}
//--------------------------------------------------------------------------------
default: break;
}
}
}
else
{
sprintf(tmp, "La commande C_BUS_UP_COMMANDE_CONFIG_CARTE reçue sur C-Bus Up n'est pas conforme (erreur = %i)", erreur);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
}
reponse->reponse[reponse->lg_reponse ++] = C_BUS_UP_COMMANDE_ETAT_CARTE; // La trame de retour comprend toujours le code commande en tête.
reponse->reponse[reponse->lg_reponse ++] = erreur;
reponse->flag_ready = TRUE;
return (erreur);
}
//------------------------------------------------------------------------------------------------------------------------------------
//==================================================================================================================================================================
// Fonction : Fonction appelée lorsque le code de la commande reçu est inconnu.
// Reçoit : Le pointeur sur la structure de commande qui permet sa lecture mais aussi la mise à jour du buffer de réponse et sa longueur.
// Renvoit : Systématiquement code d'erreur C_BUS_ERREUR_COMMANDE_INCONNUE
//==================================================================================================================================================================
uint8_t c_bus_up_commande_inconnue(struct Struct_commande_c_bus * commande, struct Struct_reponse_c_bus * reponse)
{
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
// Message de debug :
sprintf(tmp, "Commande inconnue reçue sur C_Bus [code=%i]...", c_bus.up.cde.cde[0]);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
// Préparation de la réponse d'erreur :
reponse->lg_reponse = 0;
reponse->reponse[reponse->lg_reponse ++] = c_bus.up.cde.cde[0]; // La trame de retour comprend toujours le code commande en tête...
reponse->reponse[reponse->lg_reponse ++] = C_BUS_ERREUR_COMMANDE_INCONNUE; // ... suivi du code d'erreur.
reponse->flag_ready = TRUE;
return (C_BUS_ERREUR_COMMANDE_INCONNUE);
}
//==================================================================================================================================================================
// Fonction : En fonction du premier octet de la commande reçue sur C-Bus, appelle la fonction correspondante.
// Si le code reçu ne correspond à aucune commande connue, une fonction particulière est appelée pour formatter une réponse d'erreur au Compagnon.
// Reçoit : Rien
// Renvoit : 0 si pas d'erreur (commande connue et réponse acceptée), code d'errer > 0 sinon
//==================================================================================================================================================================
uint8_t c_bus_up_recherche_commande(void)
{
switch(c_bus.up.cde.cde[0])
{
case C_BUS_UP_COMMANDE_ETAT_CARTE : { return(c_bus_up_commande_etat_carte(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_CIRCUITS : { return(c_bus_up_commande_etat_circuits(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_ENTREES_AUX : { return(c_bus_up_commande_etat_entrees_aux(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_LEVEL_SENSORS : { return(c_bus_up_commande_etat_level_sensors(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_ENTREES_VOLT : { return(c_bus_up_commande_etat_entrees_volt(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_ENTREES_OW : { return(c_bus_up_commande_etat_entrees_ow(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_ENTREES_BATTERIES : { return(c_bus_up_commande_etat_entrees_batteries(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_ETAT_PGN_NMEA : { return(c_bus_up_commande_etat_pgn_nmea(&c_bus.up.cde, &c_bus.up.reponse)); break; }
case C_BUS_UP_COMMANDE_CONFIG_CARTE : { return(c_bus_up_commande_config_carte(&c_bus.up.cde, &c_bus.up.reponse)); break; }
default : { return (c_bus_up_commande_inconnue(&c_bus.up.cde, &c_bus.up.reponse)); break; }
}
}