B4R Question How do I remove an object from array?

Kevin

Well-Known Member
Licensed User
Longtime User
I used the ESP Configurator to get me started with communicating with my ESP-12E.

When I then tried using the B4A client example to communicate with it, it ended up screwing up the WiFi settings on the ESP. I quickly realized why after looking at the code.

So now I intend to add a "header" so to speak when communicating from a B4J or B4A app. In other words, I intend to first send a description of what the app is doing, such as "CONFIG" when sending WiFi configuration stuff or "DATA" when sending other config type things, such as setting the status of a relay.

I have worked out a way to take the incoming bytes and break it down into objects, then re-convert the objects back into bytes and send that on to where it saves the network details. This is working, so I think I am on the right path. But if I send a "header" part, I want to be able to remove that before handling it in the proper way.

Any suggestions or examples on how to do this? I can either remove the first object or create an all-new array of objects but leave out the first (the "header").

B4X:
Private Sub Astream_NewData (Buffer() As Byte)
    Log("New data arrived...")
    Log("Data length: ", Buffer.Length)
 
    Dim Objects() As Object = serializator.ConvertBytesToArray(Buffer,ObjectsBuffer)
    Log("Reading data: ")
    For Each o As Object In Objects
        Log("Incoming Object: ", o)
    Next
 
    ' How to remove the first object above and pass on the rest below?

    Dim FinalData() As Byte = serializator.ConvertArrayToBytes(Objects)
     
    Main.SaveNetworkDetails(FinalData) ' Originally Main.SaveNetworkDetails(Buffer)
 
End Sub
 

Kevin

Well-Known Member
Licensed User
Longtime User
I use the byteconverter class. Substrimg an substring2 is used to copy part of array/string to another.

I think I looked into that but nothing was clicking for me. I'll have another go at it in a bit. Would you happen to have an example?
 
Upvote 0

Kevin

Well-Known Member
Licensed User
Longtime User
I thought I may have been making some progress (and maybe I did) but I seem to have completely broken the communication between B4R and B4J. I don't get any data arrival events. :(

At this point, I'll take all the help I can get. I think I am just not understanding the idea of bytes.

B4X:
Private Sub Astream_NewData (Buffer() As Byte)  '<---- No longer seems to fire when sending data from the B4J config utility after attempting to insert a "CONFIG" header/variable before the "Board Name" text.
    Log("New data arrived...")
    Log("Data length: ", Buffer.Length)
    
    Dim Objects() As Object = serializator.ConvertBytesToArray(Buffer,ObjectsBuffer)
    Log("Reading data: ")
    For Each o As Object In Objects
        Log("Incoming Object: ", o)
    Next
    
    Dim bc As ByteConverter
    Dim FinalObjects() As Object
    
    'Need to detect Object #0 then remove it from the array and act accordingly
    Select Case Objects(0)
        Case "CONFIG"
            'Remove first object and handle Config stuff  ' <---- Am I close on how to remove the first object?
            For i = 1 To Objects.Length-1
                bc.ObjectSet (Objects(i),FinalObjects(i-1))
            Next
            Dim FinalData() As Byte = serializator.ConvertArrayToBytes(FinalObjects)
            'Main.SaveNetworkDetails(FinalData) 'Disable until I know this is working 'Originally Main.SaveNetworkDetails(Buffer)
        Case "DATA"
            'Remove first object and handle Data stuff
            For i = 1 To Objects.Length-1
                bc.ObjectSet (Objects(i),FinalObjects(i-1))
            Next
            Dim FinalData() As Byte = serializator.ConvertArrayToBytes(FinalObjects)
            ' Handle DATA request
        Case Else
            ' Unknown or no header, so assume it is Config stuff (eventually this shouldn't happen
            ' so we should then ignore it
            
            'Main.SaveNetworkDetails(FinalData) ' Originally Main.SaveNetworkDetails(Buffer)           
    End Select   
    
    'Temporary logging - eventually shouldn't get to this part of the sub
    For Each o As Object In FinalObjects
        Log("Final Object: ", o)
    Next
    Log ("Byte Array = [", FinalData, "]")
    
End Sub

On the plus side, I managed to add a functioning clock to my project. :D
 
Upvote 0

Kevin

Well-Known Member
Licensed User
Longtime User
Why aren't you adding the header field as the first element in the array sent from B4A?

Wouldn't Objects(0) be the first element in the array? It's possible that my Select Case code is not properly removing the header, but that may be part of my issue.

For now I am using B4J as the client as it is easier and quicker to test, but eventually will use B4A.

