NanoPB: Gérer les enums en C++

English Français

Voir aussi : Version C : Comment gérer les enums en C

NanoPB est une implémentation de Protocol Buffers optimisée pour la taille du code, destinée aux systèmes embarqués. Cet article montre comment gérer les types enum en C++ avec NanoPB.

Définition Proto

Créez d’abord un fichier .proto avec des enums :

enums.proto
syntax = "proto3";

package example;

enum Status {
  UNKNOWN = 0;
  OK = 1;
  ERROR = 2;
  BUSY = 3;
}

message EnumMessage {
  Status status = 1;
}

Génération du code NanoPB

Générez le code NanoPB :

generate_nanopb_enums.sh
protoc --nanopb_out=. enums.proto

Cela générera enums.pb.h et enums.pb.c.

Exemple C++

Voici un exemple C++ complet gérant les enums :

enums_example.cpp
#include <stdio.h>
#include "enums.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"

// Fonction utilitaire pour convertir un enum en chaîne
const char* status_to_string(example_Status status) {
    switch (status) {
        case example_Status_UNKNOWN: return "UNKNOWN";
        case example_Status_OK: return "OK";
        case example_Status_ERROR: return "ERROR";
        case example_Status_BUSY: return "BUSY";
        default: return "INVALID";
    }
}

int main() {
    // Tampon pour le message encodé
    uint8_t buffer[64];
    size_t message_length;
    
    // --- ENCODAGE ---
    example_EnumMessage message = example_EnumMessage_init_zero;
    
    // Définir la valeur de l'enum
    message.status = example_Status_OK;
    
    // Créer le flux pour l'encodage
    pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
    
    // Encoder le message
    if (!pb_encode(&ostream, example_EnumMessage_fields, &message)) {
        printf("Échec de l'encodage : %s\n", PB_GET_ERROR(&ostream));
        return 1;
    }
    
    message_length = ostream.bytes_written;
    printf("Encodé %zu octets\n", message_length);
    
    // Afficher le dump hexadécimal des données encodées
    printf("Données encodées : ");
    for (size_t i = 0; i < message_length; i++) {
        printf("%02x ", buffer[i]);
    }
    printf("\n");
    
    // --- DÉCODAGE ---
    example_EnumMessage decoded = example_EnumMessage_init_zero;
    
    // Créer le flux pour le décodage
    pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
    
    // Décoder le message
    if (!pb_decode(&istream, example_EnumMessage_fields, &decoded)) {
        printf("Échec du décodage : %s\n", PB_GET_ERROR(&istream));
        return 1;
    }
    
    // Afficher la valeur décodée
    printf("Valeur décodée :\n");
    printf("  status : %s (valeur enum : %d)\n", 
           status_to_string(decoded.status), decoded.status);
    
    return 0;
}

Commande de compilation

Compilez l’exemple avec nanopb. NanoPB est généralement utilisé en incluant directement les fichiers sources dans votre projet :

compile_enums_example.sh
g++ -o enums_example enums_example.cpp enums.pb.c pb_common.c pb_encode.c pb_decode.c -I.

Note : Les fichiers sources NanoPB (pb_common.c, pb_encode.c, pb_decode.c) doivent être compilés directement avec votre projet. Vous pouvez les obtenir depuis le dépôt GitHub de NanoPB.

Script de test Python

Pour vérifier l’encodage, vous pouvez utiliser la bibliothèque protobuf de Python :

test_enums.py
import enums_pb2

# Lire les données binaires
with open('encoded.bin', 'rb') as f:
    data = f.read()

# Décoder
msg = enums_pb2.EnumMessage()
msg.ParseFromString(data)

print("Valeurs décodées par Python :")
print(f"  status : {enums_pb2.Status.Name(msg.status)}")

D’abord, compilez les définitions protobuf Python :

compile_python_enums.sh
protoc --python_out=. enums.proto

Modifiez ensuite l’exemple C++ pour enregistrer les données encodées dans un fichier :

save_encoded_enums.cpp
// Après l'encodage, ajoutez ceci :
FILE *f = fopen("encoded.bin", "wb");
fwrite(buffer, 1, message_length, f);
fclose(f);

Exemple avec enum dans une instruction switch

Voici un exemple montrant comment utiliser les enums dans des instructions switch :

enums_switch_example.cpp
#include <stdio.h>
#include "enums.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"

void handle_status(example_Status status) {
    printf("Traitement du status : ");
    
    switch (status) {
        case example_Status_UNKNOWN:
            printf("UNKNOWN - État par défaut\n");
            break;
        case example_Status_OK:
            printf("OK - Opération réussie\n");
            break;
        case example_Status_ERROR:
            printf("ERROR - Opération échouée\n");
            break;
        case example_Status_BUSY:
            printf("BUSY - Système occupé\n");
            break;
        default:
            printf("INVALID - Valeur enum inconnue\n");
            break;
    }
}

int main() {
    uint8_t buffer[64];
    size_t message_length;
    
    // Tester toutes les valeurs de l'enum
    example_Status test_values[] = {
        example_Status_UNKNOWN,
        example_Status_OK,
        example_Status_ERROR,
        example_Status_BUSY
    };
    
    for (size_t i = 0; i < 4; i++) {
        example_EnumMessage message = example_EnumMessage_init_zero;
        message.status = test_values[i];
        
        pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
        
        if (!pb_encode(&ostream, example_EnumMessage_fields, &message)) {
            printf("Échec de l'encodage : %s\n", PB_GET_ERROR(&ostream));
            return 1;
        }
        
        message_length = ostream.bytes_written;
        
        example_EnumMessage decoded = example_EnumMessage_init_zero;
        pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
        
        if (!pb_decode(&istream, example_EnumMessage_fields, &decoded)) {
            printf("Échec du décodage : %s\n", PB_GET_ERROR(&istream));
            return 1;
        }
        
        handle_status(decoded.status);
    }
    
    return 0;
}

Points clés

Quand utiliser les enums

Sortie attendue

enums_expected_output.txt
Encoded 2 bytes
Encoded data: 08 01 
Decoded value:
  status: OK (enum value: 1)

Sortie attendue (exemple switch)

enums_switch_expected_output.txt
Handling status: UNKNOWN - Default state
Handling status: OK - Operation successful
Handling status: ERROR - Operation failed
Handling status: BUSY - System busy

Plus d’articles sur NanoPB


Check out similar posts by category: Embedded, C/C++, Protocol Buffers