Fail at sending byte array through serial port excel-vba - vba

I am trying to get information from an Excel worksheet and send it through a serial port as a byte array, using Windows API. This is just a small part of it:
lngSize = UBound(byteData) - LBound(byteData)
WriteFile(udtPorts(intPortID).lngHandle, byteData, lngSize, _lngWrSize, udtCommOverlap)
My current problem: when I am sending a byte array of length 1 (just one byte), I receive it correctly (I am using a hyperterminal to check what I'm sending), but when I send an array of length > 1, here comes the problem; instead of receiving it like this:
letter = 65
For i = 0 To 5
dataToSend(i) = letter
letter = letter + 1
Next
what I should receive
what I get is this:
what I receive
I really cannot figure out what could be the problem and I would be grateful if someone had a clue. Thank you!

First, the correct number of elements in an array is:
lngSize = UBound(byteData) - LBound(byteData) + 1 ' <-- add 1
More importantly, your code is not applying the call convention for the WriteFile API. Namely, the second parameter should be a LPCVOID pointer to the first Byte to transfer. Passing the array's name byteData to the function wont achieve that, because the array is a complex COM data structure, not like a C array. What you should do is:
First get the address of the array's data structure, using VarPtrArray:
Then add 12 to it to get the address of the first byte.
.
Private Declare Function VarPtrArray Lib "VBE7" Alias "VarPtr" (var () As Any) As Long
...
WriteFile(udtPorts(intPortID).lngHandle, VarPtrArray(byteData()) + 12, lngSize, _lngWrSize, udtCommOverlap)
' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For information about handling arrays' data and their pointers, excellent examples can be found [on this page].(https://www.codeproject.com/Articles/729235/VB-and-VBA-Array-Buffering)
Also make sure that you declared you array as a Byte array, like
Redim byteData(someSize) As Byte
' ^^^^^^^
There might be other errors in the parts of code you didn't show (possibly the settings of udtCommOverlap), but hopefully these corrections will put you on the right track.

Related

Is there a method for arudino to store values into different variables as soon as they come over a serial connection?

I have built an android app that will send a string of values (using getbyte()_) across a serial connection. I would like each of these values to be stored in a seperate variable/
For example:
a list of numbers like this:
10004056700003
are sent across the connection.
there are a bunch of variables on the arduino side:
A,B,C,D.... etc
i would like to be able to do this:
A = 1
B = 0
C = 0
D = 0
E = 4
F= 0
.... and so on. i will then use these variables to run a certain sequence of functions on the arduino. In this sense the android application is just to control the arduino.
Thanks for the help! :D
Serial communication usually happens byte-wise.
So if you want to transfer a sequence of numbers (>255) the easiest way is to send each digit as a byte.
On the receiving end you basically have two options.
a) you read each byte and do something with it befor reading the next byte.
b) you read the bytes into a buffer array and do something with it later.
If you want to minimize the number of bytes transferred you of course can split the number value into several bytes instead of transferring each digit.
Try sending the data as String, and then you can access each character of the String using the method: StringVariableName.charAt(pos);
With this approach, your code will be more readable.
Check out charAt function here.

sprintf hex number deleted

I am trying to get and send my MCU's IP Adress, SubnetMask and Gateway adress.
I got them but problem is merging them. I want to merge them with array and send for one step..
For example:
my values are
e2promIpAddress = 0A020705 // represents 10.2.7.5
e2promSubnetMask = FFFF0000 // represents 255.255.0.0
e2promGateway = 0A02070F // represents 10.2.7.15
When I add with sprintf()
char buffer[64];
sprintf(buffer,"%x%x%x",e2promIpAddress,e2promSubnetMask,e2promGateway);
Output is A020705FFFF00000A02070F
Unfortunatelly array must start with 0 but it goes away..
Thanks in advance
I finally find my answer and want to post here..
My values for example e2promIpAddress = 0A020705 is 4 bytes.
When I wrote this with;
sprintf(buffer,"%02x%02x%02x",e2promIpAddress,e2promSubnetMask,e2promGateway);
it did not pad "0"
when I wrote this with;
sprintf(buffer,"%08x%08x%08x",e2promIpAddress,e2promSubnetMask,e2promGateway);
all values which starts with "0" pad with "0"
Have a good day..

