Forum: PC-Programmierung FT232 String senden/empfangen


von Mark L. (Gast)


Lesenswert?

Hallo, ich bin auf der Suche nach einer Library für den FT232.

Ein Zeichen senden kann ich (funktioniert auch), aber für mehr reichen 
meine Kenntnisse nicht. Deshalb suche ich einen Codeausschnitt bzw. eine 
Library die einen String senden und empfangen kann. Ich programmieren in 
Codeblocks unter Win7 x64 / mit C++.

Vielen Dank für etwaige Hilfe

von Karl H. (kbuchegg)


Lesenswert?

> Ein Zeichen senden kann ich (funktioniert auch), aber für mehr reichen
meine Kenntnisse nicht.

Du kannst 1 Zeichen senden, hast aber Probleme mit Strings?

Das ergibt keinen Sinn. Einen String sendet man, indem man 1 Zeichen 
nach dem anderen sendet. Das kannst du aber offenbar. Wo liegt daher das 
Problem?

1
void sendString( const char* string )
2
{
3
  while( *string )
4
    sendCharacter( *string++ );
5
}

wenn du nicht mit ollen C-style Strings rummachen willst (was ich 
verstehen kann), musst du dir halt was Gleichwertiges mit deiner 
favorisierten String-Klasse einfallen lassen.

von Mark L. (Gast)


Lesenswert?

Genauer gesagt sind es mehrere Probleme. Der Null Teminierte String muss 
dieser funktion übergeben werden.Daher muss er konvertiert werden jedoch 
weiß ich leider nicht wie?

FT_STATUS FT_Write (FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD 
dwBytesToWrite,LPDWORD lpdwBytesWritten)

Parameters:

ftHandle Handle of the device.
lpBuffer Pointer to the buffer that contains the data to be written to 
the device.
dwBytesToWrite Number of bytes to write to the device.
lpdwBytesWritten Pointer to a variable of type DWORD


Das lesen ist für mich noch weit komplizierter.Zuerst muss die folgende 
Funktion richtig parametriert werde.

FT_STATUS FT_SetEventNotification (FT_HANDLE ftHandle, DWORD 
dwEventMask, PVOID pvArg)

Parameters
ftHandle Handle of the device.
dwEventMask Conditions that cause the event to be set.
pvArg Interpreted as the handle of an event.

Remarks
An application can use this function to setup conditions which allow a 
thread to block until one of the conditions is met. Typically, an 
application will create an event, call this function, then block on the 
event. When the conditions are met, the event is set, and the 
application thread unblocked.
dwEventMask is a bit-map that describes the events the application is 
interested in. pvArg is interpreted as the handle of an event which has 
been created by the application. If one of the event conditions is met, 
the event is set.
If FT_EVENT_RXCHAR is set in dwEventMask, the event will be set when a 
character has been received by the device.
If FT_EVENT_MODEM_STATUS is set in dwEventMask, the event will be set 
when a change in the modem signals has been detected by the device.
If FT_EVENT_LINE_STATUS is set in dwEventMask, the event will be set 
when a change in the line status has been detected by the device.

Danach ein nullterminierter String aus folgender funktion ausgelesen 
werden.

FT_STATUS FT_Read (FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD 
dwBytesToRead,
LPDWORD lpdwBytesReturned)

Parameters
ftHandle Handle of the device.
lpBuffer Pointer to the buffer that receives the data from the device.
dwBytesToRead Number of bytes to be read from the device.
lpdwBytesReturned Pointer to a variable of type DWORD which receives the 
number of bytes read from the device.

wie gesagt ich verstehe es leider nicht ganz.

von Mark L. (Gast)


Lesenswert?

> void sendString( const char* string )
> {
>   while( *string )
>     sendCharacter( *string++ );
> }
>
> wenn du nicht mit ollen C-style Strings rummachen willst (was ich
> verstehen kann), musst du dir halt was Gleichwertiges mit deiner
> favorisierten String-Klasse einfallen lassen.

