IowKitReadImmediate blockiert unter Windows

Dies ist das deutsche Forum für alle Themen um den IO-Warrior. Beiträge bitte nur in Deutsch.

Moderator: Guido Körber

Post Reply
hiasl
Posts: 26
Joined: Tue Jul 25, 2006 9:58 am

IowKitReadImmediate blockiert unter Windows

Post by hiasl »

Hallo,

ich habe folgenden Codeschnippsel, der von mehreren iowarriorn lesen kann:

fprintf(stderr, "IN\n");
ULONG readValue;
IowKitReadImmediate(sDevs[sId], &readValue);
fprintf(stderr, "OUT\n");
return (readValue & (1 << dId)) != 0;

Ich habe ein kleines Testprogramm (Kommandozeile) , das ich mehrfach hintereinander aufrufe. Nachdem ich das Programm ein paar mal starte, bleibt der Leseaufruf hängen. Das Testprogramm hat sich vorher sauber beendet und IowKitCloseDevice aufgerufen.

Ich verwende das aktuelle SDK

Was kann das sein?

Gruß
Matthias
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Frisch runtergeladen nach dem 9.2.? Wir haben da noch einen Bugfix gemacht.

Es kann nicht schaden mir die Sourcen des Testprogramms zu schicken, damit ich den Fehler nachstellen kann.
marquardt att codemercs dott com
hiasl
Posts: 26
Joined: Tue Jul 25, 2006 9:58 am

Post by hiasl »

Frisch runter geladen am 13.02. ;)

Das Ganze ist als DLL an Python gekoppelt und etwas umfangreicher...
hiasl
Posts: 26
Joined: Tue Jul 25, 2006 9:58 am

Post by hiasl »

Hm.. ich habe mal folgendes ausprobiert:

[SNIP]
#include "iowkit.h"

IOWKIT_HANDLE sDevs[IOWKIT_MAX_DEVICES];
int numSDevs;
int numDevs[IOWKIT_MAX_DEVICES];

int compare( const void *arg1, const void *arg2 ) {
return wcscmp((WCHAR*) arg1, (WCHAR*) arg2);
}