I'm working on it again now with fresh eyes. Some things are just a bit foreign to me, particularly bytes as well as the sheets & metadata in B4J.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
For now I am using B4J as the client as it is easier and quicker to test, but eventually will use B4A.
It doesn't matter.
I previously didn't understand how you are adding the header.

The simplest way that you can implement it with a generic solution where you don't know the number of items is to serialize the data that should be saved before you send it.
Now you have an array of bytes.
Create an array with the header and this array of bytes, serialize it and send it.

In B4R you only need to read the header and take the second item which is the array of bytes that should be saved and save it as-is.
 
Upvote 0

Kevin

Well-Known Member
Licensed User
Longtime User
Out of curiosity, will my Select Case code actually work regarding reading the value of the first object, as it is? Or do I need to do any conversions to a string first?

B4X:
Select Case Objects(0)
        Case "CONFIG"  ' <------ WIll this work or does it need converting to a string first?
 
Upvote 0

Kevin

Well-Known Member
Licensed User
Longtime User
I got it sorted out. I saw another thread (but since lost it) where you (Erel) suggested sending the data in separate chunks. Following that idea, I was able to get it working. Thanks for all the help in this thread and all of the valuable information in the many other threads here in this forum. :)

Below are the relevant parts in case it might help others:

B4R (WiFiServer module)
B4X:
Sub Process_Globals
    Private Astream As AsyncStreams   
    Private server As WiFiServerSocket
    Private serializator As B4RSerializator
    Private ObjectsBuffer(10) As Object
    Private HeaderReceived As Int  '<---- New, to keep track of the last header received as an integer
End Sub

Private Sub Astream_NewData (Buffer() As Byte)
    Log("New data arrived...")
    Log("Data length: ", Buffer.Length)
    
    Dim Objects() As Object = serializator.ConvertBytesToArray(Buffer,ObjectsBuffer)
    Log("Reading data: ")
    For Each o As Object In Objects
        Log("Incoming Object: ", o)
    Next
        
    Select Case Objects(0)
        Case "CONFIG"
            HeaderReceived = 1 'CONFIG
            Return
        Case "DATA"
            HeaderReceived = 2 'DATA
            Return
        Case Else ' Not a header, so process the data based on the last header received
            Select Case HeaderReceived
                Case 0 'No header received or detected (shouldn't happen)
                    If Main.Logging Then Log ("Data was received before a header!")
                Case 1 'CONFIG
                    Delay (500)
                    Main.SaveNetworkDetails(Buffer)
                    If Main.Logging Then Log ("CONFIG SETTINGS SAVED")
                Case 2 'DATA
                    If Main.Logging Then Log ("DATA handling not finished yet!")
                    ' Do something here
                Case Else
                    If Main.Logging Then Log("Unknown data received!")
            End Select
            HeaderReceived = 0 'Reset Header to nothing, wait for next header
    End Select
End Sub

B4J Configurator Example (Main module)
B4X:
Sub Connect (Get As Boolean)
    SetBusy(True)
    Try
        Disconnect
        Dim sock As Socket
        sock.Initialize("sock")
        sock.Connect(txtIP.Text, 51041, 10000)
        Wait For sock_Connected (Successful As Boolean)
        If Successful Then
            astream.InitializePrefix(sock.InputStream, False, sock.OutputStream, "astream")
            If Get Then
                Wait For astream_NewData (Buffer() As Byte)
                If Buffer(0) = 0 Then
                    rec.BoardName = "PoolMinder"
                Else
                    ' We recieved a 1 as the first byte sent, which means it has been configured
                    Log ("Board appears to have been configured")
                    Wait For (astream) AStream_NewData(Data() As Byte)
                    Dim ObjectsReceived() As Object = (ser.ConvertBytesToArray(Data))
                    Log (ObjectsReceived(0))
                    If ObjectsReceived(0) = "CONFIG" Then
                        Log ("Config Header received")
                        Wait for astream_NewData (Buffer() As Byte)
                        rec = ObjectsToRecord(ser.ConvertBytesToArray(Buffer))
                    End If
                End If
                sheet.Set(rec, meta)
            Else 'Put mode, so send the header followed by field values to the B4R project
                Dim HeaderObj As Object = Array ("CONFIG")
                astream.Write(ser.ConvertArrayToBytes(HeaderObj))
                Sleep(1500)
                astream.Write(ser.ConvertArrayToBytes(RecordToObjects(rec)))
                Sleep(1500)
            End If
        Else
            cutils.ShowNotification2("Failed to connect", "", cutils.ICON_ERROR, MainForm)
        End If
        Disconnect
    Catch
        Log(LastException)
    End Try
    SetBusy(False)
End Sub
 
Upvote 0
Top