Convert audio doubles to bytes

I am dealing with raw PCM audio data (the audio data of a PCM file without the header).
This data is provided to me in the form of a vector of double.
I would like to pass this data to another function, and this function expects the audio data in the form of a byte vector.
I tried
Dim nBytes() As Byte = nDoubles.SelectMany(Function(d) BitConverter.GetBytes(d)).ToArray()
but that wouldn't give the expected results.
I guess I have to deal with the conversion manually, but I am unsure how this should be done.
Can anybody help?
Thank you.
Since the required format for the other function is 16-bit, 48 kHz, which is the same as your source data, it's a simple case of converting the source to an array of Short, then serializing this as a Byte array.
The problem with the code you suggest for this is that the first step is missed, so it basically serializes the Double array. However, you can re-use this for the second step. So, you can do something like:
Dim nShorts() As Short = New Short(nDoubles.Length - 1) {}
For i = 0 To nDoubles.Length - 1
nShorts(i) = Convert.ToInt16(nDoubles(i))
Next
Dim nBytes() As Byte = nShorts.SelectMany(Function(s) BitConverter.GetBytes(s)).ToArray()

How do I limit BitConverter.GetBytes() to return only a certain amount of bytes using VB.NET?

I do:
Dim BytArr() as Byte = BitConverter.GetBytes(1234)
Since, by default, they are 32 bits, it returns 4 byte elements.
I want to be able to control it to return only like two bytes. Maybe only three bytes. Are there any built-in functions to control it?
I don't want to rely on using shifting >> 8 >> 16 >> 24 >> 32, etc..
I also don't want to rely on type casting the data in GetBytes() to a specific datatype.
It is not that GetBytes defaults to 32 bits, it is that GetBytes returns an array of the size required to hold the data type. If you pass a Long then you will get a 8 elements in your array.
The best way to control this is indeed casting the data you pass in. Otherwise you could truncate some of the number.
That being said, you could do something like this:
Dim BytArr() as Byte = Array.Resize(BitConverter.GetBytes(1234), 2)
But if the value you passed in exceeded what could be stored in 2 bytes (in this case) then you will have some very broken code.

Converting a number larger than 255 into a byte variable

I understand the concept of bytes and declaring variables to save on processing space. I understand that the max value that can be stored in a byte is 255.
I cannot seem to wrap my head around my current issue and was hoping that someone would be able to educate me and help me solve this problem. I don't have much experience working with byte manipulation.
I was given a project to update and was told that the service that is passing data to my project would start using 2bytes to transfer the ID rather than the 1 byte previously as their parameters have grown.
The current declaration for the variable is:
Dim bytvariable As Byte = 0
What is the new declaration to accept a 2 byte value?
Secondly, how would I be able to convert that 2 byte value into an integer number?
Example, they are passing me this value: 0x138 and it is supposed to come out as 312.
Thank you in advance.
Here's a summary of the "primitive" datatypes in .NET, and their sizes.
Yes, an Int16 is probably what you want.
Often you'd be reading the binary data from a stream, or getting it from an array of bytes.
To convert from those sources into an Int16, you can do this:
in C#:
byte[] block = new byte[128];
mystream.Read(block, 0, block.Length);
int i = 0;
Int16 value = (Int16)(block[i++] + block[i++] * 256);
In VB.NET, it would be:
Dim block as New Byte(128)
stream.Read(block, 0, block.Length)
Dim i as Int16 = 0
Dim value As Short = CShort((block(i) + (buffer(i+1) * &H100)))
i = i + 2
(I think)
from the top of my head I'd suggest if you insist on doing it that way (instead of just passing an integer), you could use an array of byte, first index holding the first number and the second index the second ex. byte[0] = 123, byte[1] = 255;
then combine them into a string ex. string concatenatedNumber = byte[0].ToString() + byte[1].ToString(); then parse it ex. int ID = Int32.Parse(concatenatedNumber);
Examples are in C#, but I think you should get the idea. I would definitely rather just pass it as an integer though.
You could try this:
Dim bytvariable As Byte(0 To 1)
bytvariable(0) = ' Get the first byte however they are sending it
bytvariable(1) = ' Get the second byte however they are sending it
Dim value As Int16 = BitConverter.ToInt16(buffer, 0);