ja so leicht ist es leider nicht, ich habe Probleme mit den Pointern 
bzw. der Datentyp konvertierung. Aber schon mal Danke

von Mark L. (Gast)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Mark L. schrieb:
> Genauer gesagt sind es mehrere Probleme. Der Null Teminierte String muss
> dieser funktion übergeben werden.Daher muss er konvertiert werden jedoch
> weiß ich leider nicht wie?
>
> FT_STATUS FT_Write (FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD
> dwBytesToWrite,LPDWORD lpdwBytesWritten)
>
> Parameters:
>
> ftHandle Handle of the device.
> lpBuffer Pointer to the buffer that contains the data to be written to
> the device.
> dwBytesToWrite Number of bytes to write to the device.
> lpdwBytesWritten Pointer to a variable of type DWORD


Ich versteh dein Problem immer noch nicht.
Dein STring hat eine gewisse Länge und damit eine gewisse Byteanzahl. 
Ich ignoriere jetzt mal Unicode sondern gehe von guten alten ASCII 
Strings aus. Wenn dem nicht so ist, dann musst du also entweder 
feststellen wie man von einem Unicode-String die Anzahl der Bytes 
ermittelt, oder wie man einen Unicode String auf ASCII transferiert. 
Beides hat aber erst mal nichts mit FT232 zu tun.

Hast du dann die Anzahl der Bytes, dann ab damit in diese Funktion. Die 
Längenangabe richtig angegebn und fertig, Wo liegt da jetzt schon wieder 
das Problem? Das ist banales C++ / Windows Wissen. So wie ich das sehe, 
hat diese API Funktion auch durchaus eine unter Windows gebräuchliche 
Signatur.

von Karl H. (kbuchegg)


Lesenswert?

Mark L. schrieb:
>> void sendString( const char* string )
>> {
>>   while( *string )
>>     sendCharacter( *string++ );
>> }
>>
>> wenn du nicht mit ollen C-style Strings rummachen willst (was ich
>> verstehen kann), musst du dir halt was Gleichwertiges mit deiner
>> favorisierten String-Klasse einfallen lassen.
>
> ja so leicht ist es leider nicht, ich habe Probleme mit den Pointern
> bzw. der Datentyp konvertierung.

Welche Probleme?

Die Sache wäre wesentlich einfacher, wenn du Code zeigen würdest.

Und PS: konzentrier dich erst mal nur auf eine Sache. Senden geht 
einfacher als Empfangen. Also fang erst mal mit Senden an.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> So wie ich das sehe, hat diese API Funktion auch durchaus eine
> unter Windows gebräuchliche Signatur.

1
  char String[] = "Hallo World";
2
  DWORD len = strlen( String ) + 1;  // + 1 damit das \0 Byte auch mitkommt
3
  DWORD bytesSent = 0;
4
5
  FT_Write( ftHandle, (void*)String, len, &bytesSent );
6
7
  if( bytesSent != len )
8
    cout << "Nicht alle Bytes konnten gesendet werden\n";

Wie gesagt: die Problematik UNICODE ignoriere ich jetzt erst mal, weil 
ich nicht weiß ob das ein konkretes Problem für dich darstellt.

von Mark L. (Gast)


Lesenswert?

Soweit bin ich:

Das funktioniert.
1
int write(void)
2
{
3
4
  DWORD Written=0;
5
  unsigned char cmd[]= {'T','E','S','T','\n'};
6
7
8
  /* String zu Char array?
9
    for(unsigned i = 0; i < TEXT.size(); i++)
10
      {
11
        cmd[i] = TEXT[i];
12
     }
13
14
  */
15
16
  ftStatus=FT_Write(ftHandle,cmd,sizeof(cmd),&Written);
17
18
  if (ftStatus == FT_OK)
19
    {
20
21
22
      printf("\nText: \"%s\" written\n",cmd);
23
24
    }
25
  else
26
    {
27
      printf("\nText write failed\n");
28
    }
29
30
  return 0;
31
32
}


