QDataStream

  1. 2 months ago

    Does anyone have any experience and/or tips on using a QDataStream with Xojo?

    https://doc.qt.io/archives/qt-4.8/qdatastream.html

    This is in connection with WSJT-X.

    The object is to interface with the network message stream.

    https://sourceforge.net/p/wsjt/wsjtx/ci/master/tree/NetworkMessage.hpp

    https://physics.princeton.edu/pulsar/k1jt/wsjtx.html

    https://physics.princeton.edu/pulsar/k1jt/

    Any help or feedback would be welcome.

    Thanks

    Bingo!! Thanks Norman.

  2. Norman P

    Mar 13 Pre-Release Testers, Xojo Pro Alberta Canada

    Just to listen and read messages ?
    Or something more ?

  3. Yes, just to listen and read messages.
    At least for now.
    I would be so grateful if you could help!

  4. Maurizio R

    Mar 13 Pre-Release Testers, Xojo Pro

    It's used to serialize qt entities in binary format.
    What exactly are you looking for?

  5. I have written a routine to capture UDP messages with data in this format. I am looking for a way to decode and use the data.

  6. Maurizio R

    Mar 13 Pre-Release Testers, Xojo Pro

    Qt documentation explain how entities are represented in binary format.
    Let me collect the related links.
    I'll post here when ready.
    Nothing difficult to implement in Xojo.

  7. THANK YOU!!!!

    No rush... it's bed time here in Los Angeles and I'm done for today.

  8. Maurizio R

    Mar 14 Pre-Release Testers, Xojo Pro
    Edited 2 months ago

    Hello Ed,
    the informations stated in the comment section (the green colored part) of the source at https://sourceforge.net/p/wsjt/wsjtx/ci/master/tree/NetworkMessage.hpp are the only one required.
    In Qt all types starts with the "q" letter so: qint32 is an int32 in Xojo and so on.
    A QByteArray is very similar to a MemoryBlock.
    No classes are serialized in a network message so things are simpler.
    The important parts are:

    • all numeric values are represented in big endian format not little endian as used natively by x86/x64 Intel processors
    • all strings are in utf8 format without an end of string marker but prepended with an int32 value containing the string length
    • special string length values are 0 for an empty string and &hffffffff for a null string
    • all values are in binary format so an int32 is represented as 4 bytes (remember in big endian format)

    The MemoryBlock LittleEndian =false property can be used to set/get numeric values in big endian.
    Values can be set/get into/from frames contained in a MemoryBlock using offsets: this can be tedious.

    A QDataStream is a class used to manipulate files/QByteArray contents in a simpler way instead of referring to the contained data using offsets.
    Something very similar can be implemented in Xojo subclassing a MemoryBlock and adding methods to insert/pull data from the MemoryBlock contents and mantaining, as a private property, an offset index that increment accordingly to what is inserted/extracted from the MemoryBlock.

    This is the fastest/shortest reply I can give you here just to start.
    Reports here if you need more help.
    Regards.

  9. Norman P

    Mar 14 Pre-Release Testers, Xojo Pro Alberta Canada

    Oh yeah if this is all thats required they should be straight forward to decode

  10. Maurizio, thank you. Also Norman!

    Let me study this and if I need to I will ask you for further guidance.

    Many thanks!

  11. With your generous help I am making sense of all of this. Thank You!

    I should probably be embarrassed to ask this, but here goes:

    What is the most straightforward method for converting an array of bytes into a decimal value?

    For instance, I have the following array of bytes representing the Dial Frequency as a quint64: 00 00 00 00 00 36 85 08
    This becomes &h0000000000368508 which converts to 3573000 decimal.

    I thought using
    ============
    function decodeFreq (QBlock As MemoryBlock, firstByte As Integer) As String

    Dim m As New MemoryBlock(8)
    Dim i As Integer
    Dim aVal As Int64

    for i = 0 to 7
    m.byte( i ) = QBlock.byte( firstByte + i )
    Next

    aVal = m.Int64Value( 0 )

    Return str( aVal )
    =============

    might give the value but instead I got 613956297833840640!

  12. Norman P

    Mar 21 Pre-Release Testers, Xojo Pro Alberta Canada

    Make sure your memoryblock has the right endianness

    'For instance, I have the following array of bytes representing the Dial Frequency as a quint64: 00 00 00 00 00 36 85 08
    'This becomes &h0000000000368508 which converts to 3573000 decimal.
    
    dim mb as new memoryblock(8)
    mb.UInt8Value(0) =  &h00
    mb.UInt8Value(1) =  &h00
    mb.UInt8Value(2) =  &h00
    mb.UInt8Value(3) =  &h00
    mb.UInt8Value(4) =  &h00
    mb.UInt8Value(5) =  &h36
    mb.UInt8Value(6) =  &h85
    mb.UInt8Value(7) =  &h08
    
    mb.LittleEndian = true
    dim leI64 as Uint64 = mb.UInt64Value(0)
    
    mb.LittleEndian = false
    dim beI64 as Uint64 = mb.UInt64Value(0)
    
    break
  13. Seems like a hard way to do it, but this works for me.

    ============
    function decodeQ64 (QBlock As MemoryBlock, firstByte As Integer) As String

    Const blockSize = 8
    Const stringSize = 16

    Dim m As New MemoryBlock(blockSize)
    Dim i, hVal As Integer
    Dim aVal As Int64
    Dim pFactor( stringSize ) As Int64
    Dim byteValue As integer
    Dim s, h1 As String

    for i = stringSize DownTo 1
    pFactor( i ) = Pow( stringSize, stringSize - i )
    Next

    for i = 0 to blockSize - 1
    m.Byte(i) = QBlock.Byte( firstByte + i )
    Next

    for i = 0 to blockSize - 1
    byteValue = m.Byte( i )
    h1 = hex( byteValue )
    if len( h1 ) = 1 Then h1 = "0" + h1
    s = s + h1
    Next

    for i = 1 to stringSize

    hVal = asc( mid( s, i, 1 ) )

    Select case hVal
    Case 48 to 57
    hVal = hVal - 48
    Case 65 to 70
    hVal = ( hVal - 65) + 10
    End

    aVal = aVal + (hVal * pFactor( i ) )

    Next
    Return str( aVal )
    =============

    Is there an easier way to do this???

  14. Norman P

    Mar 21 Pre-Release Testers, Xojo Pro Alberta Canada
    Edited 2 months ago

    @Ed S Seems like a hard way to do it, but this works for me.

    The first bunch of lines is just me setting up the memory block with the data you suggested to show how using LITTLEENDIAN and Uint64Value would do this for you

    Literally you need 2 lines

    1. littlendian = false
    2. read the Uint64 from whatever offset
    mb.LittleEndian = false
    dim beI64 as Uint64 = mb.UInt64Value(0)

    Is the code getting a string that is the hex representation ? ie "00" , "00" or BYTES with those values ?

    IE/ would my little sample need to be

    dim mb as new memoryblock(8)
    mb.UInt8Value(0) = val(" &h" + "00")
    mb.UInt8Value(1) = val(" &h" + "00")
    mb.UInt8Value(2) = val(" &h" + "00")
    mb.UInt8Value(3) = val(" &h" + "00")
    mb.UInt8Value(4) = val(" &h" + "00")
    mb.UInt8Value(5) = val(" &h" + "36")
    mb.UInt8Value(6) = val(" &h" + "85")
    mb.UInt8Value(7) = val(" &h" + "08")
    
    mb.LittleEndian = false
    dim beI64 as Uint64 = mb.UInt64Value(0)
    
    break
    
  15. Edited 2 months ago

    I'm setting littlendian here in UDPSocket.DataAvailable

    Dim d As DataGram
    Dim mb1, mb As MemoryBlock

    d = UDPSocket1.Read
    mb = d.Data
    if mb <> NIL Then
    mb1 = mb
    mb1.LittleEndian = False
    end

    HexDump( mb1 )

    Then in HexDump I call my function

    if wsjtxData.Size = 0 Then Return
    .
    {Other code to dump the hex of the dataGram)
    .
    if wsjtxData.Byte( 11 ) = 1 Then
    s = decodeQ64( wsjtxData, 22 )
    outPut.AppendText s + chr( 13 )
    end

  16. Norman P

    Mar 21 Pre-Release Testers, Xojo Pro Alberta Canada

    ah you want to see the bytes from the block in hex ....... I though you just wanted the decimal value from the memry block based on your first post and what I replied with
    and that returns the decimal converted value with just the lines I posted
    if you wanted to add that as a string you could just use STR or FORMAT on the value the two lines I posted return

  17. Hi Norman

    I need to stop trying to do it the other way and listen to your good advice.

    Really I don't care about the individual bytes. I DO want to return the decimal value.

    Let me change gears and see if I can make it work the way you have shown.

    My wife says I'm like a dog with a bone. Once I start chewing it's hard to get me to pay attention.

    Thanks for your help!

  18. Norman wrote:

    Is the code getting a string that is the hex representation ? ie "00" , "00" or BYTES with those values ?

    Answer
    the code is getting BYTES in a dataGram

  19. Sample data (hex dump)

    AD BC CB DA 00 00 00 02 00 00 00 01 00 00 00 06 . . . . . . . . . . . . . . . .
    57 53 4A 54 2D 58 00 00 00 00 00 36 85 08 00 00 W S J T - X . . . . . 6 . . . .
    00 03 46 54 38 00 00 00 06 4A 52 36 45 5A 45 00 . . F T 8 . . . . J R 6 E Z E .
    00 00 01 33 00 00 00 03 46 54 38 01 00 01 00 00 . . . 3 . . . . F T 8 . . . . .
    05 16 00 00 03 E8 00 00 00 05 57 31 4B 4F 4B 00 . . . . . . . . . . W 1 K O K .
    00 00 04 44 4D 30 34 00 00 00 04 50 4D 35 33 00 . . . D M 0 4 . . . . P M 5 3 .
    FF FF FF FF 00 . . . . .

  20. Norman P

    Mar 21 Pre-Release Testers, Xojo Pro Alberta Canada

    yeah if the MB already has the bytes and you just want the decimal value then

    dim beI64 as Uint64 = mb.UInt64Value(offset) /// start at whatever byte offset in the memory block you need <<<

    will give you an unsigned int 64 (8 bytes) with one line of code

    instead of

    if wsjtxData.Byte( 11 ) = 1 Then
      s = decodeQ64( wsjtxData, 22 )
      outPut.AppendText s + chr( 13 )
    end if

    and all the code in decodeQ64 you can do

    if wsjtxData.Byte( 11 ) = 1 Then
      dim beI64 as Uint64 = mb.UInt64Value(offset)
      outPut.AppendText s + str(beI64) + chr(13) // you might use end of line here
    end 
  21. Newer ›

or Sign Up to reply!