Forum: PC-Programmierung serielle Kommunikation


von Machine (Gast)


Lesenswert?

Hi, für die serielle Schnittstelle verwende ich einen sogenannten 
Zwischenpuffer.
1
int CQUEUE::write_que_str(char* str)
2
{
3
  int i;
4
  i = (len + ri - wi - 1) % len; //i = space in buffer
5
  if (i>0) //if enough space
6
    { 
7
    sprintf(strbuf,"%s",str); 
8
      return(1); //successfully transmitted one int
9
    }
10
  else
11
    return(0);
12
}
13
14
int CQUEUE::read_que_str(char* str)
15
{
16
  int i;
17
  i = (len - ri + wi) % len; //i = contents in buffer
18
  if (i>0) //if enough space
19
    { 
20
    sprintf(str,"%s",strbuf);
21
      return(1); //successfully transmitted one int
22
    }
23
  else
24
    return(0);
25
}

Wenn ich dies so mache, dann stürzt mein System ab.
Kann ich dies mit dem QUEUE auch noch anders lösen? Gibt es da schon 
fertige Methoden in C++?

von Machine (Gast)


Lesenswert?

Das mit dem QUEUE bekomme ich nicht gebacken! Brauche dringend 
Unterstützung.

Danke im voraus!

von Stefan (Gast)


Lesenswert?

Wenn keiner antwortet, ist vielleicht

1/ deine Ungeduld zu gross
2/ das Problem zu ungenau beschrieben
3/ das Problem zu komplex

Ich vermute die Punkte 1+2 treffen zu.

Du könntest z.B. angeben

* aus welcher Library sich dein CQUEUE stammt. Dann könnte man 
nachsehen, woher die obskuren Variablen len, ri, wi und strbuf stammen 
und was sie bedeuten. Ist strbuf der Anfang des CQUEUE Puffers oder die 
Adresse der ersten freien Position in der Queue? Wenn letzteres - wer 
erhöht strbuf nach der sprintf Aktion?

* wie du die Klasse CQUEUE im Hauptprogramm initialisierst.

* wie gross du den Puffer str anlegst und ob sprintf(str,"%s",strbuf); 
den zum Platzen bringen kann.

Es scheint sich bei strbuf um einen Ringpuffer zu handeln (ri, wi 
könnten ReadIndex und WriteIndex) sein. In dem Fall kannst du nicht 
davon ausgehen, dass der freie Speicher linear fortlaufend angeordnet 
ist, d.h. du darfst kein sprintf verwenden. Du musst eine Kopieraktion 
benutzen, die einzelne Zeichen kopiert (wi erhöht) und beim erreichen 
von len bei 0 am Pufferanfang bis max. ri (-1 fürs Nullbyte) 
weitermacht.

von Karl H. (kbuchegg)


Lesenswert?

> Es scheint sich bei strbuf um einen Ringpuffer zu handeln (ri, wi
> könnten ReadIndex und WriteIndex) sein. In dem Fall kannst du nicht
> davon ausgehen, dass der freie Speicher linear fortlaufend angeordnet
> ist, d.h. du darfst kein sprintf verwenden. Du musst eine Kopieraktion
> benutzen, die einzelne Zeichen kopiert (wi erhöht) und beim erreichen
> von len bei 0 am Pufferanfang bis max. ri (-1 fürs Nullbyte)
> weitermacht.

@Machine

Was auch immer wieder gut kommt:

Sich eine Zeichnung machen!
Und dann mal ein paar Beispiele am Papier durchspielen!

von Machine (Gast)


Angehängte Dateien:

Lesenswert?

Mit den Funktionen kann ich bereits Integerwerte übergeben und wieder 
lesen.

>>read_que_int(int* value)
>>write_que_int(int value)

Für Strings müsste ich dies vom Prinzip auch so realisieren.
(FIFO Prinzip)

von Machine (Gast)


Lesenswert?

Definitionen in der Headerdatei "queue.h"

#define QSIZE   264         // queue length

int*  buf;     // pointer to fifo-buffer
int   len;     // length of buffer
int   ri;      // read_index
int   wi;      // write_index
int   read_que_int(int* value);
int   write_que_int(int value);
void  Clear(void);                  // clears unconditionally the queue
int   get_que_space();
int   que_contents();

