vb.net serial port character encoding - vb.net

I'm working with VB.NET and I need to send and receive bytes of data over serial. This is all well and good until I need to send something like 173. I'm using a Subroutine to send a byte that takes an input as an integer and just converts it to a character to print it.
Private Sub PrintByte(ByVal input As Integer)
serialPort.Write(Chr(input))
End Sub
If i try
PrintByte(173)
Or really anything above 127 it sends 63. I thought that was a bit odd, so i looked up the ASCII table and it appears 63 corresponds to the ? character. So i think what is happening is VB.NET is trying to encode that number into a character that it does not recognize so it just prints a ?.
What encoding should I use, and how would I implement the encoding change?

The issue here is the SerialPort.Encoding property. Which defaults to Encoding.ASCII, an encoding that cannot handle a value over 127. You need to implement a method named PrintByte by actually sending a byte, not a character:
Private Sub PrintByte(ByVal value As Integer)
Dim bytes() As Byte = {CByte(value)}
serialPort.Write(bytes, 0, bytes.Length)
End Sub

Related

VB.NET - Convert String Representation of a Byte Array back into a Byte Array

I have an application that makes a call to a third party web API that returns a String that looks something like this:
"JVBERi0xLjMNCiXi48/TDQoxIDAgb2JqDQo8PA0KL1R5cGUgL091dGxpbmVzDQovQ291bnQgMA0KPj4NCmVuZG9iag0KMiAwIG9iag0KDQpbL1BERiAvVGV4dCAvSW1hZ2VDXQ0KZW"
(It's actually much longer than that but I'm hoping just the small snippet is enough to recognize it without me pasting a string a mile long)
The documentation says it returns a Byte array but when I try to accept it as a Byte array directly, I get errors. Part of my problem here is that the documentation isn't completely clear what the Byte array represents. Since it's a GetReport function I'm calling, I'm guessing it's a PDF but I'm not 100% sure as the documentation doesn't say at all.
So, anyway, I'm getting this String and I'm trying to convert it to a PDF. Here's what that looks like:
Dim reportString As String = GetValuationReport(12345, token.SecurityToken)
Dim report As Byte() = System.Text.Encoding.Unicode.GetBytes(reportString)
File.WriteAllBytes("C:\filepath\myreport.pdf", report)
I'm pretty sure that the middle line converts the String into a new Byte array rather than simply converting it into its Byte array equivalent but I don't know how to do that.
Any help would be fantastic. Thanks!
It looks like your string may be Base64 encoded, in which case you would use this to convert it to bytes:
Dim report As Byte() = Convert.FromBase64String(reportString)

zLib decompress from string not file to DeflateStream

