0
votes

Comment envoyer une chaîne hexadécimale au port série?

Je développe un programme de communication série pour envoyer et recevoir des données entre le PC hôte (Linux) et le microcontrôleur. Maintenant, je dois envoyer des octets hexadécimaux de données au MCU. Alors, comment puis-je convertir mes données de chaîne de tampon en chaîne hexadécimale sans utiliser sprint / printf afin que l'utilisateur envoie une chaîne comme "AA12CDFF1000001201" au lieu de "\ xAA \ x12 \ xCD \ xFF \ x10 \ x00 \ x00 \ x12 \ x01" à MCU. J'ai également vu envoyer un hexadécimal au port série mais il pas utile car il dit que je peux convertir une chaîne en hexadécimal en utilisant sprintf mais ici, dans mon cas, je ne veux pas utiliser sprinf. En gros, ce que je veux, c'est: Si l'utilisateur donne input = "AA12CDFF1000001201" Je dois le convertir au format suivant "\ xAA \ x12 \ xCD \ xFF \ x10 \ x00 \ x00 \ x12 \ x01" puis l'écrire sur le port série.

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
void main()
{
int fd;
fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY);
char buff[]="\xAA\x12\xCD\xFF\x10\x00\x00\x12\x01";
write(fd, buff, sizeof(buff));
close(fd);
}    


13 commentaires

* dans mon cas, je ne veux pas utiliser sprinf pour une raison quelconque. * quelle est la raison? Pourquoi enverriez-vous même 9 octets en utilisant une chaîne de 18 octets?


J'envoie 9 octets de données hexadécimales = "\ xAA \ x12 \ xCD \ xFF \ x10 \ x00 \ x00 \ x12 \ x01", ce qui est fastidieux pour l'utilisateur à saisir donc je dois le rendre simple pour l'utilisateur afin que quelqu'un tape simplement " AA12CDFF1000001201 "comme une application de terminal série normale le fait lorsque l'utilisateur saisit simplement une chaîne normale. @ Tilz0R


Vous avez donc échoué avec votre question à la première place. Vous voulez convertir une chaîne en octets, pour cela vous n'avez PAS du tout besoin de sprintf. Ce n'est même pas possible de le faire.


Ok, je l'ai changé. @ Tilz0R


Je vous ai donné une réponse ci-dessous.


@ raj123, n'est-ce pas ce que vous voulez un moyen d'insérer automatiquement \ x dans l'entrée utilisateur?


Oui, cela fonctionnera, je peux prendre une chaîne comme entrée et insérer \ x au début de tous les deux caractères, puis l'envoyer à mcu @hessamhedieh


@ raj123, alors quelle est la vraie question? cherchez-vous un moyen d'insérer \ x dans une chaîne? ou c'est quelque chose d'autre que je ne peux pas voir?


Oui, insérer \ x dans la chaîne m'aidera @ hessamhedieh


Votre envoi (...) ne sait rien du descripteur fd. Comment cela se compile-t-il? Vous avez également utilisé "envoyer", mais c'est aussi un nom de routine de bibliothèque; mauvaise pratique.


Êtes-vous absolument sûr que le format d'entrée attendu est une chaîne avec quatre caractères par octet, c'est-à-dire un littéral \ x suivi des deux chiffres hexadécimaux? Peut-être que vous cherchez à envoyer uniquement les octets réels (par exemple, juste X au lieu de \ x58 ), mais les spécifications que vous avez lues utilisaient \ x comme une échappatoire pour eux?


raj123, Voyez-vous maintenant un problème avec sizeof (buff) ? C'est la taille d'un pointeur, pas la taille du tableau du code appelant. Cette approche ne fonctionnera pas.


\ x est simplement utilisé pour envoyer une valeur hexadécimale plutôt qu'une chaîne. @Arkku


5 Réponses :


0
votes

Conversion de chaîne en octets
Output: 121314005A  

Si vous exécutez le code: Tester la sortie [2] = 13