von Karl H. (kbuchegg)


Lesenswert?

Der SChlüssel zuum Ganzen liegt darin, dass du in deinem
Ringbuffer (und genau darum handelt es sich), keine
Strings bearbeiten musst, sondern einzelne Zeichen.

Um einen String einzufügen, fügst du also alle Zeichen
die den String bilden ein.

angenommen deine Queue hat eine Länge von 8 Zeichen:


  +---+---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 0
  wi = 0

und jetzt soll der String "Test" eingefügt werden.

  dann muss das Ergebnis so aussehen:

  +---+---+---+---+---+---+---+---+
  | T | e | s | t | \0|   |   |   |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 0
  wi = 5

und du erreichst es, indem du aus dem übergebenen String
Zeichen für Zeichen ausliest und in den Buffer überführst.
Warum Zeichen für Zeichen?

Nun nimm mal an aus der Queue wurde der String bereits
ausgelesen. Dann ist die Situation diese:

  +---+---+---+---+---+---+---+---+
  | T | e | s | t | \0|   |   |   |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 5
  wi = 5

und jetzt fügst du den Test "Hurra" ein (6 Zeichen)

Dann sieht das Ergebnis so aus:

  +---+---+---+---+---+---+---+---+
  | r | a | \0| t | \0| H | u | r |
  +---+---+---+---+---+---+---+---+

  len = 8
  ri = 5
  wi = 3

Beachte wie der Text "Hurra" an den vorhergehenden und noch
im Speicher befindlichen Text "Test" angefügt ist und bei
Erreichen des Bufferendes am Bufferanfang weitergeschrieben
wird. Daher kannst du nicht mit irgendwelchen Standard String
Funktionen arbeiten, sondern musst selbst dafür sorgen, dass
dieser Wrap around gemacht wird.

Sagte ich nicht: Nimm dir Papier und Bleistift und mal
dir die Situationen auf. Dann schreibst du dein Programm
und spielst hinterher selbst Computer und simulierst dein
Programm auf dem Papier durch. Sehr lehrreich!



von Machine (Gast)


Lesenswert?

Danke für die Hilfe!

Das Problem ist ja, das mein Puffer vom Typ int ist.
>>int* buf;

Den möchte ich beibehalten. Quasi ist mein buf mein Ringpuffer.

In der folgenden Funktion übergebe ich einen String (cstring).
Nach der if(i>0) Bedingung weiss ich nicht wie ich das ganze jetzt in 
den
Puffer bekomme.
1
int CQUEUE::write_que_str(char* cstring)
2
{ 
3
  int i;
4
  i = (len + ri - wi) % len; //i = contents in buffer
5
6
  if (i>0) //if enough space
7
    { 
8
      ?????
9
           wi = (wi + 1) % len;  //increment write index 
10
     return(1); //successfully transmitted one int
11
    }
12
  else
13
    return(0);
14
}

von Machine (Gast)


Lesenswert?

Ein Integer setzt sich aus zwei Character zusammen.
2 x 8Bit = Integer

wenn z.B. wi = 1 ist , dann bedeutet das ja das eigentlich zwei 
Character vorhanden sind oder?

von Stefan (Gast)


Lesenswert?

Korrekt. Du kannst jetzt auf zwei Arten weitermachen

1/ Du verschwendest pro Zeichen im String ein Byte. Du erweiterst 
einfach über einen Cast ein char (vom String) zu einem int (im Puffer). 
Nachteil: Das eine Erweiterungsbyte pro Nutzzeichen frisst den halben 
Speicher.

2/ Du setzt aus je zwei Zeichen im String ein int zusammen. (Kleiner) 
Nachteil: Du musst dir was überlegen, wie du das Stringende erkennst 
(Nullbyte kann im Highbyte oder im Lowbyte stecken) und du brauchst u.U. 
exakt ein Erweiterungsbyte (wenn strlen(str) ungerade ist).

von Karl H. (kbuchegg)


Lesenswert?

3/ Du wirfst die unsinnige Forderung, dass du den Speicher
   weiterhin als int halten willst über Bord und machst das
   vernünftig: Der Buffer ist ein Array von unsigned char.
   Dieselbe Technik, mit der ein String letztendlich in
   diesem Buffer landet, wird dann auch auf int angewendet.
   Und dieselbe Technik nimmt man dann auch für double,
   float, long, Strukturen, etc...