aber wie bekomme ich den String\0 nach char []? Ja danke ich dacht mir 
schon das es wohl trivial sei.

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> unsigned char cmd[]= {'T','E','S','T','\n'};

ich glaube du braucht ein Buch über C und nicht über die FT232 lib.


unsigned char cmd[]= {'T','E','S','T','\n', 0 };

oder VIEL besser

char cmd[]= "TEST\n";

von Mark L. (Gast)


Lesenswert?

Angedacht ist:

String str0 = "Test\n";


write (str0);


int write(string str)
{

"String senden"

}

von Mark L. (Gast)


Lesenswert?

Peter II schrieb:
> char cmd[]= "TEST\n";

ergibt aber übertragunsfehler:

Ausgabe ist dann <NUL>xTEST<LF>

x ist ein unbekanntes Zeichen. Aber danke der hilfe.

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> ergibt aber übertragunsfehler:
> Ausgabe ist dann <NUL>xTEST<LF>
> x ist ein unbekanntes Zeichen. Aber danke der hilfe.

dann hast du wo anders noch einen Fehler oder eventuell Probleme mit 
unicode.

Zeig doch mal den den quelltext mit den dieser Fehler entstanden ist.

von Mark L. (Gast)


Lesenswert?

>   FT_Write( ftHandle, (void*)String, len, &bytesSent );
>
>   if( bytesSent != len )
>     cout << "Nicht alle Bytes konnten gesendet werden\n";
>
> Wie gesagt: die Problematik UNICODE ignoriere ich jetzt erst mal, weil
> ich nicht weiß ob das ein konkretes Problem für dich darstellt.

Vielen dank das hilft schon mal weiter, ich wusste nicht das es soo 
möglich ist den string zu senden (void*)String.

von Karl H. (kbuchegg)


Lesenswert?

Mark L. schrieb:
> Peter II schrieb:
>> char cmd[]= "TEST\n";
>
> ergibt aber übertragunsfehler:
>
> Ausgabe ist dann <NUL>xTEST<LF>
>
> x ist ein unbekanntes Zeichen.

Wie hast du das festgestellt?

Bei allen 'Messmethoden' muss man immer auch berücksichtigen, dass das 
'Messgerät' Unsinn anzeigt, weil es sich zb erst mal auf eine 
Übertragung einklinken muss. Nach dem ersten Zeichen sollte das 
allerdings dann nicht mehr sein.
1
Angedacht ist:
2
3
String str0 = "Test\n";
4
5
6
write (str0);
7
8
9
int write(string str)
10
{
11
12
"String senden"
13
14
}

Ja. Wie gehts jetzt weiter?
Stringlänge feststellen (Hinweis: dein sizeof da oben ist schon mal 
nicht dafür geeignet), entsprechenden Pointer auf die Bytes in FT_wruite 
reinstecken, die ermittelte Stringlänge reinstecken und ... fertig.

Ich seh immer noch kein Problem.

von Mark L. (Gast)


Lesenswert?

1
int write(void)
2
{
3
4
  DWORD Written=0;
5
  unsigned char cmd[]= {'T','E','S','T','\n'};
6
7
  ftStatus=FT_Write(ftHandle,cmd,sizeof(cmd),&Written);
8
9
  if (ftStatus == FT_OK)
10
    {
11
12
13
      printf("\nText: \"%s\" written\n",cmd);
14
15
    }
16
  else
17
    {
18
      printf("\nText write failed\n");
19
    }
20
21
  return 0;
22
23
}


Ausgabe: Test<LF>