Conversion d'octets en string

Quelque chose comme ça. Le but est de traduire chaque quartet de chaque octet en caractère. Cela signifie que la longueur de sortie est le double de la taille de votre tampon initial.

#include <stdio.h>
#include <string.h>
#include <stdint.h>

/* Output array */
char output[128];

/* Dummy input data array */
char data[] = {0x12, 0x13, 0x14, 0x00, 0x5A};

/* Convert each nibble to char */
char num2char(uint8_t num) {
    if (num < 10) {
        return num + '0';
    } else if (num < 16) {
        return num - 10 + 'A';
    }
}

int
main() {
    size_t i;
    printf("Hello World\r\n");

    /* Process all bytes */
    for (i = 0; i < sizeof(data) / sizeof(data[0]); i++) {
        /* Generate it twice, for high and low nibble */
        output[2 * i] = num2char((data[i] >> 4) & 0x0F);
        output[2 * i + 1] = num2char((data[i]) & 0x0F);
    }
    /* Trailing zero for string */
    output[2 * i] = 0;

    printf("Output: %s\r\n", output);

    return 0;
}

Lorsque vous exécutez le code:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

/* Dummy input */
char input[] = "11121314151617181920";
uint8_t output[32];

/* Convert input char to int */
uint8_t
char2byte(char c) {
    if (c >= '0' && c <= '9') {
        return c - '0';
    } else if (c >= 'A' && c <= 'F') {
        return c - 'A' + 10;
    } else if (c >= 'a' && c <= 'f') {
        return c - 'a' + 10;
    }
    return 0;
}

int
main() {
    size_t len;

    /* String must be even */
    len = strlen(input);
    if (len & 1 == 0) {

    }
    /* Process all inputs, 2 chars for single byte */
    for (size_t i = 0; i < len / 2; ++i) {
        output[i] = char2byte(input[2 * i]) << 4;
        output[i] |= char2byte(input[2 * i + 1]);
    }

    /* Test, expected is 0x13 */
    printf("Test output[2] = %02X\r\n", (unsigned)output[2]);

    return 0;
}

2 commentaires

Votre chaîne en octet n'est pas ce dont j'avais besoin dans mon code.Je dois écrire cette commande sur le port série "\ xAA \ x12 \ xCD \ xFF \ x10 \ x00 \ x00 \ x12 \ x01" au lieu de le rendre convivial entrée comme celle-ci "AA12CDFF1000001201"


Alors votre question est mûre pour être close.



0
votes

Jetez un œil à ceci, pas un code propre mais devrait faire le travail

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void hexify(const char *input, char *output)
{
    int i = 0;
    int o = 0;
    while(1)
    {
        if(input[i] == 0) break; 
        output[o++] = '\\';
        output[o++] = 'x';
        output[o++] = input[i++];
        if(input[i] == 0) break; 
        output[o++] = input[i++];
    }
    output[o] = 0;
}

 int main()
 {
     char test[]="112233AA"; //user input
     if((strlen(test) % 2) && strlen(test) != 1)
         printf("Input is not in correct format");
     else
     {
         char *out = malloc(2 * strlen(test) + 1);
         hexify(test, out);
         printf("%s", out);
         free(out);//dont forget this
     }
     return 0;
 }


0 commentaires

0
votes

Voulez-vous quelque chose comme ça:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char inbuff[]="AA12CDFF1000001201";
    char *outbuff;

    if (strlen(inbuff)%2) {
            printf("error : strlen is odd");
            exit(1);}
    outbuff=malloc((strlen(inbuff)*2+1)*sizeof(char));
    for (int strin=0,strout=0;strin<strlen(inbuff);) {
        outbuff[strout++]='\\';
        outbuff[strout++]='x';
        outbuff[strout++]=inbuff[strin++];
        outbuff[strout++]=inbuff[strin++];
    }
    outbuff[strlen(inbuff)*2]='\0';
    printf("%s\n",outbuff);
    return 0;
}


