DShot bidirectionnel : décodage de la réponse eRPM (C)

Écrit par

dans

/* Table GCR inverse : code 5 bits -> quartet, -1 si code invalide */
static const int8_t gcr_inv[32] = {
    -1, -1, -1, -1, -1, -1, -1, -1, -1,  9, 10, 11, -1, 13, 14, 15,
    -1, -1,  2,  3, -1,  5,  6,  7, -1,  0,  8,  1, -1,  4, 12, -1
};

/* Décode une réponse eRPM de 21 bits (bit de départ en tête, poids fort d'abord).
   Renvoie la vitesse en eRPM, 0 moteur arrêté, -1 si la trame est invalide. */
int32_t dshot_reponse_erpm(uint32_t brut21)
{
    uint32_t gcr = (brut21 ^ (brut21 >> 1)) & 0xFFFFF;  /* transitions -> 20 bits GCR */
    uint32_t trame = 0;
    for (int q = 3; q >= 0; q--) {
        int8_t n = gcr_inv[(gcr >> (q * 5)) & 0x1F];
        if (n < 0)
            return -1;
        trame = (trame << 4) | (uint32_t)n;
    }
    uint32_t x = trame ^ (trame >> 8);
    x ^= x >> 4;
    if ((x & 0x0F) != 0x0F)          /* le XOR des 4 quartets doit valoir 0xF */
        return -1;
    uint32_t v = trame >> 4;         /* 12 bits : eee mmmmmmmmm */
    uint32_t periode_us = (v & 0x1FF) << (v >> 9);
    if (periode_us == 0 || periode_us >= 65408u)
        return 0;                    /* période maximale : moteur arrêté */
    return (int32_t)(60000000u / periode_us);
}