Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

Bitverschiebung?

 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 13.05.2015, 00:55    Titel: Bitverschiebung? Antworten mit Zitat

Code:

   'Eingabedaten
   Prio = &h00
   mainCommand = &h00
   SubCommand = &h00   
   Hash = &h4711
   DLC = &h05

   hash = ((((UID AND &h0000FFFF) XOR (UID SHR 16)) AND &hFF7F) OR &h0300)
   StartWord = (((Prio SHL 12) + (mainCommand SHL 1) + (ResponseBit AND 1)) AND &hFFFF)
   DataBytes(0) = ((UID SHR 24) AND &hFF)
   DataBytes(1) = ((UID SHR 16) AND &hFF)
   DataBytes(2) = ((UID SHR  8) AND &hFF)
   DataBytes(3) = ((UID SHR  0) AND &hFF)
   DataBytes(4) = ((Funktionen(l) SHR 8) AND &hFF)
   DataBytes(5) = (Funktionen(l) AND &hFF)

   ' als String darstellen
   SendingString = CHR((StartWord SHR 8) AND &hFF) + CHR(StartWord AND &hFF)
   SendingString = SendingString + CHR((Hash SHR 8) AND &hFF) + CHR(Hash AND &hFF)
   SendingString = SendingString + CHR(DLC AND &hFF)
   FOR j = 0 TO 7
      SendingString = SendingString + CHR(DataBytes(j) AND &hFF)  ' wir gehen mit "AND &hFF" auf Nummer sicher...
   NEXT

   SendingString = LEFT(SendingString, 13)


Mit obigen Code werden Daten kodiert! Wie Decodiere ich das ganze wieder? Wie muss ich die Bits korrekt verschieben, damit das ganze wieder dekodiert wird? Ich stehe momentan etwas auf dem Schlauch. Es sollen die Daten zum Schluss in die obenstehende Eingabedaten gespeichert werden zur weiteren Auswertung. Vorallem weil die Bits logisch verknüpft wurden, bin ich etwas überfragt? Wie entknüpfe ich die wieder?

Vielleicht komme ich selber noch drauf? Bin seit geraumer Zeit am rumexperimentieren.

Gruß
ALWIM
_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
St_W



Anmeldungsdatum: 22.07.2007
Beiträge: 949
Wohnort: Austria

BeitragVerfasst am: 13.05.2015, 10:06    Titel: Re: Bitverschiebung? Antworten mit Zitat

ALWIM hat Folgendes geschrieben:
Mit obigen Code werden Daten kodiert! Wie Decodiere ich das ganze wieder? Wie muss ich die Bits korrekt verschieben, damit das ganze wieder dekodiert wird? Ich stehe momentan etwas auf dem Schlauch. Es sollen die Daten zum Schluss in die obenstehende Eingabedaten gespeichert werden zur weiteren Auswertung. Vorallem weil die Bits logisch verknüpft wurden, bin ich etwas überfragt? Wie entknüpfe ich die wieder?

Na ganz einfach indem du sie wieder zurückschiebst, mit einer Maske die entsprechenden Bits maskierst und dann ggf. mit anderen Teilen des Werts ver-oder-st.
z.B. für "DataBytes(1) = ((UID SHR 16) AND &hFF)" erhältst du den original-Teil von UID durch UID = UID OR ((DataBytes(1) and &hff) shl 16)
Auf diesselbe oder ähnliche Art und Weise funktioniert das auch für den ganzen Rest.


ALWIM hat Folgendes geschrieben:
Vielleicht komme ich selber noch drauf? Bin seit geraumer Zeit am rumexperimentieren.
Dann hättest du aber schon längst selber drauf kommen sollen. Aber da du offenbar nur Code-Schnipsel von irgendwoher zusammenkopierst, die du dann nicht verstehst, anstatt sich selber Gedanken zu machen und den Code selber zu schreiben, wird sich das vermutlich auch nicht bessern.
_________________
Aktuelle FreeBasic Builds, Projekte, Code-Snippets unter http://users.freebasic-portal.de/stw/
http://www.mv-lacken.at Musikverein Lacken (MV Lacken)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 13.05.2015, 10:33    Titel: Antworten mit Zitat

