• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Windows.h - ReadFile komunikacja z arduino

VPS Starter Arubacloud
0 głosów
202 wizyt
pytanie zadane 24 lutego 2019 w C i C++ przez Maciej Złotorowicz Gaduła (4,230 p.)
enum errorType {
	Success = 0,
	PORTISNOTAVALIBLE = 1,
	OTHERERROR = 2,
	CANTGETPARMS = 3,
	CANTSETPARMS = 4

};
class Arduino
{
private:
	HANDLE handler;
	bool connected;
	COMSTAT status;
	errorType Errorer;
	DWORD errors;
public:
	
	Arduino() {
		connected = false;
	}
	Arduino(string &PortName,unsigned int BoudRate) {
		handler = CreateFileA(static_cast<LPCSTR>(PortName.c_str()),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
		if (handler == INVALID_HANDLE_VALUE) {
			if (GetLastError() == ERROR_FILE_NOT_FOUND) {
				Errorer = PORTISNOTAVALIBLE;
			}
			else {
				Errorer = OTHERERROR;
			}
		}
		else {
			DCB SerialParam = { 0 };

			if (!GetCommState(handler, &SerialParam)) {
				Errorer = CANTGETPARMS;
			}
			else {
				SerialParam.BaudRate = BoudRate;
				SerialParam.ByteSize = 8;
				SerialParam.StopBits = ONESTOPBIT;
				SerialParam.Parity = NOPARITY;
				SerialParam.fDtrControl = DTR_CONTROL_ENABLE;
				
				if (!SetCommState(handler, &SerialParam))
				{
					Errorer = CANTSETPARMS;
				}
				else {
					connected = true;
					PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
				}
			}
		}
	}
	Arduino(const char *PortName, unsigned int BoudRate) {
		handler = CreateFileA(static_cast<LPCSTR>(PortName),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
		if (handler == INVALID_HANDLE_VALUE) {
			if (GetLastError() == ERROR_FILE_NOT_FOUND) {
				Errorer = PORTISNOTAVALIBLE;
			}
			else {
				Errorer = OTHERERROR;
			}
		}
		else {
			DCB SerialParam = { 0 };

			if (!GetCommState(handler, &SerialParam)) {
				Errorer = CANTGETPARMS;
			}
			else {
				SerialParam.BaudRate = BoudRate;
				SerialParam.ByteSize = 8;
				SerialParam.StopBits = ONESTOPBIT;
				SerialParam.Parity = NOPARITY;
				SerialParam.fDtrControl = DTR_CONTROL_ENABLE;

				if (!SetCommState(handler, &SerialParam))
				{
					Errorer = CANTSETPARMS;
				}
				else {
					connected = true;
					PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
				}
			}
		}
	}
	bool TryConnect(string &PortName, unsigned int BoudRate) {
		handler = CreateFileA(static_cast<LPCSTR>(PortName.c_str()),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
		if (handler == INVALID_HANDLE_VALUE) {
			if (GetLastError() == ERROR_FILE_NOT_FOUND) {
				Errorer = PORTISNOTAVALIBLE;
			}
			else {
				Errorer = OTHERERROR;
			}
			return false;
		}
		else {
			DCB SerialParam = { 0 };

			if (!GetCommState(handler, &SerialParam)) {
				Errorer = CANTGETPARMS;
				return false;
			}
			else {
				SerialParam.BaudRate = BoudRate;
				SerialParam.ByteSize = 8;
				SerialParam.StopBits = ONESTOPBIT;
				SerialParam.Parity = NOPARITY;
				SerialParam.fDtrControl = DTR_CONTROL_ENABLE;

				if (!SetCommState(handler, &SerialParam))
				{
					Errorer = CANTSETPARMS;
					return false;
				}
				else {
					connected = true;
					PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
					return true;
				}
			}
		}
	}
	bool TryConnect(const char *PortName, unsigned int BoudRate) {
		handler = CreateFileA(static_cast<LPCSTR>(PortName),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
		if (handler == INVALID_HANDLE_VALUE) {
			if (GetLastError() == ERROR_FILE_NOT_FOUND) {
				Errorer = PORTISNOTAVALIBLE;
			}
			else {
				Errorer = OTHERERROR;
			}
			return false;
		}
		else {
			DCB SerialParam = { 0 };

			if (!GetCommState(handler, &SerialParam)) {
				Errorer = CANTGETPARMS;
				return false;
			}
			else {
				SerialParam.BaudRate = BoudRate;
				SerialParam.ByteSize = 8;
				SerialParam.StopBits = ONESTOPBIT;
				SerialParam.Parity = NOPARITY;
				SerialParam.fDtrControl = DTR_CONTROL_ENABLE;

				if (!SetCommState(handler, &SerialParam))
				{
					Errorer = CANTSETPARMS;
					return false;
				}
				else {
					connected = true;
					PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
					return true;
				}
			}
		}
	}

	errorType Error() {
		return Errorer;
	}
	~Arduino() {
		if (connected) {
			connected = false;
			CloseHandle(handler);
		}

	}
	bool isConnected()
	{
		if (!ClearCommError(handler, &errors, &status))
			connected = false;

		return connected;
	}
	
	string TryRead(){

	}
	string ReadUntil (char EndSing) {
		ClearCommError(this->handler, &errors, &this->status);
		char buff = 0;
		DWORD READED;
		string out;

			int ReadedSize = 0;
			while(buff != EndSing) {
				while (!(status.cbInQue > 0)) {
					Sleep(5);
					ClearCommError(this->handler, &errors, &this->status);
				}
				ReadFile(handler, &buff, 1, &READED, NULL);
				out.append(1, buff);
				ReadedSize++;
			}
			return out;
	}
};

Dzień dobry. Wpadłem dziś na pomysł by zmusić Cpp do porozumiewania się z arduino. i pisałem sobie powyższą klasę w oparciu o materiały z internetu - i mam teraz takie pytanie: Czy dało by się lepiej zrobić funkcję ReadUntil i czy ktoś obeznany z ta biblioteką mógłby dać mi kilka wskazówek dotyczących sprawnego wykorzystywania tych narzędzi. 

1 odpowiedź

0 głosów
odpowiedź 24 lutego 2019 przez j23 Mędrzec (194,920 p.)
wybrane 26 lutego 2019 przez Maciej Złotorowicz
 
Najlepsza

Kilka uwag:

  • linia 215: czas przeszły słowa read to... read :)
  • linia 220: zamiast zawiłego warunku !(status.cbInQue > 0), wystarczy status.cbInQue == 0
  • powinieneś sprawdzać, czy ClearCommError nie zwraca błędu, bo teraz wewnętrzna pętla może zawiesić program.
  • linia 218: zbędna zmienna ReadedSize (duplikuje out.size()).
  • Po co powielasz kod 4x w TryConnect i ctorach? Zrób jedną funkcję Connect i wywołuj ją w konstruktorach.
  • zablokuj możliwość kopiowania obiektów klasy Arduino.
komentarz 27 lutego 2019 przez j23 Mędrzec (194,920 p.)
edycja 27 lutego 2019 przez j23
DWORD Read(char* Data, DWORD Size) 
{
	if (!connected) return 0;

	ClearCommError(handler, &errors, &status);
	
	DWORD bytes_read;
 
	if (!ReadFile(handler, Data, Size, &bytes_read, NULL) || errors != 0) 
	{
		Errorer = READERROR;
		return 0;
	}

	return bytes_read;
}



template <
	typename T,
	typename = std::enable_if_t<std::is_pod<T>::value>
>
bool ReadAll(T* Data, DWORD Size) 
{
	char* p = reinterpret_cast<char*>(Data);
	DWORD bytes_to_read = sizeof(T) * Size;

	while(bytes_to_read > 0 && Errorer == errorType::Success)
	{
		DWORD bytes_read = Read(p, bytes_to_read);
		bytes_to_read -= bytes_read;
		p += bytes_read;
	}

	return bytes_to_read == 0;
}

Tak bym zrobił.

komentarz 27 lutego 2019 przez Maciej Złotorowicz Gaduła (4,230 p.)
nie jestem pewnien czy nie miałeś na myśli

while(bytes_to_read> 0 ...
(bo inaczej pętla działała by w nieskończoność/do momentu napotkania błędu)

i jaką przewagę ma to nad tą "prostszą" wersją?
(nie licząc tego że można teraz wywołać Read by ładnie wczytać surową listę charów)
komentarz 27 lutego 2019 przez j23 Mędrzec (194,920 p.)

nie jestem pewnien czy nie miałeś na myśli

Tak, to miałem na myśli.

 

 jaką przewagę ma to nad tą "prostszą" wersją?

Twoja wersja zakłada, że ReadFile przeczyta Size * sizeof(T) bajtów, ale może się zdarzyć, że w buforze portu nie będzie tyle bajtów i wtedy twoja funkcja zwróci błąd, co IMO jest błędnym podejściem. Dlatego zrobiłem funkcję Read, która czyta tyle bajtów, ile może, i ReadAll, która czyta dokładnie tyle, ile podano w parametrze. Dodatkowo szablon jest zabezpieczony przed czytaniem nie-POD-ów.

 

komentarz 28 lutego 2019 przez Maciej Złotorowicz Gaduła (4,230 p.)
edycja 28 lutego 2019 przez Maciej Złotorowicz
Wydawało mi sie że jeżeli bufor nie zawiera N bajtów to ReadFile zaczeka aż Ten bufor się zapełni.
komentarz 28 lutego 2019 przez j23 Mędrzec (194,920 p.)
Jakby tak było, to czwarty parametr funkcji byłby niepotrzebny.

Podobne pytania

0 głosów
1 odpowiedź 264 wizyt
pytanie zadane 31 października 2018 w C i C++ przez Aleksander Początkujący (360 p.)
0 głosów
0 odpowiedzi 247 wizyt
0 głosów
0 odpowiedzi 462 wizyt

92,454 zapytań

141,262 odpowiedzi

319,092 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...