B4R Library [module] GlobalStore - Global objects storage

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User
As explained in the tutorial about memory management in B4R: https://www.b4x.com/android/forum/threads/65672/#content it is not trivial to assign the value of a local, non-numeric, variable to a global variable.

The reason behind this limitation is that the memory is statically allocated during compilation. It is therefore only possible to set fixed-size values (such as numbers).

GlobalStore allows storing arrays of bytes or strings.
B4X:
GlobalStore.Put(0, "A String") 'store value in slot #0
Log(GlobalStore.Slot0) 'get the value from slot #0
There are 5 slots by default. Note that the data is stored internally in a single array of bytes and it takes care of maintaining the indices and lengths of the slots arrays.

Notes & Tips:

- The data is saved in a global buffer. Its size is set to 100. You can increase it if you encounter out of arrays exceptions.
- Always set the values with the Put method and get them from the SlotX fields.

It depends on rRandomAccessFile library.
 

Attachments

Last edited:

Erel

Administrator
Staff member
Licensed User
There was a design flaw in the previous version of GlobalStore which caused the data to be corrupted in some cases.

Version 2.00 fixes this issue. The API has changed a bit. See the code example in the first post.

Note that it supports arrays of bytes or strings.
 

max123

Active Member
Licensed User
Maybe this is a solution of all my problems, now I know because I can't save data on global variables.

If eg. I create a new type and declare it as global variable, this do not works, i save data and then when I read, retrieve wrong data..... for this reason in Arduino IDE I used string class, because this class allow to dinamically add new data, or just reserve some fixed space this way that I think internally use malloc():
B4X:
void ESP8266VirtualDisplay::setSliderValue(byte idx, unsigned int val){
  String root;
  root.reserve(80);
  root = "cmd" + CM + "SetSliderValue" + CM;
  root += idx + CM;
  root += val;
  SendCmd(root);
}
I will study your GlobalStore module to know how it works. I see, very small code, about 50 lines. Many thanks for this. ;)
 

max123

Active Member
Licensed User
I've set a slot number to 10 (that seem to work on ESP8266)
B4X:
'You can change the number of slots. You must update the next three lines.
Public Slot0(), Slot1(), Slot2(), Slot3(), Slot4(), Slot5(), Slot6(), Slot7(), Slot8(), Slot9() As Byte
Public slots() As Object = Array(Slot0, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7, Slot8, Slot9)
Private lengths(10) As Byte
Then I increased a buffer size:
B4X:
Private GlobalBuffer(800) As Byte
then I tried to add a Get method to get indicized slots:
B4X:
Public Sub Get(slot As Int) As Byte()
    Return slots(slot)
End Sub
Now with this this code I can write/read up 10 slots and indicize slots in a For Next loop:
B4X:
Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")

    'PART ONE
    GlobalStore.Put(0, "This is the String 0") 'store value in slot #0
    GlobalStore.Put(1, "This is the String 1") 'store value in slot #1
    GlobalStore.Put(2, "This is the String 2") 'store value in slot #2
    GlobalStore.Put(3, "This is the String 3") 'store value in slot #3
    GlobalStore.Put(4, "This is the String 4") 'store value in slot #4
    GlobalStore.Put(5, "This is the String 5") 'store value in slot #5
    GlobalStore.Put(6, "This is the String 6") 'store value in slot #6
    GlobalStore.Put(7, "This is the String 7") 'store value in slot #7
    GlobalStore.Put(8, "This is the String 8") 'store value in slot #8
    GlobalStore.Put(9, "This is the String 9") 'store value in slot #9

    '    Log(GlobalStore.Slot0) 'get the value from slot #0
    Log(GlobalStore.Get(0)) 'get value from slot #0
    Log(GlobalStore.Get(1)) 'get value from slot #1
    Log(GlobalStore.Get(2)) 'get value from slot #2
    Log(GlobalStore.Get(3)) 'get value from slot #3
    Log(GlobalStore.Get(4)) 'get value from slot #4
    Log(GlobalStore.Get(5)) 'get value from slot #5
    Log(GlobalStore.Get(6)) 'get value from slot #6
    Log(GlobalStore.Get(7)) 'get value from slot #7
    Log(GlobalStore.Get(8)) 'get value from slot #8
    Log(GlobalStore.Get(9)) 'get value from slot #9

    'PART TWO
    Log("Now we write bytes")

    For i = 0 To GlobalStore.slots.Length-1     ' it returns 9 as right value
        Log("Write ", i)
        Dim tmp() As Byte = "This is another String (overwritten slot)"
        GlobalStore.Put(i, tmp) 'store value
    Next

    Log("Now we read bytes")

    For i = 0 To GlobalStore.slots.Length-1    ' it returns 9 as right value
        Log("Read ", i)
        Log(GlobalStore.Get(i)) 'get value
    Next