Den geposteten Code habe ich selber geschrieben.
Mir ist bewusst, dass ich die wieder zurückschieben muss. Durch die ganze Verknüpfung komme ich ein wenig durcheinander.

Gruß
ALWIM
_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1211
Wohnort: Ruhrpott

BeitragVerfasst am: 13.05.2015, 12:04    Titel: Antworten mit Zitat

Ich muß St_W recht geben und frage mich, wer (von der Logik her) diesen Code verbrochen hat. Kopf schütteln Das war doch bestimmt mal ein Stück C, das 1:1 nach FB übertragen wurde. Und die byteweise Verarbeitung lässt auf ein Programm für einen 8bit Mikrocontroller schliessen. Stimmts? lächeln

Vielleicht hilft dir ja ein kleiner Schubs in die richtige Richtung weiter:

SendingString besteht zum Schluß aus: 16bit StartWord + 16bit hash + 8bit DLC + 24bit UID + 16bit Funktionen(1)
StartWord besteht aus: Prio * 4096 + mainCommand * 2 + ResponseBit

Da ist zum Zurückrechnen also eher "isolieren" als "dekodieren" angesagt.

Gruß
grindstone
_________________
For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 13.05.2015, 12:48    Titel: Antworten mit Zitat

Das wird mit meinem Programm angesteuert:
http://medienpdb.maerklin.de/digital22008/files/cs2CAN-Protokoll-2_0.pdf

Nach dieser PDF-Datei wurde das Programm geschrieben. Der gepostete Quellcode ist nur ein Teil von dem Programm was ich geschrieben habe. Das Gerät wird bereits erfolgreich mit meinem Programm gesteuert.

Gruß
ALWIM
_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
volta



Anmeldungsdatum: 04.05.2005
Beiträge: 1875
Wohnort: D59192

BeitragVerfasst am: 13.05.2015, 17:54    Titel: Antworten mit Zitat

Hi,
statt der vielen SHR, das geht in FB viiiiel einfacher
Code:
Dim As ULong UID = &h12345678
Dim As UByte DataByte(3)

Asm  mov eax,[UID]
Asm  bswap eax
Asm  mov [DataByte],eax

?Hex(DataByte(0))
?Hex(DataByte(1))
?Hex(DataByte(2))
?Hex(DataByte(3))
Sleep
lachen
_________________
Warnung an Choleriker:
Dieser Beitrag kann Spuren von Ironie & Sarkasmus enthalten.
Zu Risiken & Nebenwirkungen fragen Sie Ihren Therapeuten oder Psychiater.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 13.05.2015, 20:15    Titel: Antworten mit Zitat

volta hat Folgendes geschrieben:
Hi,
statt der vielen SHR, das geht in FB viiiiel einfacher
Code:
Dim As ULong UID = &h12345678
Dim As UByte DataByte(3)

Asm  mov eax,[UID]
Asm  bswap eax
Asm  mov [DataByte],eax

?Hex(DataByte(0))
?Hex(DataByte(1))
?Hex(DataByte(2))
?Hex(DataByte(3))
Sleep
lachen

Da komme ich jetzt nicht mit? Was bewirken die Assemblerzeilen denn?
Vielleicht kannst du mich aufklären?

Gruß
ALWIM
_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
St_W



Anmeldungsdatum: 22.07.2007
Beiträge: 949
Wohnort: Austria

BeitragVerfasst am: 13.05.2015, 21:15    Titel: Antworten mit Zitat

ALWIM hat Folgendes geschrieben:
[...]
Da komme ich jetzt nicht mit? Was bewirken die Assemblerzeilen denn?
Vielleicht kannst du mich aufklären?

BSWAP kehrt die Byte Reihenfolge um. d.h. aus &h12345678 wird &h78563412. Dieser Wert wird dann in das Array DataByte gespeichert. Aufgrund der Little-Endian Byte-Reihenfolge der Intel x86 Architektur findet sich dann &h12 auf der niedrigsten Adresse (Array-Index 0), &h78 an der höchsten (Array-Index 3).
_________________
Aktuelle FreeBasic Builds, Projekte, Code-Snippets unter http://users.freebasic-portal.de/stw/
http://www.mv-lacken.at Musikverein Lacken (MV Lacken)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1211
Wohnort: Ruhrpott

