Question

J'envoie / réception de données sur une ligne série sous Linux et je voudrais trouver le délai entre les caractères.

Modbus utilise un retard de caractères 3.5 pour détecter les limites de trame de message. S'il y a plus d'un retard de 1,5 caractère, la trame de message est déclarée incomplète.

J'écris un programme rapide en C qui est essentiellement

fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
// setup newtio
....
tcsetattr(fd, TCSANOW, &newtio);
for(;;) {
    res = read(fs, buf, 1);
    if (res > 0) {
        // store time in milliseconds?
        //do stuff
    }
}

Y at-il un moyen de mesurer le temps ici? Ou dois-je regarder la récupération de données à partir de la ligne série d'une manière différente?

J'ai aussi essayé accrochage dans SIGIO pour obtenir un signal chaque fois qu'il ya des données mais il me semble d'obtenir des données 8 octets à la fois.

(oui, je sais qu'il existe des bibliothèques modbus mais je veux l'utiliser dans d'autres applications)

Était-ce utile?

La solution

est MODbus comme beaucoup de vieux protocoles et déteste vraiment du matériel moderne.

La raison pour laquelle vous obtenez 8 octets à la fois est: Votre PC a un (au moins) FIFO série de 16 octets sur réception et de transmission, dans le matériel. La plupart sont plus ou 64 octets.

est possible de dire au dispositif de UART à temps et émettre un reçu d'interruption après un certain nombre de fois char.

Le niveau de déclenchement est réglable, mais le pilote de bas niveau le met « intelligemment ». essayez le mode à faible latence en utilisant setserial) Vous pouvez jouer avec le code dans le pilote de série si vous devez. Google il (MATURE avertissement contenu) il n'est pas assez.

de sorte que la routine est en pseudocode

int actual=read (packet, timeout of 1.5 chars)

look at actual # of received bytes

if less than a packet, has issues, discard.

pas grand.

Autres conseils

La réponse est simple ... vous ne pouvez pas (non sans vous écrire propre pilote de série)!

Si vous écrivez un MODBUS maître il y a un peu d'espoir: Vous pouvez détecter la fin d'une réponse esclave en attente any de temps (à condition que leur plus longue que 3.5) sans caractères quoi que ce soit de réception (select (2) peut vous aider ici), ou par analyse de la réponse à la volée, comme vous l'avez lu (beaucoup moins de temps la deuxième déchets de méthode). Vous devez également faire attention à attendre au moins 3,5 personnages avant de regarder de transmettre une nouvelle demande, après avoir reçu la réponse à la demande précédente. « Au moins » est important ici! En attendant plus n'a pas d'importance. Subir fait.

Si vous une écriture MODBUS esclave alors vous êtes de chance . Il vous suffit de ne peut pas faire fiable Linux depuis l'espace utilisateur. Vous devez vous écrire du pilote série.

BTW, ce n'est pas la faute de Linux. Cela est dû à la stupidité incroyable de la méthode de cadrage de MODBUS.

Je pense que vous allez sur ce dans le mauvais sens. Il est construit dans le mécanisme pour faire en sorte que les personnages viennent tous ensemble.

En fait, vous allez vouloir utiliser ioctl() et définir les paramètres de VMIN et VTIME de façon appropriée. Dans ce cas, il semble que vous voudriez VMIN (nombre minimum de caractères dans un paquet) à 0 et VTIME (montant minimum de temps entre les caractères à 15 (ils sont dixièmes de secondes).

Certains vraiment Code exemple de base:

struct termio t;
t.c_cc[ VMIN ] = 0;
t.c_cc[ VTIME ] = 15;
if (ioctl( fd, TCSETAW, &t ) == -1)
{
    printf( msg, "ioctl(set) failed on port %s. Exiting...", yourPort);
    exit( 1 );
}

Pour ce faire, avant votre open() mais avant read(). Voici quelques liens que j'ai trouvé follement utile:

Guide de programmation série

Comprendre Vmin et Vmax

J'espère que au moins vous aide / points dans la bonne direction, même si ce n'est pas une réponse parfaite pour votre question.

Vous ne pouvez pas utiliser les délais d'attente. Sur les taux de transmission plus élevés 3.5 délai d'attente de caractères signifie quelques millisecondes, voire des centaines de microsecondes. Ces délais d'attente ne peuvent pas être traitées dans l'espace utilisateur Linux.

Du côté client, ce n'est pas un gros problème car Modbus ne pas envoyer des messages asynchrones. Il est donc à vous de ne pas envoyer 2 messages consécutifs dans 3,5 délai d'attente de caractères.

Du côté du serveur, le problème est que si vos clients ont un délais d'attente de réponse extrêmement court et Linux est trop occupé, vous ne pouvez pas écrire une solution d'encadrement pare-balles. Il y a une chance que la fonction read () retournera plus d'un paquet. Voici (un peu artificiel) par exemple.

  1. Client écrit un paquet au serveur. Délai d'attente est disons 20 ms.

  2. Disons que Linux est actuellement très occupé, donc le noyau ne se réveille pas votre fil à moins de 50 ms suivant.

  3. Après 20 ms client détecte qu'il n'a pas reçu de réponse de sorte qu'il envoie un autre paquet au serveur (peut-être le précédent en vouloir un).

  4. Si Linux se réveille votre fil de lecture après 50 ms, fonction de lecture () peut obtenir 2 paquets ou même 1 et la moitié en fonction de combien d'octets ont été reçus par le pilote de port série.

Dans ma mise en œuvre que j'utilise une méthode simple qui tente d'analyser les octets sur la volée - première détection du code de fonction, puis j'essaie de lire tous les octets restants pour une fonction spécifique. Si je reçois un paquet et demi, je parse que le premier et octets restants sont laissés dans la mémoire tampon. Si plusieurs octets viennent dans un court délai d'attente je les ajoute et essayer d'analyser, sinon je les mettre au rebut. Ce n'est pas une solution parfaite (par exemple des sous-codes pour la fonction 8 ne dispose pas d'une taille fixe) mais depuis MODBUS RTU n'a pas de caractères STX ETX, il est le meilleur que je pouvais trouver.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top