End Sub
And this is the output:
AppStart
This is the String 0
This is the String 1
This is the String 2
This is the String 3
This is the String 4
This is the String 5
This is the String 6
This is the String 7
This is the String 8
This is the String 9
Now we write bytes
Write 0
Write 1
Write 2
Write 3
Write 4
Write 5
Write 6
Write 7
Write 8
Write 9
Now we read bytes
Read 0
This is another String (overwritten slot)
Read 1
This is another String (overwritten slot)
Read 2
This is another String (overwritten slot)
Read 3
This is another String (overwritten slot)
Read 4
This is another String (overwritten slot)
Read 5
This is another String (overwritten slot)
Read 6
This is another String (overwritten slot)
Read 7
This is another String (overwritten slot)
Read 8
This is another String (overwritten slot)
Read 9
This is another String (overwritten slot)
but if I comment in the code a PART ONE I've strange issue, ESP works, but after a bit stop it's execution, seem to enter on infinite loop, no errors, this is the result, after this ESP do not respond, eg. if I put a Log("Hello") I can't see on serial log:
AppStart
Now we write bytes
Write 0
Write 1
Write 2
Write 3
Write 4
Write 5
Write 6
Write 7
Write 8
Write 9
Now we read bytes
Read 0
This is another String (overwritten slot)
Read 1
This is another String (overwritten slot)
Read 2
This is another String (overwritten slot)
Read 3
This is another String (overwritten slot)
Read 4 <<<<<< HERE IT STOPS
 

max123

Active Member
Licensed User
Ok, thanks so much!

Outside of For Next loop, the Get method seem to works well here.
 

Erel

Administrator
Staff member
Licensed User
The Get method you added can cause memory issues as it copies the data to the stack buffer. By using the slot methods the data is not copied.
 

max123

Active Member
Licensed User
Many thanks Erel, I removed Get method from GlobalStore module, now I will try to use it on my FirebaseCloudMessaging library.

I need to mantain this data globally:
B4X:
Type KeyValuePair(key() As Byte, val() As Byte)
Public field(10) As KeyValuePair
And write/read like this:
B4X:
'write
field(2).key = "title".GetBytes
field(2).val = Title
field(3).key = "message".GetBytes
field(3).val = Message

'read
Dim notificationTitle() As Byte = field(2).val
Dim notificationMessage() As Byte = field(3).val
Currently I write fields and after a bit if I read just returns void byte array, so can't get it, missed data or strange characters.

Can I put fields inside a slots to store and read?
 
Last edited:

ivan.tellez

Active Member
Licensed User
I want to make some Mqtt devices. For that, they need to send unique topics. I want to use the MAC to do something like

somename/MAC/somefunction
somename/MAC/somefunction


But instead of doing

B4X:
mqtt.Publish(JoinStrings(Array As String("home/", GetMacAddress, "status"), Serializator.ConvertArrayToBytes(Array(iBtnNum, iState)))
Because JoinStrings is an expensive functions, maybe it should be a way to have some global vars with the topics. I tried:

In AppStart:

B4X:
        GlobalStore.Put(0, JoinStrings(Array As String("home/", MyMac, "/out")))
        'Also:
        Dim Topic As String = JoinStrings(Array As String("home/", MyMac, "/in"))
        GlobalStore.Put(1, Topic)
And then use:
B4X:
mqtt.Subscribe(GlobalStore.Slot0, 0)
'And
mqtt.Publish(GlobalStore.Slot1, Serializator.ConvertArrayToBytes(Array(iBtnNum, iState)))
In the logs it prints the correct textbut this fails:


B4X:
Sub Mqtt_MessageArrived (Topic As String, Payload() As Byte)
       Log("Topic: ", Topic)
       Log ("Slot1: ", GlobalStore.Slot1)
  
      If Topic = GlobalStore.Slot1 Then
      
    Else
        Log("Topic <> Slot1")
    End If
It prints: "Topic <> Slot1"



And, in the other side, the Topic recived is something like this: "1073669004"



Is it posible to use GlobalStore For this?
 
Last edited:
Status
Not open for further replies.
Top