For a serial port user interface, I've stored menu data in program memory as StringVectorData. Depending on which menu I am displaying, a sub is called which parses the data and sends it off to the port.
There's a bunch of them though, and the code to handle the VectorData is repeated for each sub because I can't get a working method to pass the information along to another function or sub that can be called from multiple locations.
Perhaps Don or Mike could clue me in as to how to effectively/efficiently pass the data, while maintaining it's current string formatting? I know it's possible using byte data, but the strings are so much easier to deal with.
-Don
Passing StringVectorData
Re: Passing StringVectorData
There is no easy solution to this problem but it can be solved if you don't mind using some implementation-specific information. Firstly, consider this program fragment that has two string tables and a call to a single routine to display a particular string from each one of them. Here, the address of the string table is passed to the display routine.Don_Kirby wrote:I can't get a working method to pass the information along to another function or sub that can be called from multiple locations.
Code: Select all
Dim ps1 as StringVectorData({
"able",
"baker",
"charlie",
"delta"
})
Dim ps2 as StringVectorData({
"red",
"orange",
"yellow",
"green"
})
Sub Main()
Call dspStr(CUInt(ps1.DataAddress), 3)
Call dspStr(CUInt(ps2.DataAddress), 2)
End Sub
First, the brute force" solution.
Code: Select all
Sub dspStr(ByVal strTbl as UnsignedInteger, ByVal idx as Integer)
Dim addr as UnsignedInteger
Dim strData as ProgMem Byte Based addr
Dim strLen as Byte
' read the string address from the index table
Call GetProgMem(CLng(strTbl + CUInt(idx - 1) * 2), addr, 2)
' read the string's length and advance the address to the first character
strLen = strData
addr = addr + 2
' display the characters of the string
Do While (strLen > 0)
Debug.Print Chr(strData);
addr = addr + 1
strLen = strLen - 1
Loop
Debug.Print
End Sub
Code: Select all
Sub dspStr2(ByVal strTbl as UnsignedInteger, ByVal idx as Integer)
Const MaxStrLen as Byte = 30
Dim addr as UnsignedInteger
Dim strLen as Byte
Dim str as BoundedString(MaxStrLen)
' read the string address from the string table
Call GetProgMem(CLng(strTbl + CUInt(idx - 1) * 2), addr, 2)
' read the string length
Call GetProgMem(CLng(addr), strLen, 1)
' limit the string length to fit in the string variable
If (strLen > MaxStrLen) Then
strLen = MaxStrLen
End If
' populate the string variable
Call GetProgMem(CLng(addr), str.DataAddress, strLen + 2)
' set the string length (possibly truncated)
Call RamPoke(strLen, str.DataAddress)
Debug.Print str
End Sub
It should be noted that SizeOf(ps1) returns the value 8, i.e. it returns the size of the index table, twice the number of entries in the table.
- Don Kinzer
Re: Passing StringVectorData
Luckily, the upper bound is fixed at 15, so no bound checking is required.dkinzer wrote: The code for both implementations does not validate the index but it should. A third parameter could be supplied giving the highest valid index.
After I posted, I implemented a quick-fix by simply copying the string data into an array, which gets passed to the sub for output (via a module level variable). It uses about 50 bytes more RAM, but frees up 2064 bytes of program space.
I'm currently working on your method to see what the results are. At the moment, the RAM usage is well below the device's limit, so I have some room to work with. The code size , however, is growing continuously as I add features, so this is where I am concentrating the effort to optimize.
Thanks Don, for once again, pointing the way.
-Don
In order to pass the entire table, I added a simple loop around the code. Pass in the max number of entries, and it cycles through. I am unable to test it at the moment, however it compiles fine, with no impact on RAM usage, and still 1700 bytes less program memory than the original code.
It is called via:
-Don
Code: Select all
Private Sub ShowMenu(ByVal MenuAddress as UnsignedInteger, ByVal maxIdx as Integer)
Const MaxStrLen as Byte = 30
Dim strLen as Byte
Dim addr as UnsignedInteger
Dim str as BoundedString(MaxStrLen)
Dim I as Byte
For I = 1 to CByte(maxIdx)
' read the string address from the string table
Call GetProgMem(CLng(MenuAddress + CUInt(I - 1) * 2), addr, 2)
' read the string length
Call GetProgMem(CLng(addr), strLen, 1)
' limit the string length to fit in the string variable
If (strLen > MaxStrLen) Then
strLen = MaxStrLen
End If
' populate the string variable
Call GetProgMem(CLng(addr), str.DataAddress, strLen + 2)
' set the string length (possibly truncated)
Call RamPoke(strLen, str.DataAddress)
Console.WriteLine(str) 'show the menu item
Next I
End Sub
Code: Select all
Call ShowMenu(CUInt(CAL_MENU_ITEMS.DataAddress), uBound(CAL_MENU_ITEMS))