CalculateEx Verständnisfrage.
CalculateEx Verständnisfrage.
Hallo Community,
ich beschäftige mich gerade mit der Prozedur:
void _stdcall CCalculateEx(double *PInput, double *POutput, double *PUser; StringParam PStrings)
Wenn ich jetzt am Eingang in1 eines BAuteils ein 16 bit Register anliegen habe, muss ich dann die Variable
in1 als DOUBLE-WERT in der Prozedur deklarieren ?
Nehmen wir an ich habe in dem 16 Bit Register eine 20051(dec) stehen.
20051(dec) enstpricht 4E 53 (hex).
Da ich noch mit dieser ZAhl arbeiten will, ist es wichtig fuer mich zu wissen, wie diese nun als double dargestellt wird ?
Mit Führende Nullen ??
Gruss Tim
//Edit
ich beschäftige mich gerade mit der Prozedur:
void _stdcall CCalculateEx(double *PInput, double *POutput, double *PUser; StringParam PStrings)
Wenn ich jetzt am Eingang in1 eines BAuteils ein 16 bit Register anliegen habe, muss ich dann die Variable
in1 als DOUBLE-WERT in der Prozedur deklarieren ?
Nehmen wir an ich habe in dem 16 Bit Register eine 20051(dec) stehen.
20051(dec) enstpricht 4E 53 (hex).
Da ich noch mit dieser ZAhl arbeiten will, ist es wichtig fuer mich zu wissen, wie diese nun als double dargestellt wird ?
Mit Führende Nullen ??
Gruss Tim
//Edit
MfG Tim
Re: CalculateEx Verständnisfrage.
Hallo WoB,
im Prinzip schon verstanden. Tu mich aber in der Umsetzung noch schwer, da ich in PureBAsic
programmiere.
also muss ich die Variable in1 ( Eingang1 ) als double deklarieren.
Dann weise ich der Variablen in1 dem Pointer zu.
Jetzt könnte ich nur über eine 2. VAriable in1_us, die z.b. unsigned short deklariert ist die Variable in1
zuweisen . Dann rechne ich mit der Variablen in1_us weiter.
im Prinzip schon verstanden. Tu mich aber in der Umsetzung noch schwer, da ich in PureBAsic
programmiere.
also muss ich die Variable in1 ( Eingang1 ) als double deklarieren.
Dann weise ich der Variablen in1 dem Pointer zu.
Jetzt könnte ich nur über eine 2. VAriable in1_us, die z.b. unsigned short deklariert ist die Variable in1
zuweisen . Dann rechne ich mit der Variablen in1_us weiter.
MfG Tim
Re: CalculateEx Verständnisfrage.
Noch eine Verständnisfrage:
Kann ich mit dieser Prozedur auf der einen Seite einen numerischen Wert über
den Pointer PINPUT verarbeiten und dann einen STRING an den PSTRING Pointer
übergeben ?
oder gibt es etwas zu beachten.
Kann ich mit dieser Prozedur auf der einen Seite einen numerischen Wert über
den Pointer PINPUT verarbeiten und dann einen STRING an den PSTRING Pointer
übergeben ?
oder gibt es etwas zu beachten.
MfG Tim
Re: CalculateEx Verständnisfrage.
Salü Tim,
vielleicht hast Du's zwischenzeitlich ja schon hingekriegt ?
Auch ich kenne Deine Umgebung nicht. Kann mir vorstellen, dass es auch bei Basic die peek/poke Funktionen gibt und Du sie einsetzen musst:
Um in Anwendungen auf Daten von PL zuzugreifen und sie zu PL zurückzugeben, dient schlussendlich immer ein Speicherbereich. PL zeigt in der Routine CalculateEx mit pointers genau dahin, wo diese Daten fein säuberlich als bytes aufgereiht liegen. Die Routine liefert halt mehrere Pointer (CalculateEx 4), weil es halt verschiedene "Rubriken" gibt (Inputs, Outputs, User, Strings)
In Euphoria muss ich mir nun Hilfsprozeduren anlegen, welche zusammengehörige Werte zunächst als einzelne bytes aus der richtigen "Rubrik" raus"picken" (peek), und sie sinngemäss konvertieren; somit kann ich danach in meiner Entwicklungsumgebug arbeiten, weil ich die rausgepickten und konvertierten bytes dann frei in meine eigenen Variablen zuweisen und verarbeiten kann:
Zu untenstehenden Routinen:
Wobei base_adr der von CalculateEx zugewiesene Pointer der entsprechenden Variablengruppe ist, und Offset der <modulo> Wert der gewünschten Variabeln (bei double float bilden 8 aufeinanderfolgende bytes den Wert, also ist bei floats <modulo> = 8
-- ..........................................................................................
-- holt einen float-Wert aus einer MemoryMap
function get_value(atom Base_adr, atom Offset)
atom val
val = float64_to_atom(peek({(Base_adr + Offset),atom_len})) -- hole Wert (8bytes) aus Memory Map
return val
end function
-- ..........................................................................................
-- speichert einen float-Wert in eine MemoryMap
procedure set_value(atom Base_adr, atom Offset, atom Wert)
sequence float_seq
float_seq = atom_to_float64(Wert) -- wandle Wert in eine Sequenz (8 bytes)
poke((Base_adr + Offset), float_seq) -- und lege diese in die MemoryMap zurück
end procedure
-- ..........................................................................................
-- holt einen String aus der String MemoryMap
function get_string(atom Base_adr, atom Offset)
atom pString, term
sequence buf
pString = peek4u(Base_adr + Offset) -- hole den passenden char Pointer
buf = peek({pString, max_nr_of_char}) -- extrahiere den String
term = find(0,buf) -- find nil char
buf = buf[1..term-1] -- extract relevant chars and strip nil char
return buf
end function
In der Hauptroutine kann ich dann mit z.B.
endian = get_value(PInput, ord)
"meine" float Variable <endian> vom PL Input Speicherbereich PInput + ord füllen, wobei ich vorgängig dafür gesorgt habe, dass <ord> so definiert ist, dass er an den relativen Anfang der 8 byte Aufreihung meines gewünschten Eingangswertes zeigt. PInput bleibt immer derselbe (während der Laufzeit der PL Anwendung) und zeigt auf den absoluten Anfang der Inputspeicher"rubrik".
Ich hoffe, dass Du hiermit etwas weiterkommst.
Viele Grüsse und en schööne Tag:
Thomas
vielleicht hast Du's zwischenzeitlich ja schon hingekriegt ?
Auch ich kenne Deine Umgebung nicht. Kann mir vorstellen, dass es auch bei Basic die peek/poke Funktionen gibt und Du sie einsetzen musst:
Um in Anwendungen auf Daten von PL zuzugreifen und sie zu PL zurückzugeben, dient schlussendlich immer ein Speicherbereich. PL zeigt in der Routine CalculateEx mit pointers genau dahin, wo diese Daten fein säuberlich als bytes aufgereiht liegen. Die Routine liefert halt mehrere Pointer (CalculateEx 4), weil es halt verschiedene "Rubriken" gibt (Inputs, Outputs, User, Strings)
In Euphoria muss ich mir nun Hilfsprozeduren anlegen, welche zusammengehörige Werte zunächst als einzelne bytes aus der richtigen "Rubrik" raus"picken" (peek), und sie sinngemäss konvertieren; somit kann ich danach in meiner Entwicklungsumgebug arbeiten, weil ich die rausgepickten und konvertierten bytes dann frei in meine eigenen Variablen zuweisen und verarbeiten kann:
Zu untenstehenden Routinen:
Wobei base_adr der von CalculateEx zugewiesene Pointer der entsprechenden Variablengruppe ist, und Offset der <modulo> Wert der gewünschten Variabeln (bei double float bilden 8 aufeinanderfolgende bytes den Wert, also ist bei floats <modulo> = 8
-- ..........................................................................................
-- holt einen float-Wert aus einer MemoryMap
function get_value(atom Base_adr, atom Offset)
atom val
val = float64_to_atom(peek({(Base_adr + Offset),atom_len})) -- hole Wert (8bytes) aus Memory Map
return val
end function
-- ..........................................................................................
-- speichert einen float-Wert in eine MemoryMap
procedure set_value(atom Base_adr, atom Offset, atom Wert)
sequence float_seq
float_seq = atom_to_float64(Wert) -- wandle Wert in eine Sequenz (8 bytes)
poke((Base_adr + Offset), float_seq) -- und lege diese in die MemoryMap zurück
end procedure
-- ..........................................................................................
-- holt einen String aus der String MemoryMap
function get_string(atom Base_adr, atom Offset)
atom pString, term
sequence buf
pString = peek4u(Base_adr + Offset) -- hole den passenden char Pointer
buf = peek({pString, max_nr_of_char}) -- extrahiere den String
term = find(0,buf) -- find nil char
buf = buf[1..term-1] -- extract relevant chars and strip nil char
return buf
end function
In der Hauptroutine kann ich dann mit z.B.
endian = get_value(PInput, ord)
"meine" float Variable <endian> vom PL Input Speicherbereich PInput + ord füllen, wobei ich vorgängig dafür gesorgt habe, dass <ord> so definiert ist, dass er an den relativen Anfang der 8 byte Aufreihung meines gewünschten Eingangswertes zeigt. PInput bleibt immer derselbe (während der Laufzeit der PL Anwendung) und zeigt auf den absoluten Anfang der Inputspeicher"rubrik".
Ich hoffe, dass Du hiermit etwas weiterkommst.
Viele Grüsse und en schööne Tag:
Thomas
Curiousity makes us progress !
Re: CalculateEx Verständnisfrage.
Salü Tim,
vielleicht hast Du's zwischenzeitlich ja schon hingekriegt ?
Auch ich kenne Deine Umgebung nicht. Kann mir vorstellen, dass es auch bei Basic die peek/poke Funktionen gibt und Du sie einsetzen musst:
Um in Anwendungen auf Daten von PL zuzugreifen und sie zu PL zurückzugeben, dient schlussendlich immer ein Speicherbereich. PL zeigt in der Routine CalculateEx mit pointers genau dahin, wo diese Daten fein säuberlich als bytes aufgereiht liegen. Die Routine liefert halt mehrere Pointer (CalculateEx 4), weil es halt verschiedene "Rubriken" gibt (Inputs, Outputs, User, Strings)
In Euphoria muss ich mir nun Hilfsprozeduren anlegen, welche zusammengehörige Werte zunächst als einzelne bytes aus der richtigen "Rubrik" raus"picken" (peek), und sie sinngemäss konvertieren; somit kann ich danach in meiner Entwicklungsumgebug arbeiten, weil ich die rausgepickten und konvertierten bytes dann frei in meine eigenen Variablen zuweisen und verarbeiten kann:
Zu untenstehenden Routinen:
Wobei base_adr der von CalculateEx zugewiesene Pointer der entsprechenden Variablengruppe ist, und Offset der <modulo> Wert der gewünschten Variabeln (bei double float bilden 8 aufeinanderfolgende bytes den Wert, also ist bei floats <modulo> = 8
-- ..........................................................................................
-- holt einen float-Wert aus einer MemoryMap
function get_value(atom Base_adr, atom Offset)
atom val
val = float64_to_atom(peek({(Base_adr + Offset),atom_len})) -- hole Wert (8bytes) aus Memory Map
return val
end function
-- ..........................................................................................
-- speichert einen float-Wert in eine MemoryMap
procedure set_value(atom Base_adr, atom Offset, atom Wert)
sequence float_seq
float_seq = atom_to_float64(Wert) -- wandle Wert in eine Sequenz (8 bytes)
poke((Base_adr + Offset), float_seq) -- und lege diese in die MemoryMap zurück
end procedure
-- ..........................................................................................
-- holt einen String aus der String MemoryMap
function get_string(atom Base_adr, atom Offset)
atom pString, term
sequence buf
pString = peek4u(Base_adr + Offset) -- hole den passenden char Pointer
buf = peek({pString, max_nr_of_char}) -- extrahiere den String
term = find(0,buf) -- find nil char
buf = buf[1..term-1] -- extract relevant chars and strip nil char
return buf
end function
In der Hauptroutine kann ich dann mit z.B.
endian = get_value(PInput, ord)
"meine" float Variable <endian> vom PL Input Speicherbereich PInput + ord füllen, wobei ich vorgängig dafür gesorgt habe, dass <ord> so definiert ist, dass er an den relativen Anfang der 8 byte Aufreihung meines gewünschten Eingangswertes zeigt. PInput bleibt immer derselbe (während der Laufzeit der PL Anwendung) und zeigt auf den absoluten Anfang der Inputspeicher"rubrik".
Ich hoffe, dass Du hiermit etwas weiterkommst.
Viele Grüsse und en schööne Tag:
Thomas
vielleicht hast Du's zwischenzeitlich ja schon hingekriegt ?
Auch ich kenne Deine Umgebung nicht. Kann mir vorstellen, dass es auch bei Basic die peek/poke Funktionen gibt und Du sie einsetzen musst:
Um in Anwendungen auf Daten von PL zuzugreifen und sie zu PL zurückzugeben, dient schlussendlich immer ein Speicherbereich. PL zeigt in der Routine CalculateEx mit pointers genau dahin, wo diese Daten fein säuberlich als bytes aufgereiht liegen. Die Routine liefert halt mehrere Pointer (CalculateEx 4), weil es halt verschiedene "Rubriken" gibt (Inputs, Outputs, User, Strings)
In Euphoria muss ich mir nun Hilfsprozeduren anlegen, welche zusammengehörige Werte zunächst als einzelne bytes aus der richtigen "Rubrik" raus"picken" (peek), und sie sinngemäss konvertieren; somit kann ich danach in meiner Entwicklungsumgebug arbeiten, weil ich die rausgepickten und konvertierten bytes dann frei in meine eigenen Variablen zuweisen und verarbeiten kann:
Zu untenstehenden Routinen:
Wobei base_adr der von CalculateEx zugewiesene Pointer der entsprechenden Variablengruppe ist, und Offset der <modulo> Wert der gewünschten Variabeln (bei double float bilden 8 aufeinanderfolgende bytes den Wert, also ist bei floats <modulo> = 8
-- ..........................................................................................
-- holt einen float-Wert aus einer MemoryMap
function get_value(atom Base_adr, atom Offset)
atom val
val = float64_to_atom(peek({(Base_adr + Offset),atom_len})) -- hole Wert (8bytes) aus Memory Map
return val
end function
-- ..........................................................................................
-- speichert einen float-Wert in eine MemoryMap
procedure set_value(atom Base_adr, atom Offset, atom Wert)
sequence float_seq
float_seq = atom_to_float64(Wert) -- wandle Wert in eine Sequenz (8 bytes)
poke((Base_adr + Offset), float_seq) -- und lege diese in die MemoryMap zurück
end procedure
-- ..........................................................................................
-- holt einen String aus der String MemoryMap
function get_string(atom Base_adr, atom Offset)
atom pString, term
sequence buf
pString = peek4u(Base_adr + Offset) -- hole den passenden char Pointer
buf = peek({pString, max_nr_of_char}) -- extrahiere den String
term = find(0,buf) -- find nil char
buf = buf[1..term-1] -- extract relevant chars and strip nil char
return buf
end function
In der Hauptroutine kann ich dann mit z.B.
endian = get_value(PInput, ord)
"meine" float Variable <endian> vom PL Input Speicherbereich PInput + ord füllen, wobei ich vorgängig dafür gesorgt habe, dass <ord> so definiert ist, dass er an den relativen Anfang der 8 byte Aufreihung meines gewünschten Eingangswertes zeigt. PInput bleibt immer derselbe (während der Laufzeit der PL Anwendung) und zeigt auf den absoluten Anfang der Inputspeicher"rubrik".
Ich hoffe, dass Du hiermit etwas weiterkommst.
Viele Grüsse und en schööne Tag:
Thomas
Curiousity makes us progress !
Re: CalculateEx Verständnisfrage.
Hallo Thomas,
danke fuer deine Antwort !.
In PureBasic sieht es so aus ( Auszug aus der DLL)
Wenn du dich erinnerst :wir sprachen mal über eine DLL , die ein 16 bit Register ausliesst und den Inhalt in ASCII zeichen umwandelt
und in der richtigen Reihenfolge am Ausgang des Bauteils zur Verfügung stellt
Ich hab diese DLL mal in PL getestet. Sie hat einen Eingang ( 16 Bit register wird gelesen) und einen Ausgang ( String ) wo die beiden ASCII zeichen ausgegeben werden sollen. Wenn ich diese DLL 4 mal in PL anwende, funktioniert noch alles.
Wenn ich sie mehr als 4 mal anwende bekomme ich den Fehler:
Zugriffsverletzung bei Adresse 0186294B im Modul test.dll. Schreiben von Adresse 0000 0000.
Nun bin ich mir nicht sicher, ob bei dieser "Pointerei" irgendwas schief läuft. Vlt. ist ja auch die Typumwandlung nicht ok.
danke fuer deine Antwort !.
Denn Sinn der Prozedur habe ich verstanden. Das Bindeglied sind immer die Speicherbereiche, die PL zur Verfügung stellt.tom_g hat geschrieben:Salü Tim,
vielleicht hast Du's zwischenzeitlich ja schon hingekriegt ?
Auch ich kenne Deine Umgebung nicht. Kann mir vorstellen, dass es auch bei Basic die peek/poke Funktionen gibt und Du sie einsetzen musst:
Um in Anwendungen auf Daten von PL zuzugreifen und sie zu PL zurückzugeben, dient schlussendlich immer ein Speicherbereich. PL zeigt in der Routine CalculateEx mit pointers genau dahin, wo diese Daten fein säuberlich als bytes aufgereiht liegen. Die Routine liefert halt mehrere Pointer (CalculateEx 4), weil es halt verschiedene "Rubriken" gibt (Inputs, Outputs, User, Strings)
Thomas
In PureBasic sieht es so aus ( Auszug aus der DLL)
Code: Alles auswählen
Structure sDLLParams
DLLParam.d[100]
EndStructure
Structure sStringParams
StringParam.s[100]
EndStructure
...
...
...
ProcedureDLL CCalculateEx(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams,*PStrings.sStringParams)
Protected in1.d,out1.s,in1_typ_u.u ; in1 double out1 string in1_typ_u unicode
; in1 erhält Inhalt eines 16 bit Registers
in1.d = *PInput\DLLParam[0]
; Es folgt Typumwandlung von double zu unicode
in1_typ_u.u=in1
; Vertauschen der Bytereihenfolge (Endianness) und Umwandlung in 2 Ascii Zeichen
out1 = PeekS(@in1_typ_u, 2)
;Übergabe des ASCII Strings ( 2 Byte )
*PStrings\StringParam[0] = out1
EndProcedure
....
....
und in der richtigen Reihenfolge am Ausgang des Bauteils zur Verfügung stellt
Ich hab diese DLL mal in PL getestet. Sie hat einen Eingang ( 16 Bit register wird gelesen) und einen Ausgang ( String ) wo die beiden ASCII zeichen ausgegeben werden sollen. Wenn ich diese DLL 4 mal in PL anwende, funktioniert noch alles.
Wenn ich sie mehr als 4 mal anwende bekomme ich den Fehler:
Zugriffsverletzung bei Adresse 0186294B im Modul test.dll. Schreiben von Adresse 0000 0000.
Nun bin ich mir nicht sicher, ob bei dieser "Pointerei" irgendwas schief läuft. Vlt. ist ja auch die Typumwandlung nicht ok.
Zuletzt geändert von twofel am Dienstag 26. März 2013, 09:40, insgesamt 1-mal geändert.
MfG Tim
Re: CalculateEx Verständnisfrage.
Hoi Tim,
Mehr als 4mal heisst, mehr als 4 Instanzen der DLL in deiner PL Anwendung platziert ?
ich kann nicht beurteilen, ob Overhead (Speicher) oder Timing ein mögliches Problem darstellt ? Oder in der DLL interne Vorgänge ? Oder der Compilevorgang zur Herstellung der DLL ?
Wie würde ich vorgehen:
- schrittweise debuggen:
Mach mal ne ganz leere DLL, dann eine mit nur In, dann mit In+ Out, dann mit gemischten In/Out und versch. Typen, dann mit "Innereien", zunächst ohne Uniocode-Umwandlung..., z.B. mit einer banalen Addition eines Testzähler..oder sowas, und setze diese mehrfach in ein PL-Projekt. Beobachte das Verhalten.
Beim Untersuch ob Timing kannst Du die einzelnen DLL dynamisch programmieren, d.h. die interne Abarbeitung auf einen Triggerwert synchronisiert ablaufen lassen, so wie in den DLL Beispielen von PL.
Wenn Du das Innenleben verfolgen willst, kannst Du print-Anweisungen einfügen; diese schreiben aus der DLL in ein neben PL öffnendes Konsolenfenster, wo Du Deine Ausgaben verfolgen kannst (die Text-Ausgaben in die Konsole bremsen die Zyklusgeschwindigkeit stark ab, aber das Prinzip funktioniert)
Viele Grüsse von Thomas
Mehr als 4mal heisst, mehr als 4 Instanzen der DLL in deiner PL Anwendung platziert ?
ich kann nicht beurteilen, ob Overhead (Speicher) oder Timing ein mögliches Problem darstellt ? Oder in der DLL interne Vorgänge ? Oder der Compilevorgang zur Herstellung der DLL ?
Wie würde ich vorgehen:
- schrittweise debuggen:
Mach mal ne ganz leere DLL, dann eine mit nur In, dann mit In+ Out, dann mit gemischten In/Out und versch. Typen, dann mit "Innereien", zunächst ohne Uniocode-Umwandlung..., z.B. mit einer banalen Addition eines Testzähler..oder sowas, und setze diese mehrfach in ein PL-Projekt. Beobachte das Verhalten.
Beim Untersuch ob Timing kannst Du die einzelnen DLL dynamisch programmieren, d.h. die interne Abarbeitung auf einen Triggerwert synchronisiert ablaufen lassen, so wie in den DLL Beispielen von PL.
Wenn Du das Innenleben verfolgen willst, kannst Du print-Anweisungen einfügen; diese schreiben aus der DLL in ein neben PL öffnendes Konsolenfenster, wo Du Deine Ausgaben verfolgen kannst (die Text-Ausgaben in die Konsole bremsen die Zyklusgeschwindigkeit stark ab, aber das Prinzip funktioniert)
Viele Grüsse von Thomas
Curiousity makes us progress !
Re: CalculateEx Verständnisfrage.
Hallo Thomas,
werde mal so vorgehen.
1) leere DLL---hat funktioniert, keine Probleme.
2) DLL nur mit INPUT---hat funktioniert, Strings werden aber 1:1 an die Ausgänge durchgereicht.
Also was aus den Registern rauskommt, steht auch an den Ausgängen der DLL Bausteine.
Das ist das, was ich auch nicht so richtig verstehe, wenn ich jetzt einen Eingang lese, lade ich ja den Inhalt z.b.
eines Registers, mache irgendwas in meiner Prozedur und gebe das Rechenergebnis als String auf den Ausgang$.
Ist das richtig so?..gibt es da nicht Speicherkonflikte, wenn zuvor "ohne Rechnerei in der Prozedur", die EIngänge 1:1
durchgereicht werden ? ich steh aufm Schlauch
3) jetzt mit INPUT , ohne "innere Rechnerei" nur PSTRING Ausgabe.
Das ging auch....gab nur einmal bei der dritten Instanz eine Zugriffsverletzung. Aber dann nochmal von vorn angefangen und 8 Instanzen
der DLL erzeugt. Komischerweise ging das dann. Als String wird leerer String übergeben.
4)....So jetzt INPUT und PSTRING, unicode Umwandlung und Rechnerei....komischerweise hatte ich jetzt keine Probleme....
bis zur 10. Instanz dieser DLL....ab der 11. Instanz der DLL kam dann wieder die Meldung der Zugriffsverletzung.
//Edit 5x
werde mal so vorgehen.
1) leere DLL---hat funktioniert, keine Probleme.
2) DLL nur mit INPUT---hat funktioniert, Strings werden aber 1:1 an die Ausgänge durchgereicht.
Also was aus den Registern rauskommt, steht auch an den Ausgängen der DLL Bausteine.
Das ist das, was ich auch nicht so richtig verstehe, wenn ich jetzt einen Eingang lese, lade ich ja den Inhalt z.b.
eines Registers, mache irgendwas in meiner Prozedur und gebe das Rechenergebnis als String auf den Ausgang$.
Ist das richtig so?..gibt es da nicht Speicherkonflikte, wenn zuvor "ohne Rechnerei in der Prozedur", die EIngänge 1:1
durchgereicht werden ? ich steh aufm Schlauch
3) jetzt mit INPUT , ohne "innere Rechnerei" nur PSTRING Ausgabe.
Code: Alles auswählen
ProcedureDLL CCalculateEx(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams,*PStrings.sStringParams)
Protected in1.d,out1.s,in1_typ_u.u,i.i
; in1 erhält Inhalt eines 16 bit Registers
in1 = *PInput\DLLParam[0]
;Übergabe des ASCII Strings
*PStrings\StringParam[0] = out1
der DLL erzeugt. Komischerweise ging das dann. Als String wird leerer String übergeben.
4)....So jetzt INPUT und PSTRING, unicode Umwandlung und Rechnerei....komischerweise hatte ich jetzt keine Probleme....
bis zur 10. Instanz dieser DLL....ab der 11. Instanz der DLL kam dann wieder die Meldung der Zugriffsverletzung.
//Edit 5x
MfG Tim
Re: CalculateEx Verständnisfrage.
Hi Tim,
ich kann mir keinen Reim drauf machen, was hier passiert.
Teste doch zunächst nur mit Verarbeitung von floats. Wenn es dann problemlos geht, hat das Problem wohl mit Zuweisung, Konversion, Strings zu tun.
Im Zusammenhang mit der Verwendung von Strings kommt mir noch der String-Abschluss in den Sinn: Strings sind typischerweise (immer ?) mit dem character 0 = byte = 0 terminiert.
Ob dies bei Dir automatisch durch die Zuweisung geschieht und wie PL bei fehlendem Nullbyte am Schluss damit umgeht, weiss ich nicht.
Jedenfalls liefert PL einen Nullcharakter mit, wenn ein String als Eingang verwendet wird.
In Euphoria suche ich nach ihm im buf-array und beschneide dieses auf die relevante Länge (ohne den Null-char):
-- ..........................................................................................
-- holt einen String aus der String MemoryMap
function get_string(atom Base_adr, atom Offset)
atom pString, term
sequence buf
pString = peek4u(Base_adr + Offset) -- hole den passenden char Pointer
buf = peek({pString, max_nr_of_char}) -- extrahiere den String
term = find(0,buf) -- find nil char
buf = buf[1..term-1] -- extract relevant chars and strip nil char
return buf
end function
Grüsse von Thomas
ich kann mir keinen Reim drauf machen, was hier passiert.
Teste doch zunächst nur mit Verarbeitung von floats. Wenn es dann problemlos geht, hat das Problem wohl mit Zuweisung, Konversion, Strings zu tun.
Im Zusammenhang mit der Verwendung von Strings kommt mir noch der String-Abschluss in den Sinn: Strings sind typischerweise (immer ?) mit dem character 0 = byte = 0 terminiert.
Ob dies bei Dir automatisch durch die Zuweisung geschieht und wie PL bei fehlendem Nullbyte am Schluss damit umgeht, weiss ich nicht.
Jedenfalls liefert PL einen Nullcharakter mit, wenn ein String als Eingang verwendet wird.
In Euphoria suche ich nach ihm im buf-array und beschneide dieses auf die relevante Länge (ohne den Null-char):
-- ..........................................................................................
-- holt einen String aus der String MemoryMap
function get_string(atom Base_adr, atom Offset)
atom pString, term
sequence buf
pString = peek4u(Base_adr + Offset) -- hole den passenden char Pointer
buf = peek({pString, max_nr_of_char}) -- extrahiere den String
term = find(0,buf) -- find nil char
buf = buf[1..term-1] -- extract relevant chars and strip nil char
return buf
end function
Grüsse von Thomas
Curiousity makes us progress !
Re: CalculateEx Verständnisfrage.
Hallo Thomas,
Also muß ich den Fehler in der Typumwandlung oder Stringverarbeitung suchen. Da muss ich nochmal schaun.
HAbe jetzt die DLL nur mit double Werten getestet...Diesesmal 16 Instanzen erzeugt, das funktioniert ohne Probleme.tom_g hat geschrieben:Hi Tim,
Teste doch zunächst nur mit Verarbeitung von floats. Wenn es dann problemlos geht, hat das Problem wohl mit Zuweisung, Konversion, Strings zu tun.
Grüsse von Thomas
Code: Alles auswählen
ProcedureDLL CCalculateEx(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams,*PStrings.sStringParams)
Protected in1.d,out1.d,in1_typ_u.u,i.i
in1 = *PInput\DLLParam[0]
out1 = in1 *2
*POutput\DLLParam[0] = out1
EndProcedure
MfG Tim
Re: CalculateEx Verständnisfrage.
Viel Glück, Tim !
Sag dann was, wenn Du's gefunden hast
Sag dann was, wenn Du's gefunden hast
Curiousity makes us progress !
Re: CalculateEx Verständnisfrage.
Hier mal die Eingabe als Zahl und Ausgabe als String (Hexadezimal) mit PureBasic:
Code: Alles auswählen
EnableExplicit
#Inputs = 1
#Outputs = 1
Structure sDLLParams
DLLParam.d[101]
EndStructure
Structure sStringParams
StringParam.i[101]
EndStructure
; return number of input channels...
ProcedureDLL.a NumInputs()
ProcedureReturn #Inputs
EndProcedure
; return number of output channels...
ProcedureDLL.a NumOutputs()
ProcedureReturn #Outputs
EndProcedure
; return name for each input...
ProcedureDLL GetInputName(Channel.a, *Name)
Protected GetInputName.s
If Channel = 0
GetInputName = "E1"
Else
GetInputName = "U"
EndIf
PokeS(*Name, GetInputName, -1, #PB_Ascii)
EndProcedure
; return name for each output...
ProcedureDLL GetOutputName(Channel.a, *Name)
Protected GetOutputName.s
If Channel = 0
GetOutputName = "$A1"
Else
GetOutputName = "U"
EndIf
PokeS(*Name, GetOutputName, -1, #PB_Ascii)
EndProcedure
; check inputs and set outputs while running...
ProcedureDLL CCalculateEx(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams, *PStrings.sStringParams)
Protected in1.d, out1.s, in1_typ_u.u
in1 = *PInput\DLLParam[0]
in1_typ_u = in1
out1 = RSet(Hex(in1_typ_u), 4, "0")
PokeS(*PStrings\StringParam[0], out1, -1, #PB_Ascii)
EndProcedure
; called when project is started...
ProcedureDLL CSimStart(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)
; nothing to do...
EndProcedure
; called when project is stopped...
ProcedureDLL CSimStop(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)
; nothing to do...
EndProcedure
; ; called when button CONFIGURE is pressed in dialogue...
; ProcedureDLL CConfigure(*PUser.sDLLParams)
;
; MessageRequester("Configure", "Nothing to configure")
;
; EndProcedure
Windows 7 64bit Ultimate
Re: CalculateEx Verständnisfrage.
Hallo Chris und Thomas,
danke dir Chris fuer den Code, der mir die "POINTERKOPFSCHMERZEN" nahm
Thomas hatte schon den richtigen Riecher und du Chris hast es uns mit deinem Code gezeigt,
des der "nullterminierte String" eben doch wichtig ist.
Das hatte ich nämlich in meinen Codes nicht berücksichtigt.
Ich habe den Code ein bischen geändert, da die beiden Hex-Werte für meinen Anwendungsfall
in der Reihenfolge geändert werden müssen.
Man....das war aber auch eine Wuselei....aber immerhin fuer mich die Erkenntnis...."NULL-terminierter String" ist wichtig.
Dann kann ich ja beruhigt heute Abend Fussball ( Deutschland:Kasachstan) gucken.
Vielen Dank an euch beiden fuer eure konstruktive Hilfe.
PS: @Chris .....warum 101 Speicherplätze und nicht 100 ?
//Edit
danke dir Chris fuer den Code, der mir die "POINTERKOPFSCHMERZEN" nahm
Thomas hatte schon den richtigen Riecher und du Chris hast es uns mit deinem Code gezeigt,
des der "nullterminierte String" eben doch wichtig ist.
Das hatte ich nämlich in meinen Codes nicht berücksichtigt.
Ich habe den Code ein bischen geändert, da die beiden Hex-Werte für meinen Anwendungsfall
in der Reihenfolge geändert werden müssen.
Code: Alles auswählen
EnableExplicit
#Inputs = 1
#Outputs = 1
Structure sDLLParams
DLLParam.d[101]
EndStructure
Structure sStringParams
StringParam.i[101]
EndStructure
; return number of input channels...
ProcedureDLL.a NumInputs()
ProcedureReturn #Inputs
EndProcedure
; return number of output channels...
ProcedureDLL.a NumOutputs()
ProcedureReturn #Outputs
EndProcedure
; return name for each input...
ProcedureDLL GetInputName(Channel.a, *Name)
Protected GetInputName.s
If Channel = 0
GetInputName = "E1"
Else
GetInputName = "U"
EndIf
PokeS(*Name, GetInputName, -1, #PB_Ascii)
EndProcedure
; return name for each output...
ProcedureDLL GetOutputName(Channel.a, *Name)
Protected GetOutputName.s
If Channel = 0
GetOutputName = "$A1"
Else
GetOutputName = "U"
EndIf
PokeS(*Name, GetOutputName, -1, #PB_Ascii)
EndProcedure
;=======================================================================================================================
; check inputs and set outputs while running...
ProcedureDLL CCalculateEx(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams, *PStrings.sStringParams)
Protected in1.d, out1.s, in1_typ_u.u
;Übernahme des double Wertes vom Eingang 1 über InputPointer
in1 = *PInput\DLLParam[0]
;Typwandlung von double in unicode
in1_typ_u = in1
;Einlesen des Strings von Adresse @in1_typ_u, der PeekS Befehl garantiert mir die gewünschte Reihenfolge der beiden ASCII- Zeichen
out1 = PeekS(@in1_typ_u, 2)
; Schreibt einen String an die angegebene Speicheradresse, gefolgt von einem Null-Zeichen für den
; Abschluss ("null-terminierter" String).
;
PokeS(*PStrings\StringParam[0], out1, -1, #PB_Ascii)
EndProcedure
;====================================================================================================================
; called when project is started...
ProcedureDLL CSimStart(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)
; nothing to do...
EndProcedure
; called when project is stopped...
ProcedureDLL CSimStop(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)
; nothing to do...
EndProcedure
; ; called when button CONFIGURE is pressed in dialogue...
; ProcedureDLL CConfigure(*PUser.sDLLParams)
;
; MessageRequester("Configure", "Nothing to configure")
;
; EndProcedure
Dann kann ich ja beruhigt heute Abend Fussball ( Deutschland:Kasachstan) gucken.
Vielen Dank an euch beiden fuer eure konstruktive Hilfe.
PS: @Chris .....warum 101 Speicherplätze und nicht 100 ?
//Edit
MfG Tim
Re: CalculateEx Verständnisfrage.
101 Speicherplätze:
in der Hilfe ist ein Array von 0..100 deklariert und
bei *PUser.sDLLParams steht auf Speicherplatz 101
die Nummer des DLL-Bauteils.
in der Hilfe ist ein Array von 0..100 deklariert und
bei *PUser.sDLLParams steht auf Speicherplatz 101
die Nummer des DLL-Bauteils.
Windows 7 64bit Ultimate