I've been trying for 2 weeks to uncompress this user-defined TXXX string from an MP3 ID2,3 file.
000000B0789C6330377433D63534D575F3F737B570343767B02929CA2C4B2D4BCD2B29B6B301D376367989B9A976C519F9E50ACE1989452536FA60019B924C20696800017A10CA461F2C6AA30FD58A61427E5E72AA42228A114666E6F88CD047721100D5923799
Thanks to Dr. Adler for the correct answer when I converted the values to a string.
I have tried both MS DeflateStream and GZipstream with no success.
Every example I see uses a stream file. I am not using a file, I have the above zLib code in both an array or string variable.
GZipstream gives me 'no magic number' and Deflatestream gives me 'Block length does not match with its complement'.
I read this post:
http://george.chiramattel.com/blog/2007/09/deflatestream-block-length-does-not-match.html
tried removing bytes from the head, no luck. (I read trazillions of articles for sending a string to Deflatestream but again 'no luck'!
I have the above string, so how do I send it to Deflatestream? I'd post the two hundred different code examples I tried but that would be silly.
The funny thing is, I built my webAudio cue marker editor in less than two weeks and this is the last thing I have it do (my program must get the marker positions from a program that has worst audio editor known to man (they embedded them in the MP3 for some (bad) reason). Hence, I wrote my own to change audio cue marker so I could save hours of frustration at work. However, I'm not getting much sleep lately.
Help me get some sleep, please.
You can use a MemoryStream instead of a FileStream as they are both Streams:
Imports System.IO
Imports System.IO.Compression
Imports System.Text
Module Module1
Function HexStringToBytes(s As String) As Byte()
If (s.Length And 1) = 1 Then
Throw New ArgumentException("String is an odd number of characters in length - it must be even.")
End If
Dim bb As New List(Of Byte)
For i = 0 To s.Length - 1 Step 2
bb.Add(Convert.ToByte(s.Substring(i, 2), 16))
Next
Return bb.ToArray()
End Function
Sub Main()
Dim s = "000000B0789C6330377433D63534D575F3F737B570343767B02929CA2C4B2D4BCD2B29B6B301D376367989B9A976C519F9E50ACE1989452536FA60019B924C20696800017A10CA461F2C6AA30FD58A61427E5E72AA42228A114666E6F88CD047721100D5923799"
Dim result As String = ""
' trim off the leading zero bytes and skip the three bytes 0xB0 0x78 0x9C
Dim buffer = HexStringToBytes(s).SkipWhile(Function(b) b = 0).Skip(3).ToArray()
Using ms As New MemoryStream(buffer)
Using decompressedMemoryStream As New MemoryStream
Using decompressionStream As New DeflateStream(ms, CompressionMode.Decompress)
decompressionStream.CopyTo(decompressedMemoryStream)
result = Encoding.Default.GetString((decompressedMemoryStream.ToArray()))
End Using
End Using
End Using
Console.WriteLine(result)
Console.ReadLine()
End Sub
End Module
Outputs:
71F3-15-FOO58A77 <trivevents><event><name>show Chart</name><time>10000000.000000</time></event><event><name>show once a</name><time>26700000.000000</time></event></trivevents>
(There is a leading zero byte.)
P.S. It looks a bit strange that there is 71F3-15-FOO58A77 with letter Os instead of zeros.
P.P.S. If you could get the compressed data into a Base64 string instead of a hex string, you could pack more data into the same space.

Replacing Characters Simultaneously

Hey guys I'm trying to make a program that helps people encrypt messages and decrypt messages using the Caesar shift cipher, I know it's probably already been done, I want to have a go myself though.
The problem I've been having is when it comes to encrypting the text. The user selects a number (between 1-25) and then the application will change the letters corresponding to the number chosen, e.g. if the user inputs "HI" and selects 2, both characters are moved two places down the alphabet outputting "JK". My main problem is the replacing characters though, mostly because I've set up the program to be able to encrypt large blocks of text, because my code is:
If cmbxKey.Text = "1" Then
If txtOutput.Text.Contains("a") Then
sOutput = txtOutput.Text.Replace("a", "b")
txtOutput.Text = sOutput
End If
If txtOutput.Text.Contains("b") Then
sOutput = txtOutput.Text.Replace("b", "c")
txtOutput.Text = sOutput
End If
End If
This means if the user inputs "HAY" it will change it to "HBY" and then because of the second if statement it will change it to "HCY" but I only want it to be changed once. Any suggestions to avoid this???? Thanks guys
Since you want to shift all characters, start out by looping though the characters using something like ToArray:
For each s as string in txtOutput.Text.ToArray
'This will be here for each character in the string, even spaces
Next
Then, rather than having cases for every letter, look at it's ascii number:
ACS(s)
...and shift it by the number you want to. Keep in mind that if the number is greater than (I don't know if you want upper/lower case) 122, you want to subtract 65 to get you back to "A".
Then you can convert it back into a character using:
CHR(?)
So this might look something like this:
Dim sb as new text.StringBuilder()
For each s as string in txtOutput.Text.ToArray
If asc(s) > 122 Then
sb.append(CHR(ASC(s) + ?YourShift? - 65)
Else
sb.append(CHR(ASC(s) + ?YourShift?)
END IF
Next
txtOutput.Text = sb.ToString
A very simple method of changing your application while keeping your strategy is to replace the lower case characters with upper case characters. Then they won't be recognized by the Replace method anymore.
Obviously, the problem is that you want to implement an algorithm. In general, an algorithm should be smart in the sense that you don't have to do the grunt work. That's why a method such as the one presented by Steve is smarter; it doesn't require you to map each character separately, which is tedious, and - as most tedious tasks - error prone.
One big issue arise when you're facing a String that the basic Alphanumeric table can't handle. A String that contains words like :
"Déja vu" -> The "é" is going to be what ?
And also, how about encoding the string "I'm Aaron Mbilébé" if you use .ToUpper().
.ToUpper returns "I'M AARON MBILÉBÉ".
You've lost the casing, and how do you handle the shifting of "É" ?
Of course, a code should be smart as pointed above, and I was used to deal with strings just by using the System.Text.ASCIIEncoding to make things easier. But from the moment I started to use large amount of textual datas, sources from the web, files (...) I was forced to dig deeper, and seriously consider string encoding (and System Endianness by the way, when coding and decoding string to/from array of bytes)
Re-think of what do you really want in the end. If you're the only one to use your code, and you're certain that you'll only use A..Z, 0..9, a..z, space and a fixed amount of allowed characters (like puntuation) then, just build a Table containing each of those chars.
Private _AllowedChars As Char() = { "A"c, "B"c, ... "0"c, "1"c, .. "."c, ","c ... }
or
Private _AllowedChars As Char() = "ABCDEF....012...abcd..xyz.;,?:/".ToCharArray()
Then use
Private Function ShiftChars(ByVal CurrentString As String, ByVal ShiftValue As Integer) As String
Dim AllChars As Char() = CurrentString.ToCharArray()
Dim FinalChars As Char()
Dim i As Integer
FinalChars = New Char(AllChars.Length - 1) {} ' It's VB : UpperBound is n+1 item.
' so n items is UpperBound - 1
For i = 0 To AllChars.Length - 1
FinalChars(i) = _AllowedChars((Array.IndexOf(_AllowedChars, AllChars(i)) + ShiftValue) Mod _AllowedChars.Length)
Next
Return New String(FinalChars)
End Function
And
Private Function UnShiftChars(ByVal CurrentString As String, ByVal ShiftValue As Integer) As String
' ... the same code until :
FinalChars(i) = _AllowedChars((Array.IndexOf(_AllowedChars, AllChars(i)) - ShiftValue + _AllowedChars.Length) Mod _AllowedChars.Length)
' ...
End Function
^^ Assuming ShiftValue is always positive (defined once)
But again, this only works when you have a predefined set of allowed characters. If you want a more flexible tool, you ought to start dealing with encodings, array of byte, BitConverter and have a look at system endianness. That's why I asked if someone else is goind to use your application : let's try this string :
"Xin chào thế giới" ' which is Hello World in vietnamese (Google Trad)
In that case, you may give up..? No ! You ALWAYS have a trick in your cards !
Just create your allowed chars on the fly
Private _AllowedChars As New SortedList(Of Char, Char)
-> get the string to encode (shift)
Private Function ShiftChars(ByVal CurrentString As String, ByVal ShiftValue As Integer) As String
Dim AllChars As Char() = CurrentString.ToCharArray()
Dim FinalChars As Char()
Dim i As Integer
' Build your list of allowed chars...
_AllowedChars.Clear()
For i = 0 To AllChars.Length - 1
If Not _AllowedChars.ContainsKey(AllChars(i)) Then
_AllowedChars.Add(AllChars(i), AllChars(i))
End If
Next
' Then, encode...
FinalChars = New Char(AllChars.Length - 1) {}
For i = 0 To AllChars.Length - 1
FinalChars(i) = _AllowedChars.Keys.Item((_AllowedChars.IndexOfKey(AllChars(i)) + ShiftValue) Mod _AllowedChars.Count)
Next
Return New String(FinalChars)
End Function
The same for Unshift/decode.
Note : in foreing languages, the resulting string is pure garbage and totally unreadable, unless you (un)shift the chars again.
However, the main limitation of this workaround is the same as the fixed chars array above : Once you encode your string, and add a char in your encoded string that doesn't exists in the initial generated allowed chars, then you've nuked your data and you won't be able to decode your string. All you'll have is pure garbage.
So one day... one day maybe, you'll have to dig deeper at the byte level of the thing, in a defined extended encoding (Unicode/UTF8/16) to secure the integrity of your data.

Converting a VB6 module to VB.NET

I'm almost done converting a module from VB6 to VB.NET, but I'm having trouble with the following 2 quotes and am wondering if there's any way to go about this:
Structure AUDINPUTARRAY
bytes(5000) As Byte
End Structure
I'm trying to change that bytes line to: Dim bytes(5000) as Byte
but it's not letting me define the size in a structure.
Here's the second one:
Private i As Integer, j As Integer, msg As String * 200, hWaveIn As integer
I haven't a clue on how to convert: msg As String * 200
you cannot declare an initial size in VB.Net , you can set its size later using Redim statement in constructor or wherever needed
Structure AUDINPUTARRAY
Public bytes() As Byte
Public Sub New(ByVal size As Integer)
ReDim bytes(size) ' set size=5000
End Sub
End Structure
In Visual Basic .NET, you cannot declare a string to have a fixed length unless you use the VBFixedStringAttribute Class attribute in the declaration. The code in the preceding example causes an error.
You declare a string without a length. When your code assigns a value to the string, the length of the value determines the length of the string
see http://msdn.microsoft.com/en-us/library/f47b0zy4%28v=vs.71%29.aspx
. so your declarration will become
Private i As Integer, j As Integer, hWaveIn As Integer
<VBFixedString(200)> Private msg As String
You can do this via attributes
Public Structure <StructLayout(LayoutKind.Sequential)> AUDINPUTARRAY
Public <MarshalAs(UnmanagedType.ByValArray, SizeConst := 5000)>
Bytes() As Byte
End Structure
I would suggest that, while refactoring your code from VB6 to .net, that you take another look at whether you even want to emulate the fixed-length msg As String * 200. If you were counting on the fixed-length string so that you could chop characters off of the end, and still have a 200-character record, that's messy code that depends on a function's side effects.
When we converted from VB6 (a still-ongoing process), it made the intent of the code clearer if we explicitly set the string to a 200-byte block of spaces. Perhaps by declaring:
String msg = String(' ', 200)
(if that's valid in VB.net as well as C#).

VB.NET - Winsock GetData Method

I imported the Winsock feature in my vb.net application, so I can make a Chat System. I just have one little problem with my program. In the GetData method of my program,
CLIENT SIDE:
*Dim strData As String*
AxWinsock1.GetData(strData, vbString)
TextBox1.Text = TextBox1.Text & _
strData & vbCrLf
It will underline the whole first line, unless have an maxLen as Object in. So I plugged in Nothing, since I thought it was optional. Now when I debug, and I send a message from the server, it won't display anything. I put in vbByte as the maxLen object, and now it only shows part of the message. Can anyone tell me how to fix this. This works in VB6...
PS: I am not going to use the System.Namespaces function of VB.NET since, I find the Winsock feature much easier.
Thanks
vbByte is a constant with a value of 17, so you actually send a max length of 17 ;-)
You will want to send a bigger number as the max length. If what you want to send as a max length is the upper bound of the Byte data type you could send Byte.MaxValue (which is 255).
Edit:
I don't know what is the upper bound, but you can try Integer.MaxValue, or some arbitrary big value like 1000000...
Looking at the documentation, I noticed two things:
maxLen should be optional, I don't know why it would flag an error when you don't specify it, what kind of error is it?
It's mentioned that it's common to use GetData with a DataArrival event, is that your case? If it is, you could pass the totalBytes argument as the maxLen.