//
// Initialisation of the library at startup
//
DLLEXPORT void init() {
//begin edit
int i, j;
IOWKIT_HANDLE l_sDevs[IOWKIT_MAX_DEVICES];
l_sDevs[0] = IowKitOpenDevice();
if (l_sDevs[0] != NULL) {
//get all devices handles
numSDevs = IowKitGetNumDevs();
for (i = 1; i < numSDevs; i++) {
l_sDevs = IowKitGetDeviceHandle(i + 1);
}
//get serials and sort them
WCHAR serials[IOWKIT_MAX_DEVICES][9];
for (i = 0; i < numSDevs; i++) {
IowKitGetSerialNumber(l_sDevs, serials);
}
qsort(serials, numSDevs, sizeof(WCHAR *), compare);

//fill global sDevs
for (i = 0; i < numSDevs; i++) {
WCHAR serial[9];
IowKitGetSerialNumber(l_sDevs, serial);
for (j = 0; j < numSDevs; j++) {
if (!wcscmp(serial, serials[j])) {
sDevs = l_sDevs[j];
}
}
}
//get number of devices
for (i = 0; i < numSDevs; i++) {
switch(IowKitGetProductId(sDevs)) {
case IOWKIT_PID_IOW24:
case IOWKIT_PRODUCT_ID_IOWPV1:
case IOWKIT_PRODUCT_ID_IOWPV2:
numDevs = 16;
break;
case IOWKIT_PID_IOW40:
numDevs = 32;
break;
case IOWKIT_PID_IOW56:
numDevs = 50;
break;
}
}
} else {
EXCEPTION("No iowarriors connected!");
IowKitCloseDevice(sDevs[0]);
}

CHAR readValue[8];
memcpy(readValue, " ", 8);
int ret = IowKitReadNonBlocking(sDevs[0], IOW_PIPE_IO_PINS, readValue, sizeof(readValue));

printf("%d\n", ret);
[SNIP]

Angeschlossen sind wahlweise 2 oder 3 iowarrior. Der Leseversuch ist bereits erfolglos. Was mache ich falsch?
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Muss ich morgen mal ausprobieren. Heute habe ich noch andere Sachen zu tun.
Kannst du die Message editieren und Code Tags um die Source legen, damit die Formatierung erhalten bleibt?
hiasl
Posts: 26
Joined: Tue Jul 25, 2006 9:58 am

Post by hiasl »

So, hier mal formatierter Code. Mein Problem bei dem Beisipel: Das Lesen im Thread blockiert die ganze Anwendung!

Kompiliert als Shellprogramm mit Multithreadingunterstützung und inkludiertem "<afxwin.h>" unter VS 2003.

Gibt es eine andere schnelle Möglichkeit, um iowkit zu umgehen?

Gruß
Matthias

Code: Select all

// test12.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include "iowkit.h"

IOWKIT_HANDLE sDevs[IOWKIT_MAX_DEVICES];
int numSDevs;
int numDevs[IOWKIT_MAX_DEVICES];

int compare( const void *arg1, const void *arg2 ) {
	return wcscmp((WCHAR*) arg1, (WCHAR*) arg2);
}

int exitThreads = 0;
UINT PrinterThreadFunc(LPVOID pParam) {
	while (!exitThreads) {
		printf("Guckguck\n");
	}
	AfxEndThread(0);
	return 0;
}
UINT ReaderThreadFunc(LPVOID pParam) {
	int sId = (int) pParam;
	CHAR readValue[8];
	while (!exitThreads) {
		printf("hallo\n");
		int ret = IowKitRead(sDevs[sId], IOW_PIPE_IO_PINS, readValue, sizeof(readValue));
		int err = GetLastError();
		printf("thread %d read %d bytes value %s %d\n", sId, ret, readValue, err);
	}
	AfxEndThread(0);
	return 0;
}

int _tmain(int argc, _TCHAR* argv[]) {
	//begin edit
	int i, j;
	IOWKIT_HANDLE l_sDevs[IOWKIT_MAX_DEVICES];
	l_sDevs[0] = IowKitOpenDevice();
	if (l_sDevs[0] != NULL) {
		//get all devices handles
		numSDevs = IowKitGetNumDevs();
		for (i = 1; i < numSDevs; i++) {
			l_sDevs[i] = IowKitGetDeviceHandle(i + 1);
		}
		//get serials and sort them
		WCHAR serials[IOWKIT_MAX_DEVICES][9];
		for (i = 0; i < numSDevs; i++) {
			IowKitGetSerialNumber(l_sDevs[i], serials[i]);
		}
		qsort(serials, numSDevs, sizeof(WCHAR *), compare);
		
		//fill global sDevs
		for (i = 0; i < numSDevs; i++) {
			WCHAR serial[9];
			IowKitGetSerialNumber(l_sDevs[i], serial);
			for (j = 0; j < numSDevs; j++) {
				if (!wcscmp(serial, serials[j])) {
					sDevs[i] = l_sDevs[j];
				}
			}
		}
		//get number of devices
		for (i = 0; i < numSDevs; i++) {
			switch(IowKitGetProductId(sDevs[i])) {
				case IOWKIT_PID_IOW24:
				case IOWKIT_PRODUCT_ID_IOWPV1:
				case IOWKIT_PRODUCT_ID_IOWPV2:
					numDevs[i] = 16 * 2;
					break;
				case IOWKIT_PID_IOW40:
					numDevs[i] = 32 * 2;
					break;
				case IOWKIT_PID_IOW56:
					numDevs[i] = 50 * 2;
					break;
			}
        }
		//set timeouts
		for (i = 0; i < numSDevs; i++) {
			IowKitSetTimeout(sDevs[i], 1000);
		}
	} else {
		IowKitCloseDevice(sDevs[0]);
	}

	//create receiver threads and events for each iowarrior
	AfxBeginThread(PrinterThreadFunc, NULL);
	for (i = 0; i < numSDevs; i++) {
	 	AfxBeginThread(ReaderThreadFunc, (void *) i);
	}
	
	exitThreads = 1;
	return 0;
}
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Wie soll denn das Programm ueberhaupt funktionieren?
Es werden die Threads gestartet und dann das Hauptprogramm beendet was auch gleich die Threads in den Abgrund reisst.
Vor Beendigung des Programms muss auch IowKitCloseDevice() aufgerufen werden.

Ich habe das Programm ein bischen aufgearbeitet und es scheint zu funktionieren. Es liest aber regelmaessig 0 Bytes von den IOWarriors.
Das ist an sich nicht wirklich fehlerhaft, aber auch nicht richtig.
Wenn Daten da sind dann werden sie auch gelesen.

Einige schnelle Experimente haben die Ursache der leeren Reads nicht finden koennen. Es kann noch etwas dauern.
hiasl
Posts: 26
Joined: Tue Jul 25, 2006 9:58 am

Post by hiasl »

Das Programm als solches hat erstmal gar keinen Sinn und diente nur zum Test, ob ich mich zu blöd anstelle. Das Hauptprogramm kann sich auch eine Zeit lang schlafen legen und dann erst beenden. Es ändert nichts am Problem.

Das Ganze ist Teil einer Pythonankopplung und da macht es dann doch wieder Sinn. Allerdings ist dort der Code auch etwas abgewandelt.

Eine Frage zur deterministischen Festlegung der Handle-Reihenfolge - warum sortiert der Treiber nicht intern alphabetisch. wie mein Beispiel, nach den Seriennummern?

Achso - 0 Bytes lesen ist nicht ganz richtig und nicht ganz falsch? ;)
In der Doku steht, IowKitRead blockiert, bis eine Veränderung eingetreten ist. Somit darf die Funktion keine 0 Bytes lesen, es sei denn, es gibt einen Fehler, richtig?