Auf dieser low level Ebene gibt es sinnvollerweise nur noch
Bytes als kleinsten gemeinsamen Nenner aller überhaupt
möglichen Datentypen. Wenn für einen Datentyp mehrere Bytes
benötigt werden, dann ist das halt so, dann werden mehrere
Bytes pro Eintrag benötigt.

von Machine (Gast)


Lesenswert?

Guten Morgen Karl heinz Buchegger,

ich weiss nun echt nicht wie dies jetzt realisierne könnte.
1
//-------------------------------------------------------------------------
2
int CQUEUE::write_que_int(int value)
3
{
4
  int i;
5
  i = (len + ri - wi - 1) % len; //i = space in buffer
6
  if (i>0) //if enough space
7
    { 
8
      buf[wi] = value;    //tranfer value
9
      wi = (wi + 1) % len;  //increment write index 
10
      return(1); //successfully transmitted one int
11
    }
12
  else
13
    return(0);
14
}

Headerdatei:

>>int*  buf; // pointer to fifo-buffer

umändern in

>>char* buf

Das mit der Funktion macht mir noch große Probleme.
Wie könnte man jetzt einen String einlesen bzw. int?
1
//-------------------------------------------------------------------------
2
int CQUEUE::write_que_str(char* text)
3
{
4
  int i;
5
  i = (len + ri - wi - 1) % len; //i = space in buffer
6
  if (i>0) //if enough space
7
    { 
8
      buf[wi] = value;    //tranfer value
9
      wi = (wi + 1) % len;  //increment write index 
10
      return(1); //successfully transmitted one int
11
    }
12
  else
13
    return(0);
14
}

von Karl H. (kbuchegg)


Lesenswert?

Machine wrote:
> Headerdatei:
>
>>>int*  buf; // pointer to fifo-buffer
>
> umändern in
>
>>>char* buf

Ja.
Natürlich auch den malloc anpassen :-)

>
> Das mit der Funktion macht mir noch große Probleme.
> Wie könnte man jetzt einen String einlesen bzw. int?
>
>
1
> //-------------------------------------------------------------------------
2
> int CQUEUE::write_que_str(char* text)
3
> {
4
>   int i;
5
>   i = (len + ri - wi - 1) % len; //i = space in buffer
6
>   if (i>0) //if enough space

Das kann natürlich nicht so bleiben.
Wenn i die Anzahl der noch freien Bytes im Speicher
angibt, dann passt der String logischerweise nur dann
in diesen Speicher, wenn für jedes Zeichen im String
(+ das obligate '\0' Zeichen) ein Byte frei ist.

Die Anzahl der Zeichen in einem String kriegt man
mit strlen(). Nach 1 dazu für das '\0' Zeichen.
Ergo
1
    int textLen = strlen(text) + 1;
2
    if( textLen < i )   // es ist genug Platz

>
1
   {
2
3
>       buf[wi] = value;    //tranfer value
4
>

Nachdem text ein String (also eine Abfolge von Zeichen) ist
wird das mit einer Zuweisung wohl nichts werden. (Man kann
Arrays nicht zuweisen. Bei dir würde es auch nichts bringen
wegen dem Wrap.
(Hab ich eigentlich schon mal erwähnt, dass man sich solche
Situationen aufzeichnen sollte ?)
1
       for( i = 0; i < textLen; ++i ) {
2
         buf[wi] = text[i];     // Ein Zeichen umkopieren
3
4
         wi = ( wi + 1 ) % len;  // Und den Zielindex um 1
5
                                 // erhöhen. Dabei aber aufpassen
6
                                 // dass er beim Erreichen des Buffer-
7
                                 // endes bei 0 weitermachen muss.
8
      }

>
1
       wi = (wi + 1) % len;  //increment write index
Das brauchts dann nicht mehr. wi ist schon innerhalb der Schleife
korrekt erhöht worden.

>
1
      return(1); //successfully transmitted one int
2
>     }
3
>   else
4
>     return(0);
5
> }
6
>

Ist doch nicht so schwer.
Nochmal: Mal dir einen Buffer auf. Mal dir einen String auf
und spiele am Papier durch, was zu passieren hat!
Das ist kein Scherz!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.