Trying to send data through HId interface, but error happend - c#

I am using visual studio 2019 with C# .Netframework 4.7.2, I am trying to use jcoenraadts's HID project on github.
https://github.com/jcoenraadts/hid-sharp
I tried to send data through Hid, but error occur in the write function.
this is what I want to send
HIDInterface device = new HIDInterface(devicePath,false);
byte[] inputdata = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 };
device.write(inputdata);
and this is the write function
public void write(byte[] data)
{
if (data.Length > capabilities.OutputReportByteLength)
throw new Exception("Output report must not exceed " + (capabilities.OutputReportByteLength - 1).ToString() + " bytes");
//uint numBytesWritten = 0;
byte[] packet = new byte[capabilities.OutputReportByteLength];
Array.Copy(data, 0, packet, 1, data.Length); //start at 1, as the first byte must be zero for HID report
packet[0] = 0;
if (FS_write.CanWrite)
FS_write.Write(packet, 0, packet.Length);
else
throw new Exception("Filestream unable to write");
}
the error happend at FS_write.Write(packet,0,packet.Length);
the translate is IO operation can't complete the task,due to the data length is too long or the control code that supports synchronous IO operations has not been turned on.

Related

How to use Bulk transfer in USB communication C#

I have little bit problem with USB communication. I can connect to USB device but I cannot write any data to USB device.
This is my code to write data to USB device:
public byte[] GetUID = { 0xFF, 0xCA, 0x00, 0x00, 0x00 };
public byte[] SCardConnect = { 0x68, 0x92, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00 };
public bool WriteBulk(byte[] str)
{
//ErrorCode ec = ErrorCode.None;
if (IsConnected == false)
return false;
else Console.WriteLine("connected");
/*endpointWriter = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02, EndpointType.Bulk);
int bytesWritten = length;
ec = endpointWriter.Write(protocol, 5000, out bytesWritten);
if (ec != ErrorCode.None) return false;
else return true;*/
UsbSetupPacket packet = new UsbSetupPacket((byte)UsbRequestType.TypeVendor, 0x04, 0, 0, (short)str.Length);
int lengthTransfered;
return MyUsbDevice.ControlTransfer(ref packet, str, str.Length, out lengthTransfered);
}
public bool checkUID()
{
return WriteBulk(GetUID);
}
public bool checkSCardConnect()
{
return WriteBulk(SCardConnect);
}
When I use checkUID() or checkSCardConnect(), it always returns false. Is there any other procedure to write using USB Communication?

C# Changing parts of byte array based on user input