Gruß
Matthias
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Was geht die DLL die Reihenfolge der IOWarrior an? Da das sortieren nach Seriennummer nicht das einzig moegliche Kriterium ist, macht es keinen Sinn zu sortieren.

Ich weiss nicht warum es zum Lesen von 0 bytes kommt. Ein schnelles Experiment hat die Ursache nicht enttarnt. Ich muss am Montag nochmal genauer nachpruefen.
hiasl
Posts: 26
Joined: Tue Jul 25, 2006 9:58 am

Post by hiasl »

Eine ganze Menge. Damit wird gewährleistet, dass man alle IOs von 1 - n über mehrere IOWs durchnummerieren kann und nicht Gefahr läuft, dass sich das bei jedem Neustart ändert.

Gerade wenn es darum geht, mehrere IOWs fest in Geräte einzubauen ist das notwendig. Schließlich will man nicht für jedes Gerät manuell konfigurieren müssen (etwa Seriennummer zu IO-Range im Programm. ).

So kann man sagen: Baut die Dinger in alphabetischer Reihenfolge ein und Euer Programm läuft immer.

So wie ich die Doku verstanden habe, ist die Seriennummer die einzige Möglichkeit, um alle IOWs in eine deterministische Reihenfolge zu bringen und somit das einzige Sortierkriterium.

Naürlich hat das wenig Sinn, wenn sich die Anzahl der IOWs während dem Betrieb ändert. Aber das ist ein anderes Szenario. Eine Sortierung des Treibers würde dies aber nicht behindern, wäre also kein Schaden.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Genau das ist der Grund warum nicht sortiert wird. Fest eingebaute IOWarrior sind sicherlich in der extremen Minderheit. Es ist eine erzieherische Massnahme. Der Programmierer soll lernen das die IOWarrior nicht immer in der gleichen Reihenfolge sind.
Man kann uebrigens (zwar eher theoretisch) IOWarrior mit der gleichen Seriennummer haben. Das ist der Fall wenn man verschiedene IOWarrior (24, 40, 56) einsetzt.
Guido Körber
Site Admin
Posts: 2876
Joined: Tue Nov 25, 2003 10:25 pm
Location: Germany/Berlin
Contact:

Post by Guido Körber »

Da der USB ein ausdrücklich Hot-Plug fähiger Bus ist, ist es mit dem eindeutigen zuordnen der IO-Warrior ohne Verwendung der Seriennummer nicht weit her. Jedes betriebssystem hat seine eigene Methode wie die Geräte geordnet werden und bei Windows ist das zwischen den verschiedenen Versionen auch nicht einheitlich.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Man sollte nicht versuchen am Freitagnachmittag Sourcen zu debuggen.

IowKitSetTimeout(sDevs, 1000);

Da steht das das IowKitRead() nach einer Sekunde zurueckkehrt wenn keine Daten gekommen sind. Natuerlich liefert es dann 0 Bytes gelesen.

Ich denke damit ist alles erklaert. Die Threads funktionieren, das Hauptprogramm muss am Ende IowKitCloseDevice() aufrufen.
Wenn es also nach der Korrektur neue Probleme gibt, dann bitte einen neuen Thread aufmachen.
wayoda
Posts: 362
Joined: Fri Dec 19, 2003 12:00 pm
Location: Wuppertal/Germany

Post by wayoda »

Hallo, das hier sieht mir auch noch verdächtig aus.

Code: Select all

UINT ReaderThreadFunc(LPVOID pParam) { 
    int sId = (int) pParam; 
    CHAR readValue[8]; 
    while (!exitThreads) { 
       printf("hallo\n"); 
       int ret = IowKitRead(sDevs[sId], IOW_PIPE_IO_PINS, readValue, sizeof(readValue)); 
       int err = GetLastError(); 
       printf("thread %d read %d bytes value %s %d\n", sId, ret, readValue, err); 
    } 
    AfxEndThread(0); 
    return 0; 
 } 
IowKitRead(..) wird immer mit size=8 aufgerufen! Bitte noch mal in der doku nachlesen welche Größen hier für die verschiedenen IOWarrior benutzt werden sollten.
In diesem Fall würde bei einem IOWarrior24 die Funktion erst zurück kehren wenn 2 Reports empfangen wurden! (Abgesehen von einem Timeout).
Ich nehme an das ist so nicht beabsichtigt?
Am besten verwendet man die Kontsanten IOWKIT_24_IO_REPORT_SIZE,
IOWKIT_40_IO_REPORT_SIZE, ...
Mit einer Fallunterscheidung nach Iowarrior-Typ vor dem Aufruf von IowKitRead() stell man damit sicher, das die Funktion zurückkommt wenn 1 Report gelesen wurde.

Eberhard
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Das ist schon geklaert. Das hier ist nur eine Demo. Schlimmstenfalls liest das mehrere Reports von einem IOWarrior 24. Sollte auch funktionieren.
Post Reply