I am trying to wrap my head around when to use Memory Blocks. For example I am using a method I wrote to convert Decimal to Hex to Ascii codes to put on the wire in a frame over TCP. Could I use Memory block to do this conversion quicker/easier than my code below? I have read through the LR and I am not 100% clear when/why to use it. I see alot of you using it so it must be good to use
Thanks again!!
My Packet Design allows for user readability using Decimals.
Private Function ConvertDec2Hex2Asc(InputString as integer) As String
Dim ConvertToHex as String = Hex(InputString)
Dim Result, ToProcess as String
Dim CountLength as Integer = Len(ConvertToHex)
for i as integer = 2 to CountLength step 2
ToProcess = Left(ConvertToHex,i)
ToProcess = "&h" + ToProcess
Result = Result + ChrB(CDbl(ToProcess))
next i
Return Result
End Function
No offense, but that is some very convoluted code. It also contains some potentially serious errors. In essence, all you are doing is pulling one byte at a time out of the integer and converting it to a character. The result will be a “binary string”. The memoryblock equivalent would be
Private Function ConvertDec2Hex2Asc(InputString as integer) as string
dim mb as new MemoryBlock(4)
dim Result as String = chrb(0)
mb.IntegerValue(0) = InputString
for i as integer = 0 to 3
if mb.byte(i)<> 0 then
Result = mb.StringValue(i, 4-i)
exit
end if
next
return Result
end function
This code is more complicated than it needs to be, but it should match your existing functionality where you strip off any leading zero bytes via the Hex() function. However, you get a variable length string as a result, which I’m sure will cause complexity in your transmission protocol. Are you sending the length of the string as well? How are you decoding it on the other end? I would think it would be easier to transmit a fixed length 4-byte value. The code would then be
Private Function ConvertDec2Hex2Asc(InputString as Integer) as String
dim mb as new MemoryBlock(4)
dim Result as String
mb.IntegerValue(0) = InputString
Result = mb.StringValue(0,4)
return Result
end function
Or, better, use a Structure for the entire transmission frame.
Thanks Tim! Yes it is convoluted as it represents my thought process which isn’t smooth on this yet I am also still new to programming in general Thank you for your help!
Since your header frame is fixed length and all of it is numeric, I wouldn’t do any kind of individual string conversions. Just stuff it into a Structure and pull the entire string out in one go. Note, however, that you may need to align your integers on an even byte boundary, so your SOF might need to be 2 bytes instead of one to make it all work smoothly.
dim s as myStructure
dim head as string
s.Preamble = 4607
s.SOF = 255
s.Version = 1
s.NodeID = 5000
head = s.StringValue(false)
I just looked over to my printed version and yes I had aligned SOF to “2” already thanks again Tim!! I just debugged your code while seeing how MB worked. Pretty awesome and man so much easier than what I was trying to do!!
Do you normally send the padded zeros if you have any or do you clip them prior to transmission to keep it clean?
If I take my variable string, measure it, and convert that to bytes I can add this number as a header field right before the payload to tell the other side how much payload to expect.
Ok I think I have it. Here is my new Frame Header Format to represent my changes:
Any thoughts or suggestions are always welcome Thank you again!!!
Private Function BuildFrame() As String
Dim Header As EVIP_Structure
Dim FrameHeader As String
Dim PayloadTest As String = "{""menu"":{""id"": ""file"",""value"":""File"",""popup"":{""menuitem"":[{""value"": ""New"", ""onclick"": ""CreateNewDoc()""},{""value"":""Open""onclick"":""OpenDoc()""},{""value"":""Close"",""onclick"":""CloseDoc()""}]}}}"
Dim PayLoadLen As Integer = PayloadTest.Len
// Build the Frame Header via Structure
Header.Preamble = 4607
Header.SOF = 255
Header.ProtVer = 1
Header.NodeID = 5555
Header.OptionType = 5001
Header.OptionData = 187
Header.PayloadSize = PayloadTest.Len
FrameHeader = Header.StringValue(TargetLittleEndian)
// Build Payload via Memory Block with Size defined by Length of Payload String
Dim PayloadMB As New MemoryBlock(PayLoadLen)
Dim FrameToSend As String
PayloadMB.LittleEndian = False
PayloadMB.StringValue(0,PayLoadLen) = PayloadTest
FrameToSend = FrameHeader + PayloadMB.StringValue(0,PayLoadLen)
Return FrameToSend
End Function
FYI, MemoryBlocks self-convert to and from strings, so you can just say:
FrameToSend = FrameHeader + PayloadMB
Also, to create a MemoryBlock from a string, you can do this:
dim s as string = "some string"
dim mb as MemoryBlock = s
The mb.Size will equal s.LenB.
OH, and that underscores a bug in your code: You are using Len instead of LenB. If all of your characters are in the low-ascii range, it doesn’t matter, but you should use LenB just to be safe.
In fact, I’d restructure it to use a MemoryBlock for everything:
Â…
dim PayloadMB as MemoryBlock = PayloadTest
// Build the Frame Header via Structure
Header.Preamble = 4607
Header.SOF = 255
Header.ProtVer = 1
Header.NodeID = 5555
Header.OptionType = 5001
Header.OptionData = 187
Header.PayloadSize = PayloadMB.Size
FrameHeader = Header.StringValue(TargetLittleEndian)
Dim FrameToSend As String
PayloadMB.LittleEndian = False // Don't think this matters since you are just storing a string
FrameToSend = FrameHeader + PayloadMB
On second thought, the memoryblock does serve a purpose if you’re using it to control the Endianness of the string. If that’s your goal, then I defer to Kem.