BeitragVerfasst am: 14.05.2015, 11:05    Titel: Antworten mit Zitat

@ALWIM:

Ich merke schon, du siehst den Wald vor lauter Bäumen nicht. Ist doch ganz einfach: zwinkern

Code:
StartWord = Left(SendingString,2)
prio = (MkShort(StartWord) And %1111000000000000) Shr 12
comm = (MkShort(StartWord) And %0000000111111110) Shr 1
resp = (MkShort(StartWord) And %0000000000000001)
 DLC = Asc(Mid(SendString,5,1)) And %00001111)
UID = Cvi(Mid(SendingString,6,4))
subCMD = Asc(Mid(SendingString,10,1)
kanal = Asc(Mid(SendingString,11,1)
wert = CVShort(Asc(Mid(SendingString,12,2)


Und du bist wirklich sicher, daß dein geposteter Code funktioniert? Bei dir ist DLC nämlich 8 Bit lang, in der Protokollbeschreibung nur 4 Bit.

Laut Protokoll müsste die Decodierung so gehen:

Code:
prio = HiByte (MkShort(Left(SendingString,2)) Shr 1)
comm = LoByte (MkShort(Left(SendingString,2)) Shr 1)
resp = MkShort(Left(SendingString,2)) And 1
DLC = SendString[4] Shr 4
UID = (Cvi(Mid(SendString,5,4) Shl 4) + (SendString[8] Shr 4)
comm = (SendString[8] Shl 4) + (SendString[9] Shr 4)
byte5 = (SendString[9] Shl 4) + (SendString[10] Shr 4)
byte6 = (SendString[10] Shl 4) + (SendString[11] Shr 4)
byte7 = (SendString[11] Shl 4) + (SendString[12] Shr 4)


Gruß
grindstone
_________________
For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 14.05.2015, 14:40    Titel: Antworten mit Zitat

Zitat:
Ich merke schon, du siehst den Wald vor lauter Bäumen nicht. Ist doch ganz einfach: zwinkern
Hey, was soll das jetzt? verwundert
Ich bin doch noch nicht dazu gekommen, die Sache zu schreiben! Mittlerweile weiß ich wo ich den Hebel ansetzen muss. Teilweise bin ich auch einfach nur zu müde an dem Projekt etwas zu machen. Ein Großteil der Programme/Quellcodes werden von mir in der Nacht zwischen 23.00 Uhr und 02.00 Uhr entwickelt! Das Ding schreibe ich trotzdem selber. Schaue mir den Quellcode gar nicht mal an.

Gruß
ALWIM
_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1211
Wohnort: Ruhrpott

BeitragVerfasst am: 15.05.2015, 05:36    Titel: Antworten mit Zitat

ALWIM hat Folgendes geschrieben:
Hey, was soll das jetzt? verwundert
Das ist westfälischer Humor. Da kann ich nichts für, das ist genetisch bedingt. grinsen Und "Den Wald vor lauter Bäumen nicht sehen" ist eine Redensart, die soviel bedeutet wie "Die Übersicht verloren haben".

Außerdem muß ich mich korrigieren: Dein Programm bearbeitet ja nicht den originalen CS2 - Datenstrom, sondern den entsprechenden Ethernet - String, und da arbeitet es korrekt - wenn auch etwas umständlich. Unter Verwendung der durch FB gegebenen Möglichkeiten könnte man es zu
Code:
hash = (((LoWord(UID) Xor HiWord(UID)) And &hFF7F) Or &h0300)
StartWord = (Prio Shl 12) + (mainCommand Shl 1) + (ResponseBit And 1)
SendingString = MkShort(StartWord) & MkShort(hash) & Chr(DLC) & MkLongint(UID) & MkShort(Funktionen(1)) & Chr(DataBytes(6)) & Chr(DataBytes(7))
vereinfachen.

Und auch in meinem Decodervorschlag sind einige Fehler drin (da war ich wohl auch etwas müde). So müsste es richtig sein:
Code:
rPrio = (SendingString[0] And %11110000) Shr 4
rComm = (CVShort(Left(SendingString,2)) And %0000000111111110) Shr 1
rResp = SendingString[1] And 1
rHash = CVShort(Mid(SendingString,3,2))
 rDLC = SendingString[4]
rUID = Cvi(Mid(SendingString,6,4))
rSubCMD = SendingString[9] '= byte 4
rByte5 = SendingString[10]
rByte6 = SendingString[11]
rByte7 = SendingString[12]


Aber ich glaube, dein eigentliches Problem ist der Hash - Wert. Der kann, so wie er gebildet wurde, prinzipiell nicht mehr decodiert werden. Er dient auch lediglich der Integritätsprüfung der übermittelten Daten. Du kannst aus der empfangenen UID einen neuen Hash - Wert bilden und diesen mit dem empfangenen Hash - Wert vergleichen. Stimmen beide nicht überein, liegt ein Übermittlungsfehler vor.
Code:
If rHash <> (((LoWord(rUID) Xor HiWord(rUID)) And &hFF7F) Or &h0300) Then
   Print "Fehler"
EndIf


Gruß
grindstone
_________________
For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
volta



Anmeldungsdatum: 04.05.2005
Beiträge: 1875
Wohnort: D59192

BeitragVerfasst am: 15.05.2015, 10:16    Titel: Antworten mit Zitat

Hi Landsmann,
grindstone hat Folgendes geschrieben:
Das ist westfälischer Humor. Da kann ich nichts für, das ist genetisch bedingt. grinsen

so geht es mir auch lachen
_________________
Warnung an Choleriker:
Dieser Beitrag kann Spuren von Ironie & Sarkasmus enthalten.
Zu Risiken & Nebenwirkungen fragen Sie Ihren Therapeuten oder Psychiater.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 15.05.2015, 11:37    Titel: Antworten mit Zitat

Die CS2 sendet ja automatisch Meldungen an den PC.

Mit der Sub:
Code:
SUB TSNE_NEWDATAUDP (BYVAL V_TSNEID AS UINTEGER, BYVAL V_IPA AS STRING, BYREF V_Data AS STRING)


werden die Daten in der Variable V_Data gespeichert/angezeigt.
In dem gleichen Format wie ich sie an die CS2 versende!


Sobald ich
Code:
byte7 = (V_Data[1] SHR 1)

nehme zeigt er mir das mainCommand an.

Ich dachte mir dann das
Code:
byte4 = (V_Data[9] SHL 4)   
byte5 = (V_Data[10] SHR 4)
die Geschwindigkeit anzeigt? Allerdings wird ein Wert von 0 bis 62 angezeigt??? Was das für ein Wert ist? Keine Ahnung. Der Wert sollte doch von 0 bis 1000 gehen?

Entweder richtig ermittelt, oder doch falsch die Bits verschoben?

Dein Code funktioniert irgendwie nicht? Ich brauche die Decodierung aus der Variable V_Data. Denn dort kommen alle Daten an!

Zitat:
Und du bist wirklich sicher, daß dein geposteter Code funktioniert? Bei dir ist DLC nämlich 8 Bit lang, in der Protokollbeschreibung nur 4 Bit.

Der bisherige Quellcode funktioniert! Kann meine Modelleisenbahn erfolgreich und ohne Probleme damit steuern!

Edit:
Irgendwie hängt sich das Programm auf, sobald ich ein Print auf dem Bildschirm ausgeben will in der Sub SUB TSNE_NEWDATAUDP?

Die Bibliothek TSNE funktioniert nicht mit der neuesten Freebasic Version!

_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1211
Wohnort: Ruhrpott

BeitragVerfasst am: 15.05.2015, 12:57    Titel: Antworten mit Zitat

Hallo!

volta hat Folgendes geschrieben:
so geht es mir auch lachen

Ja, das zeigst du ja auch schon in deiner Signatur lächeln


@ALWIM:

Wir sollten uns erst mal auf eine gemeinsame Zählweise einigen. Wie kommst du darauf, daß das mainCommand byte7 ist? Das passt weder von vorne noch von hinten.

Wenn (V_Data[1] SHR 1) als mainCommand korrekt ist, müsste die Geschwindigkeit
Code:
CvShort(Chr(V_Data[9],V_Data[10]))
sein. Der Aufbau des Strings ist etwas unscheinbar oben auf Seite 7 der Protokollbeschreibung erläutert. Ich habe das auch erst beim 3. Durchlesen entdeckt.

Gruß
grindstone
_________________
For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4597
Wohnort: ~/

BeitragVerfasst am: 15.05.2015, 22:58    Titel: Antworten mit Zitat

Ein Byte speichert halt nur Werte von 0 bis 255, größere Werte müssen aus mehreren Bytes zusammengesetzt werden (so wie grindstone es macht).

Zitat:
Irgendwie hängt sich das Programm auf, sobald ich ein Print auf dem Bildschirm ausgeben will in der Sub SUB TSNE_NEWDATAUDP?

Ich vermute, dass du einen Aufruf verwendest, der nicht thread-safe ist (z. B. lesender Zugriff auf eine Variable, auf die u. U. in einem anderen Thread bzw. im Hauptprogramm ebenfalls zugegriffen wird, ohne ein Mutex zu verwenden).

Zitat:
Die Bibliothek TSNE funktioniert nicht mit der neuesten Freebasic Version!

Auch nicht mit der neusten neusten Version? (v1.02.1)
Bei uns im Portal ist leider noch die Version v1.01.0 verlinkt; bei der gibt es Probleme beim Einbinden der windows.bi. In v1.02.1 sollte das meines Wissens behoben sein.
_________________
Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ALWIM



Anmeldungsdatum: 08.08.2006
Beiträge: 1037
Wohnort: Niederbayern

BeitragVerfasst am: 15.05.2015, 23:27    Titel: Antworten mit Zitat

Zitat:
Auch nicht mit der neusten neusten Version? (v1.02.1)
Bei uns im Portal ist leider noch die Version v1.01.0 verlinkt; bei der gibt es Probleme beim Einbinden der windows.bi. In v1.02.1 sollte das meines Wissens behoben sein.
Nein auch nicht mit der Version 1.02.1! Diese habe ich versucht! (Runtergeladen über Freebasic.net)

Zitat:
Ich vermute, dass du einen Aufruf verwendest, der nicht thread-safe ist (z. B. lesender Zugriff auf eine Variable, auf die u. U. in einem anderen Thread bzw. im Hauptprogramm ebenfalls zugegriffen wird, ohne ein Mutex zu verwenden).
Interessant! Komisch nur, dass ein anderes Programm, sich ebenfalls nach einer kurzen Zeit aufhängt, bzw. einfriert! Ich glaube sogar, auch die PC-Software vom Herrsteller selber friert ein? Bin mir aber jetzt nicht mehr ganz sicher.

Das heißt konkret: Ich muss Mutexlock und Mutexunlock verwenden? Wie auch immer der Befehl heißt??? Das wäre super, wenn sich das Programm dann nicht mehr aufhängen würde!

Zitat:
Ein Byte speichert halt nur Werte von 0 bis 255, größere Werte müssen aus mehreren Bytes zusammengesetzt werden (so wie grindstone es macht).
Egal wie ich es mache, es kommt immer ein falscher Wert heraus.

Zitat:
ALWIM hat Folgendes geschrieben:
Zitat:
Vielleicht komme ich selber noch drauf? Bin seit geraumer Zeit am rumexperimentieren.

Dann hättest du aber schon längst selber drauf kommen sollen.

Mit rumexperimentieren meinte ich nicht grad das Decodieren, sondern alles andere! Ein vernünftiger Tacho fehlt mir auch noch. Das was ich momentan drin habe, ist nicht so ganz das was ich haben will. Außerdem wollte ich noch eine Maussteuerung mit einbauen. Bis jetzt nur Tastatur-gesteuert! Solche Sachen halt.

Ich danke euch recht herzlich für die bisherige Hilfe!

Gruß
ALWIM
_________________
SHELL SHUTDOWN -s -t 05
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC. Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.

 Impressum :: Datenschutz