COM -GPS Receive Interval Problem
-
Hallo,
Ich habe einen GPS-Empfänger der am USB Port sitzt und mittels USB-To-Serial über die COM Schnittstelle angesprochen wird.
Also mein Code funktioniert soweit so gut, nur habe ich aktuell das Problem das mein Programm zu schnell die Daten abfrägt und mir die NMEA-0183 Daten nicht als kompletten Satz zurück gibt sondern gestückelt:
Soll:
$GPGGA,201154.000,4834.2335,N,00935.9391,E,0,00,,,M,,M,,*41
Das kommt bei mir raus:
$GPGGA,201155.000,4834.2335,N,00935.9391,E,0,00,,,M,,M, ,*40
(Also 2 Zeilen, sollte jedoch eine sein)
Meine Baudrate: 4800
Bits: 8ReadIntervalTimeout: 15
ReadTotalMultiplier: 1
ReadTotalConstant: 1
ReceiveIntervall: 900
(Original zwar 1 aber da kommt ein satz in Zig zeilen runter gerasselt)Wie finde ich denn das Optionale Receive Interval heraus?
Welche Zeitangabe ist das Interval? ms? sek?Gibts ne möglichkeit mein Abfrage Interval irgendwie zu berechnen oder den Code so zu ändern, das er auf die vollständigen Daten wartet bis zum Ende "\r\n" ?
Meine Library die Ich nutze:
TCommThread_Unit.cpp
//--------------------------------------------------------------------------- //TCommThread version 6.0 - 30/11/2005 //Luciano Vieira Koenigkan - e-mail: lucianovk@bol.com.br #include <vcl.h> #pragma hdrstop #include "CommThread_Unit.h" #pragma package(smart_init) //--------------------------------------------------------------------------- // Important: Methods and properties of objects in VCL can only be // used in a method called using Synchronize, for example: // // Synchronize(UpdateCaption); // // where UpdateCaption could look like: // // void __fastcall Unit2::UpdateCaption() // { // Form1->Caption = "Updated in a thread"; // } //--------------------------------------------------------------------------- __fastcall TCommThread::TCommThread() : TThread(true),ReturnMethod(NULL) { //Inicializando os atributos Connected=false; FreeOnTerminate = false; DeviceName="COM1"; MyDCB.DCBlength=sizeof(DCB); MyDCB.BaudRate=4800; MyDCB.ByteSize=8; MyDCB.Parity=NOPARITY; MyDCB.StopBits=ONESTOPBIT; MyTimeouts.ReadIntervalTimeout=15; MyTimeouts.ReadTotalTimeoutMultiplier=1; MyTimeouts.ReadTotalTimeoutConstant=1; MyTimeouts.WriteTotalTimeoutMultiplier=1; MyTimeouts.WriteTotalTimeoutConstant=1; ReceiveQueue=32; TransmitQueue=9; MaxFails=100000; ReceiveInterval=1; } //--------------------------------------------------------------------------- __fastcall TCommThread::TCommThread(void(__closure *NewReturnMethod)(AnsiString)) : TThread(true),ReturnMethod(NewReturnMethod) { //Inicializando os atributos Connected=false; DeviceName="COM1"; MyDCB.DCBlength=sizeof(DCB); MyDCB.BaudRate=9600; MyDCB.ByteSize=8; MyDCB.Parity=NOPARITY; MyDCB.StopBits=ONESTOPBIT; MyTimeouts.ReadIntervalTimeout=15; MyTimeouts.ReadTotalTimeoutMultiplier=1; MyTimeouts.ReadTotalTimeoutConstant=1; MyTimeouts.WriteTotalTimeoutMultiplier=1; MyTimeouts.WriteTotalTimeoutConstant=1; ReceiveQueue=32; TransmitQueue=9; MaxFails=100000; ReceiveInterval=1; } //--------------------------------------------------------------------------- void __fastcall TCommThread::Execute() { unsigned long AvailableBytes; unsigned long ReadBytes; while(Terminated==false) { Sleep(ReceiveInterval); AvailableBytes=BytesAvailable(); if(AvailableBytes>0) { ReceivedData.SetLength(AvailableBytes); if(ReadFile(DeviceHandle,(void*)ReceivedData.data(),AvailableBytes,&ReadBytes,NULL)==true) { if(ReadBytes>0) { Synchronize(AfterReceiveData); ReceivedData=""; }//if }//if }//if } } //--------------------------------------------------------------------------- bool TCommThread::Connect(void) { Synchronize(Open); return(Connected); } //--------------------------------------------------------------------------- bool TCommThread::Disconnect(void) { Synchronize(Close); return(!Connected); } //--------------------------------------------------------------------------- bool TCommThread::GetConnected(void) { return(Connected); } //--------------------------------------------------------------------------- void __fastcall TCommThread::AfterReceiveData() { ReturnMethod(ReceivedData); } //--------------------------------------------------------------------------- bool TCommThread::TransmitChar(char c) { unsigned long CEnviados; CEnviados=0; if(Connected==true) { if(WriteFile(DeviceHandle,&c,1,&CEnviados,NULL)!=0) return(true); else return(false); }//if else return(false); } //--------------------------------------------------------------------------- int TCommThread::BytesAvailable(void) { if(Connected==true) { COMSTAT TempStat; DWORD TempDword; if(ClearCommError(DeviceHandle,&TempDword,&TempStat)==true) { return(TempStat.cbInQue); }//if else return(0); }//if else return(0); } //--------------------------------------------------------------------------- bool TCommThread::TransmitData(AnsiString Data) { int i; int Fails; i=1; Fails=0; while((i<=Data.Length())&&(Data.Length()>0)&&(Fails<MaxFails)) { if(TransmitChar(Data[i])==true) { i++; Fails=0; } else { Fails++; } } if(Fails<MaxFails) return(true); else return(false); } //--------------------------------------------------------------------------- void __fastcall TCommThread::Close() { if(Connected==true) { //back to original setings SetCommState(DeviceHandle,&OriginalDCB); SetCommTimeouts(DeviceHandle,&OriginalTimeouts); if(CloseHandle(DeviceHandle)!=0) { Connected=false; }//if else { SetCommState(DeviceHandle,&MyDCB); SetCommTimeouts(DeviceHandle,&MyTimeouts); } }//if } //--------------------------------------------------------------------------- void __fastcall TCommThread::Open() { if(Connected==false) { //Open device DeviceHandle=CreateFile( DeviceName.c_str(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL ); if(DeviceHandle!=INVALID_HANDLE_VALUE) { //Make backup and set DCB of open device GetCommState(DeviceHandle,&OriginalDCB); SetCommState(DeviceHandle,&MyDCB); //Make backup and set COMMTIMEOUTS of open device GetCommTimeouts(DeviceHandle,&OriginalTimeouts); SetCommTimeouts(DeviceHandle,&MyTimeouts); SetupComm(DeviceHandle,1024*ReceiveQueue,1024*TransmitQueue); //Resume Thread if(this->Suspended) Resume(); Connected=true; }//if }//if } //--------------------------------------------------------------------------- void TCommThread::SetDeviceName(AnsiString NewDeviceName) { if(Connected==true) { Disconnect(); DeviceName=NewDeviceName; Connect(); } else DeviceName=NewDeviceName; } //--------------------------------------------------------------------------- AnsiString TCommThread::GetDeviceName(void) { return(DeviceName); } //--------------------------------------------------------------------------- HANDLE TCommThread::GetDeviceHandle(void) { return(DeviceHandle); } //--------------------------------------------------------------------------- int TCommThread::GetReceiveQueue(void) { return(ReceiveQueue); } //--------------------------------------------------------------------------- void TCommThread::SetReceiveQueue(int NewReceiveQueue) { if(Connected==true) { Disconnect(); ReceiveQueue=NewReceiveQueue; Connect(); } else ReceiveQueue=NewReceiveQueue; } //--------------------------------------------------------------------------- void TCommThread::SetReturnMethod(void(__closure *NewReturnMethod)(AnsiString)) { if(Connected==true) { Disconnect(); ReturnMethod=NewReturnMethod; Connect(); } else ReturnMethod=NewReturnMethod; } //--------------------------------------------------------------------------- int TCommThread::GetTransmitQueue(void) { return(TransmitQueue); } //--------------------------------------------------------------------------- void TCommThread::SetTransmitQueue(int NewTransmitQueue) { if(Connected==true) { Disconnect(); TransmitQueue=NewTransmitQueue; Connect(); } else TransmitQueue=NewTransmitQueue; } //--------------------------------------------------------------------------- void TCommThread::SetMaxFails(int NewMaxFails) { if(Connected==true) { Disconnect(); MaxFails=NewMaxFails; Connect(); } else MaxFails=NewMaxFails; } //--------------------------------------------------------------------------- int TCommThread::GetMaxFails(void) { return(MaxFails); } //--------------------------------------------------------------------------- int TCommThread::GetBaudRate(void) { return(MyDCB.BaudRate); } //--------------------------------------------------------------------------- void TCommThread::SetBaudRate(int NewBaudRate) { if(Connected==true) { Disconnect(); MyDCB.BaudRate=NewBaudRate; Connect(); } else MyDCB.BaudRate=NewBaudRate; } //--------------------------------------------------------------------------- int TCommThread::GetByteSize(void) { return(MyDCB.ByteSize); } //--------------------------------------------------------------------------- void TCommThread::SetByteSize(int NewByteSize) { if(Connected==true) { Disconnect(); MyDCB.ByteSize=NewByteSize; Connect(); } else MyDCB.ByteSize=NewByteSize; } //--------------------------------------------------------------------------- int TCommThread::GetParity(void) { return(MyDCB.Parity); } //--------------------------------------------------------------------------- void TCommThread::SetParity(int NewParity) { if(Connected==true) { Disconnect(); MyDCB.Parity=NewParity; Connect(); } else MyDCB.Parity=NewParity; } //--------------------------------------------------------------------------- int TCommThread::GetStopBits(void) { return(MyDCB.StopBits); } //--------------------------------------------------------------------------- void TCommThread::SetStopBits(int NewStopBits) { if(Connected==true) { Disconnect(); MyDCB.StopBits=NewStopBits; Connect(); } else MyDCB.StopBits=NewStopBits; } //--------------------------------------------------------------------------- int TCommThread::GetReadIntervalTimeout(void) { return(MyTimeouts.ReadIntervalTimeout); } //--------------------------------------------------------------------------- void TCommThread::SetReadIntervalTimeout(int NewReadIntervalTimeout) { if(Connected==true) { Disconnect(); MyTimeouts.ReadIntervalTimeout=NewReadIntervalTimeout; Connect(); } else MyTimeouts.ReadIntervalTimeout=NewReadIntervalTimeout; } //--------------------------------------------------------------------------- int TCommThread::GetReadTotalTimeoutMultiplier(void) { return(MyTimeouts.ReadTotalTimeoutMultiplier); } //--------------------------------------------------------------------------- void TCommThread::SetReadTotalTimeoutMultiplier(int NewReadTotalTimeoutMultiplier) { if(Connected==true) { Disconnect(); MyTimeouts.ReadTotalTimeoutMultiplier=NewReadTotalTimeoutMultiplier; Connect(); } else MyTimeouts.ReadTotalTimeoutMultiplier=NewReadTotalTimeoutMultiplier; } //--------------------------------------------------------------------------- int TCommThread::GetReadTotalTimeoutConstant(void) { return(MyTimeouts.ReadTotalTimeoutConstant); } //--------------------------------------------------------------------------- void TCommThread::SetReadTotalTimeoutConstant(int NewReadTotalTimeoutConstant) { if(Connected==true) { Disconnect(); MyTimeouts.ReadTotalTimeoutConstant=NewReadTotalTimeoutConstant; Connect(); } else MyTimeouts.ReadTotalTimeoutConstant=NewReadTotalTimeoutConstant; } //--------------------------------------------------------------------------- int TCommThread::GetWriteTotalTimeoutMultiplier(void) { return(MyTimeouts.WriteTotalTimeoutMultiplier); } //--------------------------------------------------------------------------- void TCommThread::SetWriteTotalTimeoutMultiplier(int NewWriteTotalTimeoutMultiplier) { if(Connected==true) { Disconnect(); MyTimeouts.WriteTotalTimeoutMultiplier=NewWriteTotalTimeoutMultiplier; Connect(); } else MyTimeouts.WriteTotalTimeoutMultiplier=NewWriteTotalTimeoutMultiplier; } //--------------------------------------------------------------------------- int TCommThread::GetWriteTotalTimeoutConstant(void) { return(MyTimeouts.WriteTotalTimeoutConstant); } //--------------------------------------------------------------------------- void TCommThread::SetWriteTotalTimeoutConstant(int NewWriteTotalTimeoutConstant) { if(Connected==true) { Disconnect(); MyTimeouts.WriteTotalTimeoutConstant=NewWriteTotalTimeoutConstant; Connect(); } else MyTimeouts.WriteTotalTimeoutConstant=NewWriteTotalTimeoutConstant; } //--------------------------------------------------------------------------- AnsiString TCommThread::GetAvailableData(void) { unsigned long AvailableBytes; unsigned long ReadBytes; AnsiString bla=""; ReceivedData=""; AvailableBytes=BytesAvailable(); if(AvailableBytes>0) { ReceivedData.SetLength(AvailableBytes); if(ReadFile(DeviceHandle,(void*)ReceivedData.data(),AvailableBytes,&ReadBytes,NULL)==true) { if(ReadBytes>0) { bla = bla +bla; }//if }//if } return(bla); } //--------------------------------------------------------------------------- void TCommThread::SetReceiveInterval(int NewReceiveInterval) { ReceiveInterval=NewReceiveInterval; } //--------------------------------------------------------------------------- int TCommThread::GetReceiveInterval(void) { return ReceiveInterval; } //--------------------------------------------------------------------------- TStringList* TCommThread::GetAvailableDevicesNames(bool IncludeSerial, bool IncludeParallel, TStringList * AvaiableDevicesNames) { TRegistry *Registro = new TRegistry(); TStringList *StringsTemp = new TStringList(); int Indice; if (AvaiableDevicesNames!=NULL) AvaiableDevicesNames->Clear(); else AvaiableDevicesNames = new TStringList(); Registro->RootKey=HKEY_LOCAL_MACHINE; if(IncludeSerial==true) { StringsTemp->Clear(); Registro->OpenKey("hardware\\devicemap\\serialcomm",false); Registro->GetValueNames(StringsTemp); for (Indice=0;Indice<StringsTemp->Count;Indice++) AvaiableDevicesNames->Add(Registro->ReadString(StringsTemp->Strings[Indice])); Registro->CloseKey(); } if(IncludeParallel==true) { StringsTemp->Clear(); Registro->OpenKey("hardware\\devicemap\\parallel ports",false); Registro->GetValueNames(StringsTemp); for (Indice=0;Indice<StringsTemp->Count;Indice++) AvaiableDevicesNames->Add(ExtractFileName(Registro->ReadString(StringsTemp->Strings[Indice]))); Registro->CloseKey(); } AvaiableDevicesNames->Sort(); delete Registro; delete StringsTemp; return AvaiableDevicesNames; } //---------------------------------------------------------------------------
TCommThread_Unit.h
//--------------------------------------------------------------------------- //TCommThread version 6.0 - 30/11/2005 //Luciano Vieira Koenigkan - e-mail: lucianovk@bol.com.br #ifndef CommThread_UnitH #define CommThread_UnitH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Registry.hpp> //--------------------------------------------------------------------------- class TCommThread : public TThread { private: HANDLE DeviceHandle; bool Connected; AnsiString DeviceName; DCB MyDCB; DCB OriginalDCB; COMMTIMEOUTS MyTimeouts; COMMTIMEOUTS OriginalTimeouts; int ReceiveQueue; int TransmitQueue; AnsiString ReceivedData; int MaxFails; bool Disconnecting; int ReceiveInterval; void __fastcall AfterReceiveData(); bool TransmitChar(char c); int BytesAvailable(void); void __fastcall Close(); void __fastcall Open(); protected: void __fastcall Execute(); public: __fastcall TCommThread(void(__closure *NewReturnMethod)(AnsiString)); __fastcall TCommThread(); void(__closure *ReturnMethod)(AnsiString); bool Connect(void); bool Disconnect(void); bool GetConnected(void); bool TransmitData(AnsiString Data); void SetDeviceName(AnsiString NewDeviceName); AnsiString GetDeviceName(void); HANDLE GetDeviceHandle(void); int GetReceiveQueue(void); void SetReceiveQueue(int NewReceiveQueue); int GetTransmitQueue(void); void SetTransmitQueue(int NewTransmitQueue); void SetMaxFails(int NewMaxFails); int GetMaxFails(void); int GetBaudRate(void); void SetBaudRate(int NewBaudRate); int GetByteSize(void); void SetByteSize(int NewByteSize); int GetParity(void); void SetParity(int NewParity); int GetStopBits(void); void SetStopBits(int NewStopBits); int GetReadIntervalTimeout(void); void SetReadIntervalTimeout(int NewReadIntervalTimeout); int GetReadTotalTimeoutMultiplier(void); void SetReadTotalTimeoutMultiplier(int NewReadTotalTimeoutMultiplier); int GetReadTotalTimeoutConstant(void); void SetReadTotalTimeoutConstant(int NewReadTotalTimeoutConstant); int GetWriteTotalTimeoutMultiplier(void); void SetWriteTotalTimeoutMultiplier(int NewWriteTotalTimeoutMultiplier); int GetWriteTotalTimeoutConstant(void); void SetWriteTotalTimeoutConstant(int NewWriteTotalTimeoutConstant); void SetReturnMethod(void(__closure *NewReturnMethod)(AnsiString)); AnsiString GetAvailableData(void); void SetReceiveInterval(int NewReceiveInterval); int GetReceiveInterval(void); TStringList* TCommThread::GetAvailableDevicesNames(bool IncludeSerial, bool IncludeParallel, TStringList * AvaiableDeviceNames); }; //--------------------------------------------------------------------------- #endif
-
ReceiveInterval wird offenebar in Millisekunden verlangt.
Du müßtest in deiner ReturnMethod die Daten solange puffern, bis ein Zeilenendzeichen ankommt. Danach gibst du den Inhalt des Puffers als Zeile weiter und löscht den Puffer. ReceiveInterval hochdrehen ist keine Lösung für dein Problem.
Du könntest alternativ versuchen, ReadTotalTimeoutMultiplier zu erhöhen. Das setzt aber, zusammen mit ReadIntervalTimeout, voraus, dass das GPS-Gerät einen kontinuierlichen Datenstrom schickt. Darauf sollte man sich aber, angesichts des Protokolls, das Zeilenendzeichen verwendet, nicht verlassen.
-
Hallo,
Wie du schon sagtest, das ReceiveInterval hochzudrehen ist keine Lösung, da der Datenstrom vom GPS Receiver dann ins Stocken gerät.
Wie könnte denn so ein Buffer letzendlich aussehen?
Könnte in denn ein Zeilenende mit <CR><LF> mit WaitCommEvent in meinem Thread Abwarten um so an eine Vollständige GPS Zeile zu kommen?
Weil mein Start fängt generell immer mit $GPS an und Endet mit <CR><LF>...
-
Okay hab nun mein Problem gelöst.
Meine Receive Funktion sieht nun so aus:
void __fastcall TCommThread::Execute() { unsigned long AvailableBytes; unsigned long ReadBytes; bool enabled = false; while(Terminated==false) { Sleep(1); AvailableBytes=BytesAvailable(); if(AvailableBytes>0) { //ReceivedData.SetLength(AvailableBytes); if(ReadFile(DeviceHandle,Buffer,AvailableBytes,&ReadBytes,NULL)==true) { if(ReadBytes>0) { AnsiString s; for(DWORD i=0; i < AvailableBytes; i++) { if(Buffer[i] == 0x24) // Warten auf $ enabled = true; if(Buffer[i] == 0x0d) // Ende <CR> enabled = false; if(enabled == true) ReceivedData=ReceivedData+Buffer[i]; if(enabled == false && ReceivedData != "") { Synchronize(AfterReceiveData); // Ausgeben wenn String fertig ReceivedData=""; } } }//if }//if }//if } }
Die Ausgabe:
$GPGLL,4834.3678,N,00935.8617,E,102434.000,V*25 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,2,1,07,32,37,063,,28,05,265,,20,63,261,,23,26,191,*7D $GPGSV,2,2,07,01,42,057,,07,30,203,,08,38,238,*44 $GPRMC,10$GPGGA,102632.000,4834.3678,N,00935.8617,E,0,00,,,M,,M,,*41 $GPGLL,4834.3678,N,00935.8617,E,102632.000,V*21 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,2,1,06,19,08,169,,14,17,040,,01,41,056,,20,64,262,*74 $GPGSV,2,2,06,32,36,063,,07,30,202,*7A $GPRMC,102632.000,V,4834.3678,N,00935.8617,E,,,080408,,*12 $GPVTG,,T,,M,,N,,K*4E $GPGGA,102633.000,4834.3678,N,00935.8617,E,0,00,,,M,,M,,*40 $GPGLL,4834.3678,N,00935.8617,E,102633.000,V*20 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,2,1,06,19,08,169,,14,17,040,,01,41,056,,20,64,262,*74 $GPGSV,2,2,06,32,36,063,,07,30,202,*7A $GPRMC,102633.000,V,4834.3678,N,00935.8617,E,,,080408,,*13 $GPVTG,,T,,M,,N,,K*4E