IowKitReadImmediate blockiert unter Windows
Moderator: Guido Körber
IowKitReadImmediate blockiert unter Windows
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
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
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm
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?
[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?
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm
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
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;
}
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm
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.
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.
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
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
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm
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.
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.
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.
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.
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm
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.
Man kann uebrigens (zwar eher theoretisch) IOWarrior mit der gleichen Seriennummer haben. Das ist der Fall wenn man verschiedene IOWarrior (24, 40, 56) einsetzt.
-
- Site Admin
- Posts: 2876
- Joined: Tue Nov 25, 2003 10:25 pm
- Location: Germany/Berlin
- Contact:
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.
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm
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.
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.
Hallo, das hier sieht mir auch noch verdächtig aus.
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
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;
}
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
-
- Posts: 543
- Joined: Mon Dec 01, 2003 6:09 pm