• 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
258 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 (195,220 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 (195,220 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 (195,220 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 (195,220 p.)
Jakby tak było, to czwarty parametr funkcji byłby niepotrzebny.

Podobne pytania

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

92,977 zapytań

141,940 odpowiedzi

321,182 komentarzy

62,303 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.

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...