11 commentaires

pourquoi il devrait y avoir un problème avec une longueur de chaîne impaire?


@hessamhedieh Si chaque octet est supposé être représenté par deux chiffres hexadécimaux, une longueur impaire indique que ce n'est pas le cas et qu'il n'est pas possible de savoir quel octet manque un nybble. (Votre réponse suppose que c'est la dernière, mais s'il s'agit d'une entrée de l'utilisateur, il aurait pu commettre l'erreur n'importe où.)


J'ai supposé que le nombre de caractères devait être pair car 1 octet correspond à deux chiffres hexadécimaux. Avec un nombre pair de caractère, je ne sais pas où ajouter un 0 supplémentaire. Au début ou à la fin de inbuff? Peut-être, @ raj123 pourrait-il préciser. Dans votre code, avec un nombre pair de caractères, vous obtiendrez \ xAA \ x1F \ xE (par exemple). Que signifie 0E ou E0?


@Arkku, bien sûr que vous avez raison, mais lorsque user joue un rôle, les choses se passent, que se passe-t-il si l'utilisateur veut simplement envoyer le numéro 5, par exemple, le forcer à écrire 05 mènera à de nombreux problèmes concernant les utilisateurs se plaignant que l'application ne fonctionne pas ou n'est pas conviviale.


@ Stef1611, si vous avez un test qui provoque l'échec de mon code, n'hésitez pas à le fournir, mais AFAICT, mon code gère les scénarios pairs et impairs sans problème.


@hessan a hedied. Je n'ai pas dit que votre code ne gère même pas les caractères. Je viens de dire que cela pourrait poser un problème si l'utilisateur entre une chaîne d'entrée avec un nombre pair de caractères. Un octet correspond à deux chiffres hexadécimaux. C'est juste un contrôle de bon sens. Sinon, notre code est très similaire. Et le vôtre est meilleur parce que vous écrivez une fonction pour le faire.


@hessamhedieh Si l'entrée est 123 , votre cas spécial d'octet impair l'envoie comme \ x12 \ x3 alors que l'utilisateur peut s'attendre à \ x1 \ x23 . (Compte tenu des valeurs, ce dernier serait 0x123 qui correspond à ce qu'ils ont écrit, et vous enverriez 0x1203 , qui insère effectivement un zéro au milieu.) Je voudrais soutiennent que la seule fois où cette "caractéristique" est acceptable, c'est lorsque l'entrée est exactement à 1 chiffre, c'est-à-dire que 1 devient \ x1 . Si l'entrée est normalement une chaîne multi-octets, vaut-il la peine d'introduire ce cas spécial surprenant pour enregistrer 1 caractère?


@hessamhedieh Quant à "les forcer à taper 05" qui n'est pas convivial, si nous parlons d'un programme où l'utilisateur tape des données sous forme de chiffres hexadécimaux dans un terminal, je penserais que l'utilisateur est quelqu'un qui veut s'assurer que ceux-ci les octets hexadécimaux sont envoyés correctement (et pourraient donc avoir intérêt à être protégés du programme essayant de deviner ce qu'ils signifient), et non à quelqu'un qui veut appuyer sur une touche de moins. =) En fait, si j'étais moi-même un tel utilisateur, je préférerais que les octets soient séparés par des espaces.


@Arkku, votre point n'est pas discutable, je dois admettre que je n'y ai pas pensé, j'ai édité ma réponse


@ raj123 Pourriez-vous clarifier ce point? Est-il possible d'avoir une longueur de chaîne impaire? Si oui, pouvez-vous confirmer que la chaîne d'entrée: "123" doit être convertie en chaîne de sortie "\ x01 \ 23"?


@ Stef1611 Oui pour une longueur de chaîne impaire, zéro peut être ajouté au début de la chaîne de sortie.



1
votes