1
int write(void)
2
{
3
4
  DWORD Written=0;
5
  unsigned char cmd[]= "TEST\n";
6
7
8
  ftStatus=FT_Write(ftHandle,cmd,sizeof(cmd),&Written);
9
10
  if (ftStatus == FT_OK)
11
    {
12
13
14
      printf("\nText: \"%s\" written\n",cmd);
15
16
    }
17
  else
18
    {
19
      printf("\nText write failed\n");
20
    }
21
22
  return 0;
23
24
}


Ausgabe: <NUL>xTEST<LF>

von Karl H. (kbuchegg)


Lesenswert?

Mark L. schrieb:
>>   FT_Write( ftHandle, (void*)String, len, &bytesSent );
>>
>>   if( bytesSent != len )
>>     cout << "Nicht alle Bytes konnten gesendet werden\n";
>>
>> Wie gesagt: die Problematik UNICODE ignoriere ich jetzt erst mal, weil
>> ich nicht weiß ob das ein konkretes Problem für dich darstellt.
>
> Vielen dank das hilft schon mal weiter, ich wusste nicht das es soo
> möglich ist den string zu senden (void*)String.

Das hat mit versenden nichts zu tun.
Der Cast auf void ist notwendig, weil es nun mal in C++ keinen Datentyp 
gibt der für 'Pointer auf irgendwas' steht und in den alle anderen 
Pointertypen implizit konvertiert werden können.
void* realisiert einen 'Pointer auf irgendwas', aber in C++ kann kein 
Pointer vom Compiler implizt darauf hingecastet werden, sondern der 
Programmierer muss das erlauben bzw. einfordern. Die Funktion will einen 
void Pointer, also caste ich den Datenpointer entsprechend um. Das 
normalste von der Welt.

Mir scheint Peter II hat da oben schon recht. Du brauchst in erster 
Linie mal ein vernünftiges Buch.

von Karl H. (kbuchegg)


Lesenswert?

Mark L. schrieb:

> Ausgabe: <NUL>xTEST<LF>


Die Art wie du dein Array baust, hat damit nichts zu tun. Deine erste 
Version ist nur die umständliche Schreibweise der 2.ten Version. Das 
Array wird aber in beiden Fällen identisch angelegt.

Ich denke eher, dass das 'x' das du siehst, das 0-Byte vom ersten (bzw. 
vorhergehenden) Versuch ist. Wozu sollte man ein 0-byte übertragen, wenn 
es nicht korrekt angezeigt werden kann. Normalerweise macht man das 
nicht (ausser der Empfänger benötigt das 0byte um das Ende des Strings 
erkennen zu können, was ein normales Terminalprogramm nicht kann. Das 
malt dann eben ein Zeichen für 'kenn ich nicht' hin.)

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die Art wie du dein Array baust, hat damit nichts zu tun. Deine erste
> Version ist nur die umständliche Schreibweise der 2.ten Version. Das
> Array wird aber in beiden Fällen identisch angelegt.
nein, einmal hat es am ende eine 0 einmal nicht. Aber der Anfang sollte 
gleich sein.

@Mark L.
Für soetwas hilft doch der debugger, schau dir doch einfach mal die 
Variaben an.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Karl Heinz Buchegger schrieb:
>> Die Art wie du dein Array baust, hat damit nichts zu tun. Deine erste
>> Version ist nur die umständliche Schreibweise der 2.ten Version. Das
>> Array wird aber in beiden Fällen identisch angelegt.
> nein, einmal hat es am ende eine 0 einmal nicht. Aber der Anfang sollte
> gleich sein.

Ah. ok. Daran hab ich jetzt nicht gedacht.

Ist ja auch Schwachsinn einen String mittels Einzelbuchstaben anzulegen. 
Das macht die Stringverarbeitung so schon <Sarkasmus ein> unkompliziert 
</Sarkasmus aus>

von Mark L. (Gast)


Lesenswert?

