I am new to VB and I am trying to get a program to output text instead of hex. I found the code online, a program called maxiCOM. Here is the link http://www.innovatic.dk/knowledg/SerialCOM/SerialCOM.htm. The source code can be downloaded at the bottom of the page.
Unfortunately, the level of coding in the program is far above my level of understanding, and I don't really get how to change the output from hex to text. I would greatly appreciate it if someone could explain to me how to do this. The snippet of the code is
Public Class MaxiTester
Dim SpaceCount As Byte = 0
Dim LookUpTable As String = "0123456789ABCDEF"
Dim RXArray(2047) As Char ' Text buffer. Must be global to be accessible from more threads.
Dim RXCnt As Integer ' Length of text buffer. Must be global too.
' Make a new System.IO.Ports.SerialPort instance, which is able to fire events.
Dim WithEvents COMPort As New SerialPort
Private Sub Receiver(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles COMPort.DataReceived
Dim RXByte As Byte
Do
'----- Start of communication protocol handling -----------------------------------------------------------
' The code between the two lines does the communication protocol. In this case, it simply emties the
' receive buffer and converts it to text, but for all practical applications, you must replace this part
' with a code, which can collect one entire telegram by searching for the telegram
' delimiter/termination. In case of a simple ASCII protocol, you may just use ReadLine and receive
' in a global string instead of a byte array.
' Because this routine runs on a thread pool thread, it does not block the UI, so if you have any data
' convertion, encryption, expansion, error detection, error correction etc. to do, do it here.
RXCnt = 0
Do
RXByte = COMPort.ReadByte
RXArray(RXCnt) = LookUpTable(RXByte >> 4) ' Convert each byte to two hexadecimal characters
RXCnt = RXCnt + 1
RXArray(RXCnt) = LookUpTable(RXByte And 15)
RXCnt = RXCnt + 1
RXArray(RXCnt) = " "
RXCnt = RXCnt + 1
SpaceCount = (SpaceCount + 1) And 31 ' Insert spaces and CRLF for better readability
If SpaceCount = 0 Then ' Insert CRLF after 32 numbers
RXArray(RXCnt) = Chr(13) ' CR
RXCnt = RXCnt + 1
RXArray(RXCnt) = Chr(10) ' LF
RXCnt = RXCnt + 1
Else
If (SpaceCount And 3) = 0 Then ' Insert two extra spaces for each 4 numbers
RXArray(RXCnt) = " "
RXCnt = RXCnt + 1
RXArray(RXCnt) = " "
RXCnt = RXCnt + 1
End If
End If
Loop Until (COMPort.BytesToRead = 0)
'----- End of communication protocol handling -------------------------------------------------------------
Me.Invoke(New MethodInvoker(AddressOf Display)) ' Start "Display" on the UI thread
Loop Until (COMPort.BytesToRead = 0) ' Don't return if more bytes have become available in the meantime
End Sub
' Text display routine, which appends the received string to any text in the Received TextBox.
Private Sub Display()
Received.AppendText(New String(RXArray, 0, RXCnt))
End Sub
System.Text.Encoding.Unicode.GetString(bytes) 'bytes is your byte array'
Notice the first line after Do in your inner loop:
RXByte = COMPort.ReadByte
This is the only point in your code where you have the actual byte value read from the COM port. After this point the code converts the byte into two hex values using bit-shifting. You should create a global variable of string type and append the read byte value to this string before it is lost.
Add the following line immediately after the above line:
YourString &= Convert.ToChar(RXByte).ToString()
where YourString is your global string variable.
Note that you can attain some efficiency by using StringBuilder instead of string, but I'm leaving that for you as exercise.
Related
I am trying to separate the string data in an HTTP protocol in wireshark using lua and I am not having success finding the end of the string, this is what I currently have
HTTP_protocol = Proto("ourHTTP", "HTTPProtocol")
first =ProtoField.string("HTTP_protocol.first", "first", base.ASCII)
second =ProtoField.string("HTTP_protocol.second", "second", base.ASCII)
HTTP_protocol.fields = {first}
function HTTP_protocol.dissector(buffer, pinfo, tree)
length = buffer:len()
if length ==0 then return end
pinfo.cols.protocol = HTTP_protocol.name
local subtree = tree:add(HTTP_protocol, buffer(), "HTTPProtocol data ")
local string_length
for i = 0, length - 1, 1 do
if (buffer(i,1):uint() == '\r') then
string_length = i - 0
break
end
end
subtree:add(first, buffer(0,string_length))
end
porttable = DissectorTable.get("tcp.port")
porttable:add(80, HTTP_protocol)
i have tried searching for '\r', '\0' and '\n' but no matter what I still get all the strings inputed as one. Is there something I am doing wrong?
You can use 0x0D instead. That's the ASCII code for \r. So it will end up as
if (buffer(i,1):uint() == 0x0D) then
In Wireshark:
I need to remove the numeric part at the end of a string. Here are some examples:
"abcd1234" -> "abcd"
"a3bc45" -> "a3bc"
"kj3ih5" -> "kj3ih"
You get the idea.
I implemented a function which works well for this purpose.
Function VarStamm(name As String) As String
Dim i, a As Integer
a = 0
For i = Len(name) To 1 Step -1
If IsNumeric(Mid(name, i, 1)) = False Then
i = i + 1
Exit For
End If
Next i
If i <= Len(name) Then
VarStamm = name.Substring(0, i - 1)
Else
VarStamm = name
End If
End Function
The question is: is there any faster (more efficient in speed) way to do this? The problem is, I call this function within a loop with 3 million iterations and it would be nice to have it be more efficient.
I know about the String.LastIndexOf method, but I don't know how to use it when I need the index of the last connected number within a string.
You can use Array.FindLastIndex and then Substring:
Dim lastNonDigitIndex = Array.FindLastIndex(text.ToCharArray(), Function(c) Not char.IsDigit(c))
If lastNonDigitIndex >= 0
lastNonDigitIndex += 1
Dim part1 = text.Substring(0, lastNonDigitIndex)
Dim part2 = text.Substring(lastNonDigitIndex)
End If
I was skeptical that the Array.FindLastIndex method was actually faster, so I tested it myself. I borrowed the testing code posted by Amessihel, but added a third method:
Function VarStamm3(name As String) As String
Dim i As Integer
For i = name.Length - 1 To 0 Step -1
If Not Char.IsDigit(name(i)) Then
Exit For
End If
Next i
Return name.Substring(0, i + 1)
End Function
It uses your original algorithm, but just swaps out the old VB6-style string methods for newer .NET equivalent ones. Here's the results on my machine:
RunTime :
- VarStamm : 00:00:07.92
- VarStamm2 : 00:00:00.60
- VarStamm3 : 00:00:00.23
As you can see, your original algorithm was already quite well tuned. The problem wasn't the loop. The problem was Mid, IsNumeric, and Len. Since Tim's method didn't use those, it was much faster. But, if you stick with a manual for loop, it's twice as fast as using Array.FindLastIndex, all things being equal
Given your function VarStamm and Tim Schmelter's one named VarStamm2, here is a small test performance I wrote. I typed an arbitrary long String with a huge right part, and ran the functions one million times.
Module StackOverlow
Sub Main()
Dim testStr = "azekzoerjezoriezltjreoitueriou7657678678797897898997897978897898797989797"
Console.WriteLine("RunTime :" + vbNewLine +
" - VarStamm : " + getTimeSpent(AddressOf VarStamm, testStr) + vbNewLine +
" - VarStamm2 : " + getTimeSpent(AddressOf VarStamm2, testStr))
End Sub
Function getTimeSpent(f As Action(Of String), str As String) As String
Dim sw As Stopwatch = New Stopwatch()
Dim ts As TimeSpan
sw.Start()
For i = 1 To 1000000
f(str)
Next
sw.Stop()
ts = sw.Elapsed
Return String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10)
End Function
Function VarStamm(name As String) As String
Dim i, a As Integer
a = 0
For i = Len(name) To 1 Step -1
If IsNumeric(Mid(name, i, 1)) = False Then
i = i + 1
Exit For
End If
Next i
If i <= Len(name) Then
VarStamm = name.Substring(0, i - 1)
Else
VarStamm = name
End If
End Function
Function VarStamm2(name As String) As String
Dim lastNonDigitIndex = Array.FindLastIndex(name.ToCharArray(), Function(c) Not Char.IsDigit(c))
If lastNonDigitIndex >= 0 Then
lastNonDigitIndex += 1
Return name.Substring(0, lastNonDigitIndex)
End If
Return name
End Function
End Module
Here is the output I got:
RunTime :
- VarStamm : 00:00:38.33
- VarStamm2 : 00:00:02.72
So yes, you should choose his answer, his code is both pretty and efficient.
I have to import an Excel file into an Access db. My Excel has a column called 'Description'. Usually the description is long a cell, but it can happens that is more long. If it is long more than 255 characters, I cut the string and I modify last 3 characters with '...'.
When I run the program, though, I have an error "Index and length must refer to a location within the string".
I tried even to erase the check on the length, but obviously I had this error "Field is too small to accept the amount of data you attempted to add"
If flag = 2 Then
stringVoice = grid(r, 3).Text
voc.Description = voc.Description & stringVoice
If voc.Description.Length > 255 Then
voc.Description = grid(r, 3).Text.ToString.Substring(0, 252) + "..."
End If
End If
This is the code that produced the Index and length error. Same check has done before if inside a single cell there are more than 255 characters
Case 1 'voce
id = id + 1
flag = 2
voc = New cVoce
c_Voc = voc.Cod_Chapter
p_Voc = voc.Cod_Paragraph
voc.Cod_Chapter = grid(r, 1).Text.Substring(0, 1)
voc.Cod_Paragraph = grid(r, 1).Text.Split(".")(0)
voc.Cod_Voice = Right(vett(0), 2)
If grid(r, 3).Text.Length > 255 Then
voc.Description = grid(r, 3).Text.ToString.Substring(0, 252) + "..."
Else
voc.Description = grid(r, 3).Text.ToString
If voc.Description.EndsWith("-") Then
a = Replace(voc.Description, "-", "")
voc.Description = a
End If
End If
stringVoice = voc.Description
voices.Add(voc)
but in this case I've never had an error.
Can anyone help me to fix my code?
Hello everyone.
Dim txt1 As Double = Convert.ToDouble(TextBox1.Text) / 100
Dim txt2 As Double = Convert.ToDouble(TextBox2.Text)
Dim txt3 As Double = Convert.ToDouble(TextBox3.Text)
Dim txtResult As Double = Convert.ToDouble(TextBox4.Text)
Dim result As Double = txt1 * txt2 * txt3
TextBox4.Text = result
As you can see I get my result depending on what the user types in. So I have to add a space after a certain character. Textbox14.text(0) <--- after this do I want my space. It's so that after the value is higher than 999 it should type out 1 000 and not 1000. Thank you very much for any useful help, I've truly looked everywhere, I just can't find anything.
You talking about group separator. Custom Numeric Format Strings
You can use .ToString() method and define group separator in the format.
TextBox4.Text = result.ToString("0,0.000")
Different separators will be used based on the local system's language/region settings.
You can define your custome separator manually
var cultureInfo = new System.Globalization.CultureInfo("en-US");
var numberInfo = cultureInfo.NumberFormat;
numberInfo.NumberGroupSeparator = " ";
TextBox4.Text = result.ToString("0,0.000", numberInfo)
If I get it right, you want every 3 chars a space, right ?
Like 1 000 000 ?
try this :
Dim result As String, str As String, ret As String
Dim i As Integer
Dim arr As Char()
'your text to space
result = "10000000"
'reverte so we start with the end
result = StrReverse(result)
i = 0
ret = ""
' make a char array which each char is an own array element
arr = result.Take(result.Length).ToArray
'iterate through all elements
For Each str In arr
' skip the first element .
' only add a space every 3 elements
If (i <> 0) And (i Mod 3 = 0) Then
ret = ret + " "
End If
ret = ret + str
i = i + 1
Next
' revers again the output
ret = StrReverse(ret)
MsgBox(ret)
I have string
'TEST1, TEST2, TEST3'
I want to have
'TEST1,TEST2,TEST3'
Is in powerbuilder is a function like replace, substr or something?
One way is to use the database since you probably have an active connection.
string ls_stringwithspaces = "String String String String"
string ls_stringwithnospace = ""
string ls_sql = "SELECT replace('" + ls_stringwithspaces + "', ' ', '')"
DECLARE db DYNAMIC CURSOR FOR SQLSA;
PREPARE SQLSA FROM :ls_sql USING SQLCA;
OPEN DYNAMIC db;
IF SQLCA.SQLCode > 0 THEN
// erro handling
END IF
FETCH db INTO :ls_stringwithnospace;
CLOSE db;
MessageBox("", ls_stringwithnospace)
Sure there is (you could have easily found it in the help) but it is not quite helpful, though.
Its prototype is Replace ( string1, start, n, string2 ), so you need to know the position of the string to replace before calling it.
There is a common wrapper for this that consists of looping on pos() / replace() until there is nothing left to replace. The following is the source code of a global function:
global type replaceall from function_object
end type
forward prototypes
global function string replaceall (string as_source, string as_pattern, string as_replace)
end prototypes
global function string replaceall (string as_source, string as_pattern, string as_replace);//replace all occurences of as_pattern in as_source by as_replace
string ls_target
long i, j
ls_target=""
i = 1
j = 1
do
i = pos( as_source, as_pattern, j )
if i>0 then
ls_target += mid( as_source, j, i - j )
ls_target += as_replace
j = i + len( as_pattern )
else
ls_target += mid( as_source, j )
end if
loop while i>0
return ls_target
end function
Beware that string functions (searching & concatenating) in PB are not that efficient, and an alternative solution could be to use the FastReplaceall() global function provided by the PbniRegex extension. It is a c++ compiled plugin for PB classic from versions 9 to 12.
I do that:
long space, ll_a
FOR ll_a = 1 to len(ls_string)
space = pos(ls_string, " ")
IF space > 0 THEN
ls_string= Replace(ls_string, space, 1, "")
END IF
NEXT