Après la discussion fructueuse avec Hessam et Arkku, une nouvelle version du code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* str2hexstr(char* inbuff) {

    char *outbuff;

    if (strlen(inbuff)%2) {
        outbuff=malloc((strlen(inbuff)*2+3)*sizeof(char));
        outbuff[strlen(inbuff)*2+2]='\0'; }
    else {
        outbuff=malloc(strlen(inbuff)*2+1*sizeof(char));
        outbuff[strlen(inbuff)*2]='\0'; }

    for (int strin=0,strout=0;strin<strlen(inbuff);) {
        outbuff[strout++]='\\';
        outbuff[strout++]='x';
        outbuff[strout++]=(!strin&&strlen(inbuff)%2)?'0':inbuff[strin++];
        outbuff[strout++]=inbuff[strin++];
    }
    return(outbuff);
}
int main()
{
    char inbuff1[]="123",inbuff2[]="1234";
    char *outbuff;

    outbuff=str2hexstr(inbuff1);
    printf("%s\n",outbuff);
    free(outbuff);
    outbuff=str2hexstr(inbuff2);
    printf("%s\n",outbuff);
    free(outbuff);
    return 0;
}


6 commentaires

Lorsque je donne la chaîne d'entrée: "12345678901", je reçois un caractère indésirable à la fin de la chaîne de sortie: \ x01 \ x23 \ x45 \ x67 \ x89 \ x01� @ Stef1611


pour chaque chaîne d'entrée de 11 caractères, il affiche le caractère indésirable � à la fin de la chaîne de sortie. @ Stef1611


@ raj123: Vous devez clarifier davantage votre question. Cela renvoie littéralement "\ x01 \ x23 \ x45 ..." ; cela ne semble pas être ce qui a été demandé dans la question. \ 01 est une constante de caractère et je m'attendrais à ce que la sortie requise soit un seul caractère avec le modèle de bits 00000001, et non quatre caractères.


La question @Clifford concerne l'envoi de la chaîne hexadécimale "\ x01 \ xAA" au port série.


@ raj123: Assez juste (bien qu'inhabituel), mais votre clarification doit être ajoutée à la question et non dans un commentaire. Le fragment de code dans votre question est trompeur car ce n'est pas ce que contient buff [] .


@Clifford ok je vais modifier ma question de manière appropriée.



0
votes

Comment puis-je convertir mes données de chaîne de mémoire tampon en chaîne hexadécimale ... afin que l'utilisateur envoie ...?

give input = "AA12CDFF1000001201" Je dois le convertir au format suivant "\ xAA \ x12 \ xCD \ xFF \ x10 \ x00 \ x00 \ x12 \ x01" puis l'écrire sur le port série.

Lorsque le stockage intermédiaire dans un tampon n'est pas nécessaire, c'est assez simple.

Convertit 2 caractères 1 de la chaîne d'origine en un time à un octet, en écrivant chaque octet par itération.

void write_hex_string(char *hs) {
  char *pair  = hs;
  size_t length = 0;
  while (isxdigit(pair[0]) && isxdigit(pair[1])) {
    char buf[3] = { pair[0], pair[1], '\0' };
    hs[length++]  = (unsigned char) strtol(buf, 0, 16);
    pair += 2;
  }
  write(fd, hs, length);
}

Exemple d'utilisation

write_hex_string("AA12CDFF1000001201");

Si le code peut changer la chaîne d'origine dans le cadre du processus, la vie est également facile. Comme il existe un emplacement pratique pour stocker la conversion.

#include <ctype.h>

void write_hex_string(const char *hs) {
  while (isxdigit(hs[0]) && isxdigit(hs[1])) {
    char buf[3] = { hs[0], hs[1], '\0' };
    unsigned char value = (unsigned char) strtol(buf, 0, 16);
    write(fd, &value, sizeof value);
    hs += 2;
  }
}

1 Tant que les 2 caractères sont tous les deux des chiffres hexadécimaux: [' 0 '-' 9 ',' A '-' F ',' a '-' f '].


0 commentaires