1
int write( char * str )
2
{
3
4
  char TEXT[strlen(str)];
5
  DWORD Written=0;
6
7
8
  for(int i = 0; i < strlen(str); i++)
9
  {
10
    TEXT[i] = str[i];
11
}
12
 
13
14
15
  ftStatus=FT_Write(ftHandle,TEXT,sizeof(TEXT)-1,&Written);
16
17
  if (ftStatus == FT_OK)
18
    {
19
20
21
      printf("\nText: \"%s\" written\n",TEXT);
22
23
    }
24
  else
25
    {
26
      printf("\nText write failed\n");
27
    }
28
29
  return 0;
30
31
}

sorry hat einen moment gedauert, der fehler war die \0 am ende aber 
jetzt funktioniert das senden wie es soll.

Ich benutze das http://www.cplusplus.com/ als Hilfe

Vielen dank schonmal für die Hilfestellung.

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> char TEXT[strlen(str)];
>
>   DWORD Written=0;
>   for(int i = 0; i < strlen(str); i++)
>   {
>     TEXT[i] = str[i];
> }

und was soll das? Du kopierst 1:1 alles was in str steht in TEXT rein - 
wozu?

Dann kannst du auch gleich str verwenden und braucht TEXT überhaupt 
nicht.


hast du ein glück das es seit neusten soetwas gibt:
   char TEXT[strlen(str)];

vor ein paar jahren hätte jeder Compiler hier aufgehört.

von Mark L. (Gast)


Lesenswert?

Ja das ist mir jetzt auch aufgefallen ;P. Danke

char TEXT[strlen(str)];

weil es zur laufzeit passiert? wenn ich das richtig verstehe?

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> weil es zur laufzeit passiert? wenn ich das richtig verstehe?

ja, weil der Compiler es noch nicht wissen kann wie gross die Variabel 
wird.

Warum hat deine Write funktion ein int als Rückgabe, wenn du eh immer 0 
zurückgibst - man muss nichts zurückgeben.

von Mark L. (Gast)


Lesenswert?

ISO C++ forbids declaration of 'write' with no type, war sonst der 
Fehler.

Zur Read Funktion ich habe das Beispiel geteste. Jedoch ohne Erfolg, 
deshalb auch die Frage ob jemand etwas in einer funktionsfähigen Form 
hat.

1
int read (void)
2
{
3
4
#define OneSector 1024
5
DWORD EventDWord;
6
DWORD RxBytes = 0;
7
DWORD TxBytes = 0;
8
DWORD BytesReceived=1;
9
char RxBuffer[OneSector];
10
11
  while(BytesReceived==1)
12
    {
13
14
      ftStatus = FT_GetStatus(ftHandle,&RxBytes,&TxBytes,&EventDWord);
15
16
      if((ftStatus == FT_OK) && (RxBytes >= OneSector))
17
        {
18
          ftStatus = FT_Read(ftHandle,RxBuffer,RxBytes,&BytesReceived);
19
          if (ftStatus == FT_OK)
20
            {
21
              printf("\n Text readout:%s \n",RxBuffer);
22
              BytesReceived=0;
23
            }
24
          else
25
            {
26
              printf("\n Text readout failed\n");
27
              BytesReceived=0;
28
            }
29
        }
30
      else
31
        {
32
33
          printf("\n Read error  %s \n",RxBuffer);
34
          BytesReceived=0;
35
36
37
        }
38
39
    }
40
41
return 0;
42
}

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> ISO C++ forbids declaration of 'write' with no type, war sonst der
> Fehler.
es gibt ja noch void

von Peter II (Gast)


Lesenswert?

if((ftStatus == FT_OK) && (RxBytes >= OneSector))

das sieht aber merkwürdig aus, du willst wo extra den Speicher 
überschreiben weil du hier wartest bis so viele Daten da sind das sie 
nicht mehr in RxBuffer reinpassen.

von Mark L. (Gast)


Lesenswert?