I am sending an API frame using the following code:
byte[] bytesToSend5 = new byte[]
{
0x7E, 0x00, 0x10, 0x01, 0x00, 0x13,
0xA2, 0x00, 0x40, 0xA6, 0x5E, 0x23,
0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04, 0x4D
};
serialPort1.Write(bytesToSend5, 0, bytesToSend5.Length);
It's split up like this:
byte[] bytesToSend5 = new byte[]
{
5Startbits(won't change),
8IDbits(changes when a part of the device is swapped),
6determinationbits(tells the device what to do),
1checksumbit(calculated based on previous bits)
};
The first code example works as is desired with the current product. If, for whatever reason, a part of the device needs to be changed, it will not work because the ID bits won't fit. The ID number is printed on the device, 16 digits with numbers and letters, such as "0013A20043A25E86".
What I want to do is make a textbox where the user can input the new ID number and it will be replaced with the appropriate bits in the aforementioned byte array.
Here is my attempt using the Array.Copy function, trying to display the result in a textbox - but no change is detected. I've tried typing "1" "1,2,3" etc as well as the actual ID's "0013A20043A25E86":
string xbee_serienr = prop1_serienr.Text;
byte[] front = { 0x7E, 0x00, 0x10, 0x17, 0x01 };
byte[] back = { 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04 };
string[] xbee = { xbee_serienr };
byte[] combined = new byte[front.Length + xbee.Length + back.Length];
Array.Copy(front, combined, front.Length);
Array.Copy(back, 0, combined, 5, back.Length);
var result = string.Join(",", combined.Select(x => x.ToString()).ToArray());
OutputWindow.Text = result;
It would have to be possible to change the 8ID bits based on user input, and calculate the last checksum bit based on the rest of the bits.
I have searched the internet and tried Array.copy, Concat etc. but I haven't made any progress with it. Any guidance or input on this would be highly appreciated, even if it means guiding me in a direction of taking a different approach.
EDIT:
I now have the desired information in the byte array "result" using roughly the same example as below (taking user input for the var "xbee_serienr"). I now want to pass this to a method that looks like this:
private void button_D07_Lav_Click(object sender, EventArgs e)
{
byte[] bytesToSend5 = new byte[] { 0x7E, 0x00, 0x10, 0x01, 0x00, 0x13, 0xA2, 0x00, 0x40, 0xA6, 0x5E, 0x23, 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04, 0x4D };
serialPort1.Write(bytesToSend5, 0, bytesToSend5.Length);
And make the "bytesToSend5" use the array "result" from the other method.
I've tried using this example, like so:
byte result { get; set; } //above and outside of the two methods
var result = string.Join(string.Empty, combined.Select(x => x.ToString("X2")).ToArray()); //this is the end of the first method
private void button_D07_Lav_Click(object sender, EventArgs e)
{
byte[] bytesToSend5 = new byte[] { 0x7E, 0x00, 0x10, 0x01, 0x00, 0x13, 0xA2, 0x00, 0x40, 0xA6, 0x5E, 0x23, 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04, 0x4D };
bytesToSend5 = result; //using the array stored in result instead of the one currently in bytesToSend5.
serialPort1.Write(bytesToSend5, 0, bytesToSend5.Length);
}
I realize the obvious problem here, that it's not on the same form. This is why I wanted to split the array and add 0x in front of every item in the array, and separate them with commas.
I'm also going to use this for several different devices once I figure it out properly, which makes me fear there will be a lot of duplicated code, but I suspect once I'm understanding how to pass and use the array in a different method, I can always "duplicate" the code for every device, since the ID will indeed need to be different for the different devices.
Well, you never add the parsed string.
var xbee_serienr = "0013A20043A25E86";
byte[] front = { 0x7E, 0x00, 0x10, 0x17, 0x01 };
byte[] back = { 0xFF, 0xFE, 0x02, 0x44, 0x37, 0x04 };
var xbee = new byte[xbee_serienr.Length / 2];
for (var i = 0; i < xbee.Length; i++)
{
xbee[i] = byte.Parse(xbee_serienr.Substring(i * 2, 2), NumberStyles.HexNumber);
}
byte[] combined;
using (var ms = new MemoryStream(front.Length + xbee.Length + back.Length))
{
ms.Write(front, 0, front.Length);
ms.Write(xbee, 0, xbee.Length);
ms.Write(back, 0, back.Length);
combined = ms.ToArray();
}
var result = string.Join(string.Empty, combined.Select(x => x.ToString("X2")).ToArray());
Since you're adding multiple arrays one after another, I just used a MemoryStream. If you already have the byte[] ready (and mutable), you can write directly to that byte array and avoid allocating (and collecting) the extra array, but it doesn't make much of a difference when the limiting factor is the UI anyway.

C# Serial Port reading HEX data

I am writing a C# application to read from several serial COM ports at the same time to analyze the data communication of an IPOD. The data being sent needs to be interpreted as HEX bytes. For example,
0xFF 0x55 0x01 0x00 0x04 0xC3 0xFF 0x55 ...
I want to be able to read this and display it in a rich textbox, for example
0xFF 0x55 0x01 0x00 0x04 0xC3
0xFF 0x55 ...
The start of a command includes a header (0xFF 0x55) and the rest is is the command + parameters + checksum.
What is the best way to go about this?
I currently have:
private delegate void SetTextDeleg(string text);
void sp_DataReceivedRx(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
try
{
string data = IPODRxPort.ReadExisting(); // Is this appropriate??
// Invokes the delegate on the UI thread, and sends the data that was received to the invoked method.
// ---- The "si_DataReceived" method will be executed on the UI thread which allows populating of the textbox.
this.BeginInvoke(new SetTextDeleg(si_DataReceivedRx), new object[] { data });
}
catch
{ }
}
private void si_DataReceivedRx(string data)
{
int dataLength = data.Length*2;
double numLines = dataLength / 16.0;
for (int i = 0; i < numLines; ++i)
IPODTx_rtxtBox.Text += "\n";
IPODRx_rtxtBox.Text += SpliceText(convertAsciiTextToHex(data), 32) + "\n";
}
I can read data, but it is not in the appropriate format.
Im just not sure what the best way to get the hex data from the com port and display it line by line by command based on the command header (0xFF 0x55).
Any Suggestions?
Alex Farber's method works. Below is my code example:
SerialPort sp = (SerialPort) sender;
// string s = sp.ReadExisting();
// labelSerialMessage.Invoke(this.showSerialPortDelegate, new object[] { s });
int length = sp.BytesToRead;
byte[] buf = new byte[length];
sp.Read(buf, 0, length);
System.Diagnostics.Debug.WriteLine("Received Data:" + buf);
labelSerialMessage.Invoke(this.showSerialPortDelegate, new object[] {
System.Text.Encoding.Default.GetString(buf, 0, buf.Length) });

Serial Commands - NEC Projector

I'm working on a C# application that writes serial commands to an NEC projector. I can send the commands fine using RealTerm using the "Send Numbers" function but cannot seem to get it to work through my app.
The format of the commands are
POWER ON - 02H 00H 00H 00H 00H 02H
POWER OFF - 02H 01H 00H 00H 00H 03H
I've tried sending using WriteLine(command) - as a string as well as converting it to a byte array with the following code:
public static byte[] ToByteArray(string StringToConvert)
{
char[] CharArray = StringToConvert.ToCharArray();
byte[] ByteArray = new byte[CharArray.Length];
for (int i = 0; i < CharArray.Length; i++)
{
ByteArray[i] = Convert.ToByte(CharArray[i]);
}
return ByteArray;
}
Nothing seems to work, what shall I be sending down the port from my C# end? Hopefully someone can help soon :)
There is very little point in trying to convert these commands from a string. They are not strings. So just write them in your code in their native format:
private byte[] powerOnCmd = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x02 };
private byte[] powerOffCmd = new byte[] { 0x02, 0x01, 0x00, 0x00, 0x03 };
Now it is simple:
private void sendCommand(byte[] cmd) {
serialPort1.Write(cmd, 0, cmd.Length);
}
private void PowerOn() {
sendCommand(powerOnCmd);
}
You can use the Write method, it takes a string as argument :
SerialPort.Write

How to search for bytes in Queue<byte> and extract packet?

I'm receiving packets over COM port. Each packet begins with {0xFF, 0xFF} and ends with {0xFE, OxFE}. All received bytes are queued in Queue<byte> and after each void port_DataReceived(object sender, SerialDataReceivedEventArgs e) I'm processing that queue.
If any 0xFF or 0xFE shows up in packet, device add 0x00 after it.
How to extract each packet?
How to delete unnecessary 0x00 inside each packet that have header byte inside?
For the first issue I have:
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[port.BytesToRead];
try
{
port.Read(data, 0, data.Length);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
data.ToList().ForEach(newByte => receivedData.Enqueue(newByte));
processData();
}
private void processData()
{
// Determine if we have a "packet" in the queue
if (Enumerable.SequenceEqual(receivedData.Take(2), new List<byte> { 0xFF, 0xFF }))
{
// Beginning of new packet in the front of queue is ready!
if (Enumerable.SequenceEqual(receivedData.Skip(Math.Max(0, receivedData.Count() - 2)).Take(2), new List<byte> { 0xFE, 0xFE }))
{
List<byte> tempPacket = new List<byte>();
// Whole packet in the queue
while(receivedData.Count > 0)
tempPacket.Add(receivedData.Dequeue());
tempPacket.TrimExcess();
Packet pack = new Packet(tempPacket, PacketOrigin.Serial);
}
}
}
I'm trying to remove all 0x00 that are after any 0xFE and 0xFF that can be found inside Queue<byte> so far I came up with:
List<byte> unconvertedPacket = new List<byte> { 0xFF, OxFF, 0x00, 0x00,0x4D, 0xFA 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE}
int index = 0;
while (index != null)
{
unconvertedPacket.RemoveAt(index + 1);
index = unconvertedPacket.IndexOf(0xFE);
}
while (index != null)
{
unconvertedPacket.RemoveAt(index + 1);
index = unconvertedPacket.IndexOf(0xFF);
}
Does anyone have maybe any other solution/advice for doing it?
Try the following approach:
In the DataReceived event handler keep reading the incoming data and append it to a buffer (byte[]).
First you need to find the start marker ({0xFF, 0xFF}) in the buffer of received data. You need to determine the index of this marker within the buffer.
Once you have the start index, you need to keep appending incoming data to the buffer and check if the end marker (0xFE, 0xFE) has arrived. Capture the index of the end marker within the buffer.
Once you have the start and end index you can extract the packet between them. Nevermind about the extra 0x00 byte that gets added after it. You know the index of the start and end marker and their length (2). Just extract the array of bytes between them.
You need to create a search algorithm to suit this purpose. Both the needle and the haystack are an array of bytes (byte[]). You can use the Boyer-Moore string search algorithm for this purpose.
Here's a simple C# implementation of the Boyer-Moore algorithm which only implements the bad character rule. Read up on Wikipedia if you also want to implement the good suffix rule.
The algorithm is normally intended for strings, but I modified it to work with byte arrays. Tested this locally with an IP camera to extract the received JPEG images.
Check out the Wikipedia article for more information about it. It contains a full Java implementation which you can easily translate to C#.
public class BoyerMoore
{
public static int IndexOf(byte[] needle, byte[] haystack)
{
if (needle == null || needle.Length == 0)
return -1;
int[] charTable = CreateCharTable(needle);
for (int i = needle.Length - 1, j; i < haystack.Length;)
{
for (j = needle.Length - 1; needle[j] == haystack[i]; i--, j--)
{
if (j == 0)
return i;
}
i += charTable[haystack[i]];
}
return -1;
}
private static int[] CreateCharTable(byte[] needle)
{
const int ALPHABET_SIZE = 256;
var table = new int[ALPHABET_SIZE];
for (int i = 0; i < table.Length; i++)
{
table[i] = needle.Length;
}
for (int i = 0; i < needle.Length - 1; i++)
{
table[needle[i]] = needle.Length - 1 - i;
}
return table;
}
}
Example usage:
var haystack = new byte[]
{0xFF, 0xFF, 0x00, 0x00, 0x4D, 0xFA, 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE};
var startIndexOf = BoyerMoore.IndexOf(new byte[] {0xFF, 0xFF}, haystack);
var endIndexOf = BoyerMoore.IndexOf(new byte[] {0xFE, 0xFE}, haystack);
var packet = new byte[endIndexOf - 2 - startIndexOf];
for (int i = startIndexOf + 2, j = 0; i < endIndexOf - startIndexOf; i++, j++)
{
packet[j] = haystack[i];
}
Voila, the packet byte array contains 9 bytes in this example and only contains the bytes between the start and end marker. You can now trigger an event and pass the packet as an event arg for example.
Remark: Receiving the data from the COM port is a continuous event. You need to keep monitoring it. Keep appending the received data and keep checking for the start -and index markers, extract the packages...etc. Watch out that your buffer does not overflow. You need to implement some housekeeping there.
Hope it helps. Check out AForge implementation of an MJPEGStream for an example of continuously reading incoming data.
To recapitulate:
Declare an instance variable to store the received data (e.g. _buffer = new byte[4096]).
Append the incoming data to the buffer in the DataReceived event handler.
Search for the start marker. If found remember the start index in an instance variable.
If you already know the position of the start marker, then search for the index of the end marker.
When you find the end marker, extract the packet and fire an event. Use the packet as part of the event's EventArgs.
Wash, rinse, repeat.
You need to implement some housekeeping to make sure the buffer won't overflow (> 4096 bytes). For instance once you find a packet you can clean up the buffer up until the last received end marker.

Categories

Resources