All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.time4j.clock.SntpMessage Maven / Gradle / Ivy

/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2015 Meno Hochschild, 
 * -----------------------------------------------------------------------
 * This file (SntpMessage.java) is part of project Time4J.
 *
 * Time4J is free software: You can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Time4J is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Time4J. If not, see .
 * -----------------------------------------------------------------------
 */

package net.time4j.clock;

import net.time4j.Moment;
import net.time4j.SystemClock;
import net.time4j.scale.TimeScale;

import java.io.IOException;


/**
 * 

Message for the SNTP-protocol (RFC 4330).

* *

NTP-timestamps will be calculated at best in microsecond precision.

* * @author Meno Hochschild * @since 2.1 */ /*[deutsch] *

Nachricht für das SNTP-Protokoll (RFC 4330).

* *

NTP-Zeitstempel werden maximal in Mikrosekundengenauigkeit berechnet.

* * @author Meno Hochschild * @since 2.1 */ public final class SntpMessage { //~ Statische Felder/Initialisierungen -------------------------------- // Mikrosekunden seit [1900-01-01T00:00:00Z] (relativ zu 1.1.1970) private static final long OFFSET_1900 = 2208988800000000L; // Mikrosekunden seit [2036-02-07T06:28:16Z] (ohne Schaltsekunden!) private static final long OFFSET_2036 = -2085978496000000L; private static final int MIO = 1000000; private static final double MIO_AS_DOUBLE = 1000000.0; private static final byte[] NULL_REF_ID = new byte[] {0, 0, 0, 0}; private static final double BIT08 = 256.0; private static final double BIT16 = 65536.0; //~ Instanzvariablen -------------------------------------------------- private final byte leapIndicator; private final byte version; private final byte mode; private final short stratum; private final short pollInterval; private final byte precision; private final double rootDelay; private final double rootDispersion; private final byte[] refID; private final double referenceTimestamp; private final double originateTimestamp; private final double receiveTimestamp; private final double transmitTimestamp; //~ Konstruktoren ----------------------------------------------------- /** *

Konstruiert eine Anfrage des Clients.

* * @param version4 NTP4-Version statt NTP3-Version verwenden? */ SntpMessage(boolean version4) { super(); this.leapIndicator = 0; this.version = (byte) (version4 ? 4 : 3); this.mode = 3; this.stratum = 0; this.pollInterval = 0; this.precision = 0; this.rootDelay = 0; this.rootDispersion = 0; this.refID = NULL_REF_ID; this.referenceTimestamp = 0; this.originateTimestamp = 0; this.receiveTimestamp = 0; this.transmitTimestamp = getLocalTimestamp(); } /** *

Konstruiert eine Antwort des Servers.

* * @param data Antwort-Daten des Servers * @param expectedOriginateTS erwarteter Zeitstempel im NTP-Format * @param expectedVersion erwartete NTP-Version des Servers * @throws IOException bei Plausibilitätsverletzungen */ SntpMessage( byte[] data, double expectedOriginateTS, byte expectedVersion ) throws IOException { super(); this.leapIndicator = (byte) ((data[0] >> 6) & 0x3); this.version = (byte) ((data[0] >> 3) & 0x7); this.mode = (byte) (data[0] & 0x7); this.stratum = toUnsigned(data[1]); this.pollInterval = toUnsigned(data[2]); this.precision = data[3]; this.rootDelay = ( (data[4] * BIT08) + toUnsigned(data[5]) + (toUnsigned(data[6]) / BIT08) + (toUnsigned(data[7]) / BIT16) ); int dispersion = 0; for (int i = 0; i < 4; i++) { int unsigned = (data[i + 8] & 0xFF); dispersion |= (unsigned << (24 - i * 8)); } this.rootDispersion = (dispersion / BIT16); byte[] r = new byte[4]; r[0] = data[12]; r[1] = data[13]; r[2] = data[14]; r[3] = data[15]; this.refID = r; this.referenceTimestamp = decode(data, 16); this.originateTimestamp = decode(data, 24); this.receiveTimestamp = decode(data, 32); this.transmitTimestamp = decode(data, 40); // Plausibilitätsprüfungen if (this.transmitTimestamp == 0) { throw new IOException( "Server hasn't sent any transmit timestamp."); } else if ( Math.abs(expectedOriginateTS - this.originateTimestamp) >= 0.001 && (this.mode == 4) ) { throw new IOException( "Originate timestamp does not match sent timestamp: " + this.originateTimestamp + " (expected = " + expectedOriginateTS + ")" ); } else if ( (this.mode != 4) && (this.mode != 5) ) { throw new IOException( "Unexpected server mode: " + this.mode); } else if ( (this.leapIndicator < 0) || (this.leapIndicator > 3) ) { throw new IOException( "Unexpected leap indicator: " + this.leapIndicator); } else if ( (this.version < 1) || (this.version > 4) || ((this.mode == 4) && (this.version != expectedVersion)) ) { throw new IOException( "Unexpected ntp version: " + this.version); } else if ( (this.stratum < 0) || (this.stratum > 15) ) { throw new IOException( "Unexpected stratum: " + this.stratum); } } //~ Methoden ---------------------------------------------------------- /** *

Yields the LI-bits as appointment of a coming leap second.

* *
  • 0 - no warning.
  • *
  • 1 - last minute of day has 61 seconds.
  • *
  • 2 - last minute of day has 59 seconds.
  • *
  • 3 - alert state (missing clock synchronization).
* * @return byte * @since 2.1 */ /*[deutsch] *

Ermittelt die LI-Bits als Ankündigung einer bevorstehenden * Schaltsekunde.

* *
  • 0 - Keine Warnung.
  • *
  • 1 - Letzte Minute des Tages hat 61 Sekunden.
  • *
  • 2 - Letzte Minute des Tages hat 59 Sekunden.
  • *
  • 3 - Alarmzustand (fehlende Uhrzeitsynchronisation).
* * @return byte * @since 2.1 */ public byte getLeapIndicator() { return this.leapIndicator; } /** *

Displays the NTP-version.

* * @return 3 (if only IPv4 is supported) else 4 * @since 2.1 */ /*[deutsch] *

Zeigt die NTP-Version an.

* * @return 3 (wenn nur IPv4 unterstützt wird), sonst 4 * @since 2.1 */ public byte getVersion() { return this.version; } /** *

Displays the mode.

* * @return 3 (client-mode) or 4 (server-mode) oder 5 (broadcast) * @since 2.1 */ /*[deutsch] *

Zeigt den Modus an.

* * @return 3 (Client-Modus) oder 4 (Server-Modus) oder 5 (Broadcast) * @since 2.1 */ public byte getMode() { return this.mode; } /** *

Displays the stratum-value indicating the distance of * the original time source.

* *

Usually it is the count of involved clock servers respective * layers. The value {@code 0} indicates a kiss-o'-death-message * by which the server signals to the client that repeated requests should * be immediately stopped.

* * @return 0 (unspecified) oder 1 (direkt) oder 2-15 (sekundär) * @since 2.1 */ /*[deutsch] *

Zeigt den Stratum-Wert als Maß für die * Entfernung der Zeitquelle an.

* *

In der Regel handelt es sich um die Anzahl der beteiligten * Uhrzeit-Server bzw. Schichten. Der Wert {@code 0} zeigt eine * kiss-o'-death-Nachricht an, womit der Server dem * Client signalisiert, das wiederholte Senden von Anfragen sofort * einzustellen.

* * @return 0 (unspezifiziert) oder 1 (direkt) oder 2-15 (sekundär) * @since 2.1 */ public short getStratum() { return this.stratum; } /** *

Yields the maximum interval between two successful server messages * in seconds as exponent for base 2.

* *

This property is only relevant if the server is sending messages * in the broadcast-mode. In all other cases the server should * send the value{@code 0}.

* * @return broadcast-mode: value in range {@code 4 <= pollInterval <= 17} * @since 2.1 */ /*[deutsch] *

Liefert das maximale Intervall zwischen zwei erfolgreichen * Server-Nachrichten in Sekunden als Exponent zur Basis 2.

* *

Diese Eigenschaft ist nur von Belang, wenn der Server Nachrichten * im broadcast-Modus sendet. Sonst sollte der Server den Wert * {@code 0} senden.

* * @return broadcast-Modus: Wert im Bereich {@code 4 <= pollInterval <= 17} * @since 2.1 */ public int getPollInterval() { return this.pollInterval; } /** *

Yields the precision of the server clock in seconds as exponent * for the base 2.

* * @return int in the usual range {@code -6 <= precision <= -23} * @since 2.1 */ /*[deutsch] *

Liefert die Genauigkeit der Systemuhr auf dem Server in Sekunden * als Exponent zur Basis 2.

* * @return int im üblichen Bereich {@code -6 <= precision <= -23} * @since 2.1 */ public int getPrecision() { return this.precision; } /** *

Yields the total delay in seconds relative to the primary source.

* *

This information only concerns the NTP-server, not the actual * network traffic with the client.

* * @return round-trip-delay in seconds * @since 2.1 */ /*[deutsch] *

Liefert die gesamte Verzögerung in Sekunden relativ zur * primären Referenzquelle.

* *

Es handelt sich um eine Information, die nur den NTP-Server betrifft, * nicht aber den aktuellen Netzverkehr mit dem Client.

* * @return round-trip-delay in Sekunden * @since 2.1 */ public double getRootDelay() { return this.rootDelay; } /** *

Yields the maximum error in seconds relative to the primary * source.

* *

This information only concerns the NTP-server, not the actual * network traffic with the client.

* * @return maximum error in seconds * @since 2.1 */ /*[deutsch] *

Liefert den maximalen Fehler in Sekunden relativ zur * primären Referenzquelle.

* *

Es handelt sich um eine Information, die nur den NTP-Server betrifft, * nicht aber den aktuellen Netzverkehr mit dem Client.

* * @return maximaler Fehler in Sekunden * @since 2.1 */ public double getRootDispersion() { return this.rootDispersion; } /** *

Identifies a reference source.

* *

If the connected server is a primary NTP-server (stratum = 1) then * the return value will usually be a string from following list:

* *
    *
  • LOCL - uncalibrated local clock
  • *
  • CESM - calibrated Cesium clock
  • *
  • RBDM - calibrated Rubidium clock
  • *
  • PPS - calibrated quartz clock or other pulse-per-second source
  • *
  • IRIG - Inter-Range Instrumentation Group
  • *
  • ACTS - NIST telephone modem service
  • *
  • USNO - USNO telephone modem service
  • *
  • PTB - PTB (Germany) telephone modem service
  • *
  • TDF - Allouis (France) Radio 164 kHz
  • *
  • DCF - Mainflingen (Germany) Radio 77.5 kHz
  • *
  • MSF - Rugby (UK) Radio 60 kHz
  • *
  • WWV - Ft. Collins (US) Radio 2.5, 5, 10, 15, 20 MHz
  • *
  • WWVB - Boulder (US) Radio 60 kHz
  • *
  • WWVH - Kauai Hawaii (US) Radio 2.5, 5, 10, 15 MHz
  • *
  • CHU - Ottawa (Canada) Radio 3330, 7335, 14670 kHz
  • *
  • LORC - LORAN-C radionavigation getChronology
  • *
  • OMEG - OMEGA radionavigation getChronology
  • *
  • GPS - Global positioning getChronology
  • *
* *

A secondary IPv4-server will return a 32-bit-IP-address else the * return value represents the first 32 bits of a MD5-hash value of a * IPv6- or NSAP-address of the synchronization source.

* *

In case of a ({@code stratum == 0}) - reply of the server the * return value describes a kiss-or-death-message. The client should * then not repeat the request (or at least not within the next minute). * A non-exhausting selection:

* *
    *
  • ACST - Association belongs to an anycast server
  • *
  • AUTH - Server authentication failed
  • *
  • AUTO - Autokey sequence failed
  • *
  • BCST - Association belongs to a broadcast server
  • *
  • CRYP - Cryptographic authentication or identification failed
  • *
  • DENY - Access denied by remote server
  • *
  • DROP - Lost peer in symmetric mode
  • *
  • RSTR - Access denied due to local policy
  • *
  • INIT - Association has not yet synchronized for the first time
  • *
  • MCST - Association belongs to a manycast server
  • *
  • NKEY - No key found. Either the key was never installed or is not * trusted
  • *
  • RATE - Rate exceeded. The server has temporarily denied access * because the client exceeded the rate threshold
  • *
  • RMOT - Somebody is tinkering with the association from a remote * host running ntpdc. Not to worry unless some rascal has stolen your * keys
  • *
  • STEP - A step change in getChronology time has occurred, but the * association has not yet resynchronized
  • *
* * @return String * @since 2.1 */ /*[deutsch] *

Identifiziert eine Referenzquelle.

* *

Wenn es sich um einen primären NTP-Server handelt (stratum = 1), * dann wird der Rückgabewert in der Regel ein String aus der folgenden * Liste sein:

* *
    *
  • LOCL - uncalibrated local clock
  • *
  • CESM - calibrated Cesium clock
  • *
  • RBDM - calibrated Rubidium clock
  • *
  • PPS - calibrated quartz clock or other pulse-per-second source
  • *
  • IRIG - Inter-Range Instrumentation Group
  • *
  • ACTS - NIST telephone modem service
  • *
  • USNO - USNO telephone modem service
  • *
  • PTB - PTB (Germany) telephone modem service
  • *
  • TDF - Allouis (France) Radio 164 kHz
  • *
  • DCF - Mainflingen (Germany) Radio 77.5 kHz
  • *
  • MSF - Rugby (UK) Radio 60 kHz
  • *
  • WWV - Ft. Collins (US) Radio 2.5, 5, 10, 15, 20 MHz
  • *
  • WWVB - Boulder (US) Radio 60 kHz
  • *
  • WWVH - Kauai Hawaii (US) Radio 2.5, 5, 10, 15 MHz
  • *
  • CHU - Ottawa (Canada) Radio 3330, 7335, 14670 kHz
  • *
  • LORC - LORAN-C radionavigation getChronology
  • *
  • OMEG - OMEGA radionavigation getChronology
  • *
  • GPS - Global positioning getChronology
  • *
* *

Ein sekundärer IPv4-Server wird hier eine 32-Bit-IP-Adresse * liefern, sonst handelt es sich um die ersten 32 Bits eines MD5-Haschwerts * einer IPv6- oder NSAP-Adresse der Synchronisationsquelle.

* *

Im Fall einer ({@code stratum == 0}) - Antwort des Serves beschreibt * der Rückgabewert eine kiss-or-death-Nachricht. Der Client sollte * dann nicht die Anfrage wiederholen (oder wenigstens nicht innerhalb der * nächsten Minute). Eine nicht erschöpfende Auswahl:

* *
    *
  • ACST - Association belongs to an anycast server
  • *
  • AUTH - Server authentication failed
  • *
  • AUTO - Autokey sequence failed
  • *
  • BCST - Association belongs to a broadcast server
  • *
  • CRYP - Cryptographic authentication or identification failed
  • *
  • DENY - Access denied by remote server
  • *
  • DROP - Lost peer in symmetric mode
  • *
  • RSTR - Access denied due to local policy
  • *
  • INIT - Association has not yet synchronized for the first time
  • *
  • MCST - Association belongs to a manycast server
  • *
  • NKEY - No key found. Either the key was never installed or is not * trusted
  • *
  • RATE - Rate exceeded. The server has temporarily denied access * because the client exceeded the rate threshold
  • *
  • RMOT - Somebody is tinkering with the association from a remote * host running ntpdc. Not to worry unless some rascal has stolen your * keys
  • *
  • STEP - A step change in getChronology time has occurred, but the * association has not yet resynchronized
  • *
* * @return String * @since 2.1 */ public String getReferenceIdentifier() { return this.getRefIDAsString(); } /** *

NTP-timestamp when the time of the server was set or corrected * last time.

* *

The method yields {@code 0} if no request has been sent yet.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ /*[deutsch] *

NTP-Timestamp wann die Zeit auf dem Server zuletzt gesetzt oder * korrigiert wurde.

* *

Die Methode liefert {@code 0}, wenn noch nichts gesendet worden * ist.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ public double getReferenceTimestamp() { return this.referenceTimestamp; } /** *

NTP-timestamp when the client request was sent.

* *

The method yields {@code 0} if no request has been sent yet.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ /*[deutsch] *

NTP-Timestamp wann die Zeitabfrage vom Client gesendet wurde.

* *

Die Methode liefert {@code 0}, wenn noch nichts gesendet worden * ist.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ public double getOriginateTimestamp() { return this.originateTimestamp; } /** *

NTP-timestamp when the server received the client request.

* *

The method yields {@code 0} if no request has been sent yet.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ /*[deutsch] *

NTP-Timestamp wann die Zeitabfrage vom Server empfangen wurde.

* *

Die Methode liefert {@code 0}, wenn noch nichts gesendet worden * ist.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ public double getReceiveTimestamp() { return this.receiveTimestamp; } /** *

NTP-timestamp when the client or server request was sent.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ /*[deutsch] *

NTP-Timestamp wann die Abfrage bzw. Antwort vom Client bzw. vom * Server gesendet wurde.

* * @return NTP-time in seconds since 1900-01-01 * @since 2.1 */ public double getTransmitTimestamp() { return this.transmitTimestamp; } /** *

Returns a human-readable form of the internal state.

* * @return String */ /*[deutsch] *

Gibt den internen Zustand in menschenlesbarer Form aus.

* * @return String */ @Override public String toString() { StringBuilder sb = new StringBuilder(300); sb.append(this.getClass().getName()); sb.append("[version="); sb.append(this.version); sb.append(", mode="); switch (this.mode) { case 3: sb.append("client"); break; case 4: sb.append("server"); break; case 5: sb.append("broadcast"); break; default: sb.append(this.mode); } sb.append(", leap-indicator="); sb.append(this.leapIndicator); sb.append(", stratum="); sb.append(this.stratum); sb.append(", poll-interval="); sb.append(this.pollInterval); sb.append(", precision="); sb.append(this.precision); sb.append(", root-delay="); sb.append(this.rootDelay); sb.append(", root-dispersion="); sb.append(this.rootDispersion); sb.append(", reference-identifier="); sb.append(this.getRefIDAsString()); sb.append(", reference-timestamp="); sb.append(toString(this.referenceTimestamp)); sb.append(", originate-timestamp="); sb.append(toString(this.originateTimestamp)); sb.append(", receive-timestamp="); sb.append(toString(this.receiveTimestamp)); sb.append(", transmit-timestamp="); sb.append(toString(this.transmitTimestamp)); sb.append(']'); return sb.toString(); } /** *

Converts given NTP-timestamp to a microsecond value relative to * the UNIX- epoch.

* * @param ntpTimestamp NTP-timestamp (seconds since 1900-01-01) * @return long-Wert relative to 1970-01-01 in microseconds without * leap seconds * @since 2.1 */ /*[deutsch] *

Wandelt den NTP-Timestamp in einen Mikrosekundenwert relativ * zur UNIX-Epoche um.

* * @param ntpTimestamp NTP-Timestamp (Sekunden seit 1.1.1900) * @return long-Wert relativ zum 1. Januar 1970 (Mikrosekundenwert * ohne Zählung von UTC-Schaltsekunden) * @since 2.1 */ public static long convert(double ntpTimestamp) { return (long) ((ntpTimestamp * MIO) - OFFSET_1900); } /** *

Liefert die rohen Bytes dieser {@code SntpMessage} zum Versenden * an den NTP-Server.

* * @return byte-Array */ byte[] getBytes() { byte[] ret = new byte[48]; ret[0] = (byte) ( (this.leapIndicator << 6) | (this.version << 3) | this.mode ); // wird nie ausgewertet, da nur auf die Client-Message angewandt if (this.mode != 3) { ret[1] = (byte) this.stratum; ret[2] = (byte) this.pollInterval; ret[3] = this.precision; int rdelay = (int) (this.rootDelay * BIT16); ret[4] = (byte) ((rdelay >> 24) & 0xFF); ret[5] = (byte) ((rdelay >> 16) & 0xFF); ret[6] = (byte) ((rdelay >> 8) & 0xFF); ret[7] = (byte) (rdelay & 0xFF); long rdisp = (long) (this.rootDispersion * BIT16); ret[8] = (byte) ((rdisp >> 24) & 0xFF); ret[9] = (byte) ((rdisp >> 16) & 0xFF); ret[10] = (byte) ((rdisp >> 8) & 0xFF); ret[11] = (byte) (rdisp & 0xFF); for (int i = 0; i < 4; i++) { ret[12 + i] = this.refID[i]; } encode(ret, 16, this.referenceTimestamp); encode(ret, 24, this.originateTimestamp); encode(ret, 32, this.receiveTimestamp); } encode(ret, 40, this.transmitTimestamp); return ret; } /** *

Liefert den aktuellen lokalen NTP-Timestamp.

* * @return aktuelle Zeit im NTP-Format (Sekunden seit 1.1.1900) */ static double getLocalTimestamp() { long ut1 = SystemClock.MONOTONIC.currentTimeInMicros(); return ((ut1 + OFFSET_1900) / MIO_AS_DOUBLE); } private String getRefIDAsString() { StringBuilder sb = new StringBuilder(); if ( (this.stratum == 0) || (this.stratum == 1) ) { for (int i = 0; i < 4; i++) { char c = (char) this.refID[i]; if (c == 0) { break; } else { sb.append(c); } } } else if (this.version == 3) { sb.append(toUnsigned(this.refID[0])); sb.append('.'); sb.append(toUnsigned(this.refID[1])); sb.append('.'); sb.append(toUnsigned(this.refID[2])); sb.append('.'); sb.append(toUnsigned(this.refID[3])); } else if (this.version == 4) { int ref = 0; for (int i = 0; i < 4; i++) { int unsigned = (this.refID[i] & 0xFF); ref |= (unsigned << (24 - i * 8)); } return Integer.toHexString(ref); } else { sb.append('?'); } return sb.toString(); } private static String toString(double ntpTimestamp) { long micros = convert(ntpTimestamp); Moment m = Moment.of( micros / MIO, (int) ((micros % MIO) * 1000), TimeScale.POSIX); return m.toString(); } // NTP-Timestamp aus byte-Array dekodieren private static double decode( byte[] data, int pointer ) { long ntp = 0L; for (int i = 0; i < 8; i++) { long unsigned = (data[i + pointer] & 0xFF); ntp |= (unsigned << (56 - i * 8)); } // Festkomma vor Bit 32, deshalb Bits nach rechts schieben long integer = ((ntp >>> 32) & 0xFFFFFFFFL); long fraction = (((ntp & 0xFFFFFFFFL) * MIO) >>> 32); long off = (((integer & 0x80000000L) == 0) ? OFFSET_2036 : OFFSET_1900); long ut1 = (integer * MIO) + fraction - off; return ((ut1 + OFFSET_1900) / MIO_AS_DOUBLE); } // NTP-Timestamp als byte-Array kodieren private static void encode( byte[] data, int pointer, double timestamp ) { // UT1-Mikrosekunden konstruieren long ut1 = convert(timestamp); boolean before2036 = (ut1 + OFFSET_2036 < 0); long micros; if (before2036) { micros = ut1 + OFFSET_1900; } else { micros = ut1 + OFFSET_2036; // siehe RFC 4330, Abschnitt 3 } // Festkomma vor Bit 32, deshalb Bits nach links schieben long integer = micros / MIO; long fraction = ((micros % MIO) << 32) / MIO; if (before2036) { integer |= 0x80000000L; // siehe RFC 4330, Abschnitt 3 } long ntp = ((integer << 32) | fraction); // Binäre Darstellung erzeugen for (int i = 7; i >= 0; i--) { data[i + pointer] = (byte) (ntp & 0xFF); ntp >>>= 8; } // niedrigstes Byte nur als Zufallszahl (siehe RFC 4330, Abschnitt 3) data[7 + pointer] = (byte) (Math.random() * BIT08); } // Byte-Konvertierung private static short toUnsigned(byte b) { short unsignedByte = b; if ((b & 0x80) == 0x80) { unsignedByte = (short) (128 + (b & 0x7f)); } return unsignedByte; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy