Italian ByteArrayToNumber e UnixTime

Pesciolina

Active Member
Licensed User
Longtime User
Buongiorno a tutti,

ho una centralina che mi fornisce l'ora in formato esadecimale in microsecondi dal 01-01-1970 e la funzione che uso mi estrae un valore errato, è possibile
che il valore non ci stia in un campo long ?

HEX
1740730705128.png
00043871F2A1A3B0 convertito in decimali 1187961959982000 che corrisponde al 24-Aug-2007 13:25:59.982

Dove potrebbe risiedere il problema ?

B4X:
Sub ByteArrayToNumber(bytes() As Byte, signed As Boolean, bigEndian As Boolean) As Double
    Dim result As Long = 0
    Dim length As Int = bytes.Length
    
    For i = 0 To length - 1
        Dim index As Int
        If bigEndian Then
            index = length - 1 - i
        Else
            index = i
        End If
        
        result = Bit.Or(result, Bit.And(bytes(index), 0xFF) * Power(256, i))
    Next
    
    If signed Then
        Dim maxVal As Long = Power(2, length * 8 - 1)
        If result >= maxVal Then
            result = result - 2 * maxVal
        End If
    End If
    
    Return result
End Sub

Grazie
 

Sagenut

Expert
Licensed User
Longtime User
Non ho fatto prove però la tua SUB indica che deve ritornare un DOUBLE, ma tu nel RETURN indichi appunto un LONG.
Non sò se questo possa essere l'errore.
 

Sagenut

Expert
Licensed User
Longtime User
Ho fatto un test veloce, ma con quel Long ottengo
01/06/39615 18:19:42
Il LONG per la data e ora da te indicati dovrebbe essere
1187954759000
Paragonandolo al tuo sembra che il tuo abbia 3 zeri finali di troppo.
 

udg

Expert
Licensed User
Longtime User
Due semplici domande:
1. Millisecondi o microsecondi?
2. Avresti una stringa Hex e la sua decodifica attesa corretta? Indipendentemente dall'output del codice attuale
 

Sagenut

Expert
Licensed User
Longtime User
Avevo sorvolato sui Microsecondi.
Infatti dividendo il Long per 1000 corrisponde.
 

Sagenut

Expert
Licensed User
Longtime User
Se puoi ottenere la stringa esadecimale la conversione in Long la puoi fare anche così
B4X:
Dim l As Long = Bit.ParseLong("00043871F2A1A3B0", 16) / 1000
 

Daestrum

Expert
Licensed User
Longtime User
value was nanos since epoch
B4X:
    Dim hex(8) As Byte = Array As Byte(0xB0,0xA3,0xA1,0xF2,0x71,0x38,0x04,0x00) 'time in nanoseconds since epoch
    Dim bb,bo As JavaObject
 Bb. Initializestatic("java.nio.ByteBuffer")
Bo. InitializeStatic("java.nio.ByteOrder")
' change into microseconds /1000
 Dim l As Long = bb. RunMethodJO("wrap",Array(hex)). RunMethodJO("order",Array(bo. GetField("LITTLE_ENDIAN"))). RunMethod("getLong",Null) / 1000
    Log(DateTime.Date(l))
DateTime.TimeFormat = "HH:mm:ss. SSS"
    Log(DateTime.Time(l))
 
Last edited:

emexes

Expert
Licensed User
Longtime User
Probabilmente è più semplice utilizzare la libreria B4X integrata piuttosto che JavaObject:

B4X:
    Dim hex(8) As Byte = Array As Byte(0xB0,0xA3,0xA1,0xF2,0x71,0x38,0x04,0x00)
    
    Dim bc As ByteConverter
    bc.LittleEndian = True
    Dim l As Long = bc.LongsFromBytes(hex)(0)
    
    Log(l)
    
    l = l / 1000    'cambiare i microsecondi in millisecondi
    
    Log(DateTime.Date(l))
    Log(DateTime.Time(l))
 

emexes

Expert
Licensed User
Longtime User
microsecondi dal 01-01-1970
value was nanos since epoch

Questo dato mi confonde. Sembra più probabile che sia in microsecondi, non in nanosecondi. Ma perché 2007? L'orologio del controllore è sbagliato? Sbagliato di 18 anni? Il mio secondo pensiero è stato il rollover del GPS ogni 19,6 anni, forse sta dando l'ora del GPS. Ma il campione di byte grezzi fornito rappresenterebbe comunque un errore di oltre un anno.

Cosa dice il manuale del controllore o la descrizione del protocollo sul formato del valore di data e ora a 8 byte?
 

Pesciolina

Active Member
Licensed User
Longtime User
confermo che è in microsecondi, la data del 2007 è corretta perchè presa dal manuale.
se metto i dati in un converter ottengo il risultato corretto
1740742983918.png

1740743028913.png


Parte del manuale
1740743268589.png
 

Attachments

  • 1740743156084.png
    1740743156084.png
    9.4 KB · Views: 123

Pesciolina

Active Member
Licensed User
Longtime User
grazie, ho usato questa funzione

B4X:
Dim bc As ByteConverter
    bc.LittleEndian = True
    Dim l As Long = bc.LongsFromBytes(hex)(0)

l'avevo già provata ma non ho messo (0) , mi puoi spiegare a cosa sta ad indicare ?
 

emexes

Expert
Licensed User
Longtime User
Risposta breve: Magia!

Risposta vera e propria: LongsFromBytes non restituisce un singolo valore Long, ma un Array di valori Long e per ottenere un valore Long specifico in tale Array, è necessario dire a B4X quale di essi si desidera. Come se si accedesse a un elemento specifico di un normale array. Anche se sappiamo che la Array ha un solo elemento, dobbiamo comunque dire a B4X che vogliamo il valore Long del singolo elemento e che non ci stiamo riferendo all'intera Array.

B4X:
Dim bc As ByteConverter
bc.LittleEndian = True

'all together
Log(bc.LongsFromBytes(Array As Byte(0xB0,0xA3,0xA1,0xF2,0x71,0x38,0x04,0x00))(0))

'step by step
Dim hex(8) As Byte = Array As Byte(0xB0,0xA3,0xA1,0xF2,0x71,0x38,0x04,0x00)
Dim larray() As Long = bc.LongsFromBytes(hex)
Dim l As Long = larray(0)
Log(l)

Un altro modo di pensare è che (0) fornisce il primo elemento di una Array, proprio come .Get(0) fornisce il primo elemento di un List.

B4X:
Dim bc As ByteConverter
bc.LittleEndian = True

Dim hex(8) As Byte = Array As Byte(0xB0,0xA3,0xA1,0xF2,0x71,0x38,0x04,0x00)

Dim llist As List
llist.Initialize
llist = bc.LongsFromBytes(hex)
Log(hex.As(List))    'altra magia
Log(llist)
Log(llist.Get(0))
Log output:
Waiting for debugger to connect...
Program started.
(ArrayList) [-80, -93, -95, -14, 113, 56, 4, 0]
(ArrayList) [1187961959982000]
1187961959982000
 
Last edited:
Top