Wie gesagt war das Beispiel das ich fand verstanden habe ich es nicht.
1
int read (void)
2
{
3
4
  FT_STATUS ftStatus;
5
6
  DWORD RxBytes = 10;
7
  DWORD BytesReceived;
8
  unsigned char RxBuffer[256];
9
10
  FT_SetTimeouts(ftHandle,5000,0); //hier war wohl mein Fehler
11
12
  ftStatus = FT_Read(ftHandle,RxBuffer,RxBytes,&BytesReceived);
13
  if(ftStatus == FT_OK)
14
    {
15
      if(BytesReceived == RxBytes)
16
        {
17
          for(int i = 0 ; i < int(BytesReceived) ; i++)
18
            {
19
              printf("%d \n",RxBuffer[i]);
20
            }
21
        }
22
      else
23
        {
24
          printf("read error\n");
25
        }
26
    }
27
  else
28
    {
29
      printf("FTDI chip not ready\n");
30
    }
31
32
    return 0;
33
}

jetzt hab ich schonmal ein Ansatzt, im der CMD erhalte ich Ascii codes 
von mienem gesendeten String.

von Mark L. (Gast)


Lesenswert?

Okay Fehler eins war %d statt %s

jetzt muss ich es noch zu nem String zusammen setzten.

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> Wie gesagt war das Beispiel das ich fand verstanden habe ich es nicht.

dann versteh es bitte zu erst, Trial and Error ist bei programmieren in 
C das schlechteste was man machen kann.


> if(BytesReceived == RxBytes)

und was ist wenn man weniger zu empfangen ist?


Lies dir die Doku von FTDI durch und Programmiere es selber. Vom Copy 
and Paste lernt man nichts.

von Mark L. (Gast)


Lesenswert?

Ja wenn ich alles verstanden hätte wäre ich nicht hier, mir wäre es auch 
lieber alles zu können.
Oder eine Fertige lib zu nutzen die alles kann was ich brauche. Kann es 
aber eben nur so, ich dachte die Beispiele sind für den schnell 
Einstieg?Es geht leider nicht alles zu 100% zu lernen (wer hat den dazu 
Zeit?) somit ist das mein Weg. Ich bitte das zu verstehen. Jedoch, Danke 
für die Hilfe.

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> Oder eine Fertige lib zu nutzen die alles kann was ich brauche.

die FTDI lib ist doch schon fertig. Und macht eigentlich alles was man 
braucht.

> Es geht leider nicht alles zu 100% zu lernen (wer hat den dazu Zeit?)
doch geht es, wenn man einmal die Grundlagen verstanden hat, dann spart 
man am ende sogar Zeit. Du hast doch noch mal mal verstanden wie 
"Strings" in C funktionieren - dann sollte man noch nicht Anfangen 
irgendwelche Libs einzubinden.

was soll das hier:

> int(BytesReceived)

weist du überhaupt warum du das dort hingeschrieben hast?

von Mark L. (Gast)


Lesenswert?

einen typecast zur laufzeit.

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> einen typecast zur laufzeit.

nein ein typcast wird so geschrieben

(int)BytesReceived

aber warum willst du über casten? For-Schleifen müssen nicht mit int 
gemacht werden.


for(DWORD i = 0 ; i < BytesReceived; i++)

von Mark L. (Gast)


Lesenswert?

es ist ein typecast von unsigned in signed, geht doch so, warum nicht?

von Peter II (Gast)


Lesenswert?

Mark L. schrieb:
> es ist ein typecast von unsigned in signed, geht doch so, warum nicht?

das Problem dabei ist das es ein cast ist, wenn du aus irgend einem 
grund mal die Variable BytesReceived einen komplett anderen Datentyp 
gibst dann wirkt der Cast immernoch. und es gibt keine warnung vom 
Compiler. Also versucht man ohne cast auszukommenm. Und hier gibt es 
überhaupt keinen Grund mit einem Cast zu arbeiten.

von Mark L. (Gast)


Lesenswert?

okay ich ändere es...

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.