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 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
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.
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.
Due semplici domande:
1. Millisecondi o microsecondi?
2. Avresti una stringa Hex e la sua decodifica attesa corretta? Indipendentemente dall'output del codice attuale
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))
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))
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?
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