Strange behavior form C# serial port - c#

I'm getting strange behavior from simple program, which I'm using to learn how to use the serial port. The form have just one serial port control and one TextBox. Because it's just a test program I have disabled the thread call check.
I forgot to mention,that I'm using micro-controller to send 1000 bytes of data (read EEPROM).
The strange thing is that, when I read the data and just append it directly to the text box in the DataReceived event, everything is fine, but when I first pass the values to int[] array,and then use a loop to convert them to strings in HEX format and append them to the TextBox, there are some zeros, between the values.
Some code with results.
Case 1: read data and directly append to TextBox
private void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (sp1.BytesToRead > 0)
{
textBox1.AppendText(sp1.ReadByte().ToString("X")+ " ");
}
}
And the result is (well,part of it,as i said there are 1000 bytes to receive...)
0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C..... and so on
Case 2: first store the values to int array,and than convert them to string, and append to TextBox
private void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int[] buffer = new int[1000];
int i = 0;
while (sp1.BytesToRead > 0)
{
//textBox1.AppendText(sp1.ReadByte().ToString("X")+ " ");
buffer[i] = sp1.ReadByte();
i++;
}
int j = 0;
while (j < 1000)
{
textBox1.AppendText(buffer[j].ToString("X"));
j++;
}
I get a lot of 0's at random places, and it reads 4-5 times more data, than the 1000 in the loop
0123456789ABCDEF101112131415161718191A1B1C1D1E1F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF0123456789ABCDEF101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF0123456789ABCDEF101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF0123456789ABCDEF101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
What might be the reason for this strange behavior?
Thanks in advance

sp1_DataReceived is typically not called only once. Typically your computer handles received data faster than received. This means at some point the loop
while (sp1.BytesToRead > 0)
is left before all 1000 bytes are received. Just a short time later sp1_DataReceived is already called again because more of the 1000 bytes are now available. Since your first implementation only appends the bytes it doesen't matter. But your second implementation differs because you are always appending 1000 characters to your text. This could lead to a result of a multiple of 1000 characters with zeros appended.
To fix your problem you need to combine the bytes of multiple events. One solution could be to use a list like
private List<byte> buffer = new List<byte>();
private void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (sp1.BytesToRead > 0)
{
buffer.Add(sp1.ReadByte());
}
//Print if all bytes are available
if (buffer.Count >= 1000)
{
//Join the bytes to a string using LINQ
textBox1.Text = String.Join("", buffer.Select(b => b.ToString("X")));
buffer.Clear();
}
}
or an array like
private byte[] buffer = new byte[1000];
private int bufferIndex = 0;
private void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (sp1.BytesToRead > 0 && bufferIndex < 1000)
{
buffer[bufferIndex ] = sp1.ReadByte();
bufferIndex ++;
}
//Print if all bytes are available
if (bufferIndex >= 1000)
{
//Join the bytes to a string using LINQ
textBox1.Text = String.Join("", buffer.Select(b => b.ToString("X")));
bufferIndex = 0;
}
}
Note that this are only some ideas and example implementations. Since I do not know if you are also receiving other messages at the port it is not possible to give a perfect suitable solution to solve your problem.

Related

Why does this C# TcpClient code not always see a response?

I am using the following code to read a psuedo-HTTP request response. It works sometimes but not always and I do not understand.
Background: I have a device that takes HTTP GET requests and sends a chunked HTTP response. In one case, the response is not a proper chunked HTTP response. It leaves out the null chunk that indicates the end of data. I have fixed that problem in the device, but I am trying to figure out how to read the non-comforming HTTP response. I found code from Create http request using TcpClient that sometimes works and sometimes doesn't and I do not understand why.
If I use the code unaltered, it works fine. If I use it by replacing the "www.bing.com" with my device's IP, "192.1.168.89" in both places the string appears, for example, and change the GET command line to "GET /index.htm HTTP/1.1", it works fine. This version of the command returns a web page that is constructed by the device and sends several TCP buffers (about 1400 bytes in my device) of chunked data.
However, if I change to another command that my device understands, "GET /request.htm?T HTTP/1.1", but returns less than 500 bytes of chunked data, then I never see the response. In fact it never gets past the call to "CopyToAsync(memory)" and I do not understand why. The device sees the request, parses it and sends a proper HTTP response. (I know it is a proper response because I have code that uses HTTPClient to read the response and it sees the response fine. And I see the response data from the device side is exactly the same going out in both cases. I can see the device data because I am writing the device's firmware and can change it to printf() the data being sent out to the TCP routines.)
Anyone have an explanation for why the code below isn't always seeing a response?
private static async Task<string> HttpRequestAsync() {
string result = string.Empty;
using (var tcp = new TcpClient("www.bing.com", 80))
using (var stream = tcp.GetStream())
{
tcp.SendTimeout = 500;
tcp.ReceiveTimeout = 1000;
// Send request headers
var builder = new StringBuilder();
builder.AppendLine("GET /?scope=images&nr=1 HTTP/1.1");
builder.AppendLine("Host: www.bing.com");
//builder.AppendLine("Content-Length: " + data.Length); // only for POST request
builder.AppendLine("Connection: close");
builder.AppendLine();
var header = Encoding.ASCII.GetBytes(builder.ToString());
await stream.WriteAsync(header, 0, header.Length);
// Send payload data if you are POST request
//await stream.WriteAsync(data, 0, data.Length);
// receive data
using (var memory = new MemoryStream())
{
await stream.CopyToAsync(memory);
memory.Position = 0;
var data = memory.ToArray();
var index = BinaryMatch(data, Encoding.ASCII.GetBytes("\r\n\r\n")) + 4;
var headers = Encoding.ASCII.GetString(data, 0, index);
memory.Position = index;
if (headers.IndexOf("Content-Encoding: gzip") > 0)
{
using (GZipStream decompressionStream = new GZipStream(memory, CompressionMode.Decompress))
using (var decompressedMemory = new MemoryStream())
{
decompressionStream.CopyTo(decompressedMemory);
decompressedMemory.Position = 0;
result = Encoding.UTF8.GetString(decompressedMemory.ToArray());
}
}
else
{
result = Encoding.UTF8.GetString(data, index, data.Length - index);
//result = Encoding.GetEncoding("gbk").GetString(data, index, data.Length - index);
}
}
//Debug.WriteLine(result);
return result;
}
}
private static int BinaryMatch(byte[] input, byte[] pattern)
{
int sLen = input.Length - pattern.Length + 1;
for (int i = 0; i < sLen; ++i)
{
bool match = true;
for (int j = 0; j < pattern.Length; ++j)
{
if (input[i + j] != pattern[j])
{
match = false;
break;
}
}
if (match)
{
return i;
}
}
return -1;
}
=====================
Let me edit the function above to show what it is now and maybe clarify things.
static async Task<byte[]> getTcpClientHttpDataRequestAsync(string ipAddress, string request)
{
string result = string.Empty;
List<byte> arrayList = new List<byte>();
using (var tcp = new TcpClient("192.168.1.89", 80))
using (var stream = tcp.GetStream())
using (var memory = new MemoryStream())
{
tcp.SendTimeout = 500;
tcp.ReceiveTimeout = 10000;
tcp.NoDelay = true;
// Send request headers
var builder = new StringBuilder();
builder.AppendLine("GET /request.htm?x01011920000000000001 HTTP/1.1");
builder.AppendLine("Host: 192.168.1.89");
builder.AppendLine("Connection: Close");
builder.AppendLine();
var header = Encoding.ASCII.GetBytes(builder.ToString());
Console.WriteLine("======");
Console.WriteLine(builder.ToString());
Console.WriteLine("======");
await stream.WriteAsync(header, 0, header.Length);
do { } while (stream.DataAvailable == 0);
Console.WriteLine("Data available");
bool done = false;
do
{
int next = stream.ReadByte();
if (next < 0)
{
done = true;
}
else
{
arrayList.Add(Convert.ToByte(next));
}
} while (stream.DataAvailable && !done);
byte[] data = arrayList.ToArray();
return data;
}
}
The GET command is what my device is responding to. If the command starts with 'x' as shown then it responds with a proper HTTP response and the function above reads the data. If it starts with 'd' it is missing the 0 length chunk at the end and the function above never sees any data from the device.
With Wireshark, I am seeing the following responses for the 'x' and 'd' commands.
The 'x' command returns 2 TCP frames with the following data:
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 9c 00 47 00 00 64 06 d2 49 c0 a8 01 59 c0 a8 ...G..d..I...Y..
0020 01 22 00 50 05 5d fc f5 9e 72 ad 75 e3 2c 50 18 .".P.]...r.u.,P.
0030 00 01 a9 cd 00 00 48 54 54 50 2f 31 2e 31 20 32 ......HTTP/1.1 2
0040 30 30 20 4f 4b 0d 0a 43 6f 6e 6e 65 63 74 69 6f 00 OK..Connectio
0050 6e 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e n: close..Conten
0060 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d t-Type: text/htm
0070 6c 0d 0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c l..Cache-Control
0080 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 54 72 61 6e : no-cache..Tran
0090 73 66 65 72 2d 45 6e 63 6f 64 69 6e 67 3a 20 63 sfer-Encoding: c
00a0 68 75 6e 6b 65 64 0d 0a 0d 0a hunked....
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 45 00 48 00 00 64 06 d2 9f c0 a8 01 59 c0 a8 .E.H..d......Y..
0020 01 22 00 50 05 5d fc f5 9e e6 ad 75 e3 2c 50 18 .".P.].....u.,P.
0030 00 01 fc 20 00 00 30 30 31 0d 0a 2b 0d 0a 30 30 ... ..001..+..00
0040 37 0d 0a 01 85 86 00 00 0d 0a 0d 0a 30 30 30 0d 7...........000.
0050 0a 0d 0a ...
By comparison the 'd' command returns data in 2 TCP frames as:
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 9c 00 4e 00 00 64 06 d2 42 c0 a8 01 59 c0 a8 ...N..d..B...Y..
0020 01 22 00 50 05 5e d3 c3 f9 f5 69 cc 6d a3 50 18 .".P.^....i.m.P.
0030 00 01 30 ae 00 00 48 54 54 50 2f 31 2e 31 20 32 ..0...HTTP/1.1 2
0040 30 30 20 4f 4b 0d 0a 43 6f 6e 6e 65 63 74 69 6f 00 OK..Connectio
0050 6e 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e n: close..Conten
0060 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d t-Type: text/htm
0070 6c 0d 0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c l..Cache-Control
0080 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 54 72 61 6e : no-cache..Tran
0090 73 66 65 72 2d 45 6e 63 6f 64 69 6e 67 3a 20 63 sfer-Encoding: c
00a0 68 75 6e 6b 65 64 0d 0a 0d 0a hunked....
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 36 00 4f 00 00 64 06 d2 a7 c0 a8 01 59 c0 a8 .6.O..d......Y..
0020 01 22 00 50 05 5e d3 c3 fa 69 69 cc 6d a3 50 18 .".P.^...ii.m.P.
0030 00 01 64 c2 00 00 30 30 37 0d 0a 01 90 91 00 00 ..d...007.......
0040 0d 0a 0d 0a ....
The only discernible differences that I see is that in the second frame of the 'd' command it is missing a 1 byte chunk that is part of our protocol (and shouldn't have any effect on the TCP/HTTP function) and the last 7 bytes of data that the 'x' command provides, which is the 0 length chunk expected for HTTP.
Going back to the code in HttpRequestAsync(), if the 'd' command is sent then the code never sees stream.DataAvailable become true, even though the data has been sent. Why?
await stream.CopyToAsync()
will not complete until
stream.DataAvailable == false
You have indicated to the server, in the headers that you will close the TCP connection when done, but have not done so. The server will eventually close the connection when it thinks you're gone. The server is not obligated to obey your "Connection: close" request and that should be indicated in the headers the server returns.
Before you call stream.CopyToAsync() you should check the headers to determine if what Content-Length has been supplied and pass a buffer length to stream.CopyToAsync() and then call TcpClient.Close()

C# RegEx a value between numbers and characters?

Hello I want to search for the first occurrence of a specific string and capture a value between a set length of numbers and characters that change.
Using Nate Barbettini’s https://dotnetfiddle.net/vhkUV5 example I butchered it into doing what I almost need, it won’t compile and from what I’ve seen my RegEx is way off so I defiantly need help with it.
In my example I want to find the first occurrence of the PID value “116c” for chrome.exe and not all three PID values. What’s the best way to get one PID value?
Code:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var output = #"
0a80 6e 6f 74 65 70 61 64 2b 2b 2e 65 78 65 20 20 20 notepad++.exe
0a90 50 49 44 3d 31 64 38 63 7c 30 37 35 36 34 0d 0a PID=1d8c|07564..
0aa0 6a 68 69 5f 73 65 72 76 69 63 65 2e 65 78 20 20 jhi_service.ex
0ab0 50 49 44 3d 31 38 64 34 7c 30 36 33 35 36 0d 0a PID=18d4|06356..
0ac0 4c 4d 53 2e 65 78 65 20 20 20 20 20 20 20 20 20 LMS.exe
0ad0 50 49 44 3d 31 63 36 38 7c 30 37 32 37 32 0d 0a PID=1c68|07272..
0ae0 63 6d 64 2e 65 78 65 20 20 20 20 20 20 20 20 20 cmd.exe
0af0 50 49 44 3d 30 66 37 38 7c 30 33 39 36 30 0d 0a PID=0f78|03960..
0b00 63 6f 6e 68 6f 73 74 2e 65 78 65 20 20 20 20 20 conhost.exe
0b10 50 49 44 3d 30 62 64 30 7c 30 33 30 32 34 0d 0a PID=0bd0|03024..
0b20 76 63 74 69 70 2e 65 78 65 20 20 20 20 20 20 20 vctip.exe
0b30 50 49 44 3d 31 38 30 38 7c 30 36 31 35 32 0d 0a PID=1808|06152..
0b40 63 68 72 6f 6d 65 2e 65 78 65 20 20 20 20 20 20 chrome.exe
0b50 50 49 44 3d 31 31 36 63 7c 30 34 34 36 30 0d 0a PID=116c|04460..
0b60 63 68 72 6f 6d 65 2e 65 78 65 20 20 20 20 20 20 chrome.exe
0b70 50 49 44 3d 31 36 39 34 7c 30 35 37 38 30 0d 0a PID=1694|05780..
0b80 63 68 72 6f 6d 65 2e 65 78 65 20 20 20 20 20 20 chrome.exe
0b90 50 49 44 3d 31 30 62 30 7c 30 34 32 37 32 0d 0a PID=10b0|04272..";
var regex = new Regex(#"chrome.exe[\s].................................................................(.*)........");
var resultList = new List<string>();
foreach (Match match in regex.Matches(output))
{
resultList.Add(match.Groups[1].ToString());
}
var pid = string.Join(", ", resultList);
Console.WriteLine(pid);
}
}
Output:
116c, 1694, 10b0
I’m extremely new so any help or pointers are welcome.
Try this code:
var regex = new Regex("chrome\\.exe\\s*.*PID=(.*)\\|");
var pid = regex.Matches(output)
.Cast<Match>()
.Select(match => match.Groups[1].ToString())
.First();
You can test the regular expression here.

Passing pointer to a struct?

Hello I'm trying to pass data from a pointer to a struct but the values seem to be different.
struct somestruct
{
public file header;
public uint version;
}
unsafe struct file
{
public fixed char name[8];
public uint type;
public uint size;
}
Then in code somewhere..
public unsafe int ReadFile(string filepath)
{
somestruct f = new somestruct();
byte[] fdata = System.IO.ReadAllBytes( filepath );
fixed( byte* src = fdata )
{
f.header = *(file*)src;
MessageBox.Show( new string(f.header.name) ); //should be 'FILENAME' but it's like japanese.
}
return 0;
}
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 46 49 4C 45 4E 41 4D 45 00 00 00 01 00 00 00 30 FILENAME.......0
00000010 74 27 9F EF 74 77 F1 D7 C5 86 93 3D 39 0D 72 A9 t'Ÿïtwñ×ņ“=9.r©
00000020 63 8B 92 CF F6 7D 8A 14 45 9D 68 51 A4 8E A4 EE c‹’Ïö}Š.E.hQ¤Ž¤î
00000030 4E FE D0 66 45 0E C9 8D 96 BB F4 EE 52 1F 89 D3 NþÐfE.É.–»ôîR.‰Ó
00000040 5C 80 1A 71 8A 16 B1 8B 3A A8 1B A4 48 11 B8 E8 \€.qŠ.±‹:¨.¤H.¸è
Do you have any idea what's going on?
Each char is 2 bytes - a fixed buffer of 8 chars is 16 bytes. You are reading the first 8 bytes as only the first 4 characters in that buffer, and the high bytes will make it look. Like the eastern Unicode ranges.
I would say: deserialize it at the stream level. Don't do this.
Basically, read (at least) 20 bytes into a buffer, then decode manually, using:
string s = Encoding.ASCII.GetString(buffer, 0, 8);
For the string, and probably shift operations for the unsigned integers.
You could also use unsafe code to read the integers from the buffer, via the other meaning of fixed and a pointer-cast.
A char is UTF-16 and is 2 bytes. You need to convert the UTF-8/ANSI (1 byte) string to a UTF-16 string.

Encoding/Decoding hex packet

I want to send this hex packet:
00 38 60 dc 00 00 04 33 30 3c 00 00 00 20 63 62
39 62 33 61 36 37 34 64 31 36 66 32 31 39 30 64
30 34 30 63 30 39 32 66 34 66 38 38 32 62 00 06
35 2e 31 33 2e 31 00 00 02 3c
so i build the string:
string packet = "003860dc0000" + textbox1.text+ "00000020" + textbox2.text+ "0006" + textbox3.text;
then "convert" it to ascii:
conn_str = HexString2Ascii(packet);
then i send the packet... but i have this:
00 38 60 **c3 9c** 00 00 04 33 30 3c 00 00 00 20 63
62 39 62 33 61 36 37 34 64 31 36 66 32 31 39 30
64 30 34 30 63 30 39 32 66 34 66 38 38 32 62 00
06 35 2e 31 33 2e 31 00 00 02 3c **0a**
why??
Thank you!
P.S.
the function is:
private string HexString2Ascii(string hexString)
{
byte[] tmp;
int j = 0;
int lenght;
lenght=hexString.Length-2;
tmp = new byte[(hexString.Length)/2];
for (int i = 0; i <= lenght; i += 2)
{
tmp[j] =(byte)Convert.ToChar(Int32.Parse(hexString.Substring(i, 2), System.Globalization.NumberStyles.HexNumber));
j++;
}
return Encoding.GetEncoding(1252).GetString(tmp);
}
EDIT:
if i convert directly in byte, the hex packet in coded as string:
00000000 30 30 33 38 36 30 64 63 30 30 30 30 30 34 33 33 003860dc 00000433
00000010 33 30 33 43 30 30 30 30 30 30 32 30 33 34 33 32 303C0000 00203432
00000020 36 33 36 33 33 35 33 39 33 32 33 34 36 36 33 39 63633539 32346639
00000030 36 33 33 39 33 31 33 39 33 30 33 36 33 33 36 35 63393139 30363365
00000040 33 35 36 33 36 35 36 35 36 35 33 31 33 39 33 38 35636565 65313938
00000050 36 33 33 31 36 34 33 34 36 33 33 30 30 30 30 36 63316434 63300006
00000060 33 35 32 65 33 31 33 33 32 65 33 31 30 30 30 30 352e3133 2e310000
00000070 30 32 33 43 023C
You cannot convert raw binary data to string data and expect things to just work. They are not the same. This is especially true when you mix up your character encodings.
C# characters are not ASCII characters. They are Unicode characters, represented by Unicode code points. When you then turn around and write those characters out, you need to specify what kind of data to write out. When you read your byte array into a string, using Encoding.GetEncoding(1252), you are getting the characters corresponding to code page 1252, in which 0xdc is a Ü.
But when your string is being converted back into bytes to send over the network, it is being written out as UTF-8. In UTF-8, UTF-00DC cannot be encoded as a single byte, since that byte value is used to indicate the start of a multi-byte sequence. Instead, it's encoded as the multi-byte sequence 0xc3 0x9c. As far as C# is concerned, those two values are the same character. (I don't know where that extra 0x0a is coming from, but my guess is an errant line feed from one of your text boxes and/or some other part of your process).
Its not clear what exactly you're trying to do, but I suspect you are converting way too many times for it to work out correctly. If you know the byte sequence you want to send, why not just encode that as a byte[] directly? For example, use a MemoryStream and write the constant bytes you need into it.
To get the values out of your text boxes, your original code to "convert" the string of hex digits into a string of ASCII characters had the right idea. You just need to stop at the point where you have a byte array, since ultimately the byte array is what you want.
public byte[] GetBytesFrom(string hex)
{
var length = hex.Length / 2;
var result = new byte[length];
for (var i = 0; i < length; i++)
{
result[i] = byte.Parse(hex.Substring(i, 2), NumberStyles.HexNumber);
}
return result;
}
// Variable portions of packet structure.
var byte[] segment2 = GetBytesFrom(textbox1.Text);
var byte[] segment4 = GetBytesFrom(textbox2.Text);
var byte[] segment6 = GetBytesFrom(textbox3.Text);
MemoryStream output = new MemoryStream();
output.Write(new[] { 0x00, 0x38, 0x60, 0xdc, 0x00, 0x00 }, 0, 6);
output.Write(segment2, 0, segment2.Length);
output.Write(new[] { 0x00, 0x00, 0x00, 0x20 }, 0, 4);
output.Write(segment4, 0, segment4.Length);
output.Write(new[] { 0x00, 0x06 }, 0, 2);
output.Write(segment6, 0, segment6.Length);
From here, you could use MemoryStream.CopyTo() to copy it to another stream, or MemoryStream.Read() to read the entire packet into a new byte array, or MemoryStream.GetBuffer() to get the underlying buffer (though that last one is rarely what you want -- it includes unused padding bytes)

Project Euler 18

Hey, been working at Project Euler, and this one is giving me some problems
By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
3
7 4
2 4 6
8 5 9 3
That is, 3 + 7 + 4 + 9 = 23.
Find the maximum total from top to bottom of the triangle below:
...
NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route. However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)
here's the algorithm I've used to solve it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Problem18
{
class Program
{
static void Main(string[] args)
{
string triangle = #"75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23";
string[] rows = triangle.Split('\n');
int currindex = 1;
int total = int.Parse(rows[0]);
Console.WriteLine(rows[0]);
for (int i = 1; i < rows.Length; i++)
{
string[] array1 = rows[i].Split(' ');
if (array1.Length > 1)
{
if (int.Parse(array1[currindex - 1]) > int.Parse(array1[currindex]))
{
Console.WriteLine(array1[currindex - 1]);
total += int.Parse(array1[currindex - 1]);
}
else
{
Console.WriteLine(array1[currindex]);
total += int.Parse(array1[currindex]);
currindex++;
}
}
}
Console.WriteLine("Total: " + total);
Console.ReadKey();
}
}
}
now whenever i run it, it comes up with 1064, only 10 less then the solution -- 1074
i haven't found any problems with the algorithm and I did the problem by hand and also came up with 1064, anyone know if the solution is wrong, i'm interpreting the question wrong, or if there's just a flaw in the algorithm?
Here is a graphical description:
Here's what the bottom up method belisarius describes--using the trivial triangle given in problem 18--looks like, just in case the image in his post is confusing to anyone else.
03
07 04
02 04 06
08 05 09 03
03
07 04
02 04 06
08 05 09 03
^^^^^^
03
07 04
10 04 06
08 05 09 03
^^^^^^
03
07 04
10 13 06
08 05 09 03
^^^^^^
03
07 04
10 13 15
^^^^^^
08 05 09 03
03
20 04
10 13 15
^^^^^^
08 05 09 03
03
20 04
10 13 15
^^^^^^
08 05 09 03
03
20 19
^^^^^^
10 13 15
08 05 09 03
23
^^
20 19
10 13 15
08 05 09 03
Your problem is that your algorithm is a greedy algorithm, always finding local maxima. Unfortunately that causes it to miss higher numbers down below because they are directly below lower numbers. For example, if the triangle were only 3 levels, your algorithm would pick 75 + 95 + 47 = 217, while the correct answer is 75 + 64 + 82 = 221.
The correct algorithm will either try every path and choose the one with the highest total, or compute paths from the bottom up (which allows you to avoid trying every one, thus being much faster). I should add that working from the bottom-up is not only much faster (O(n^2) instead of O(2^n)!), but also much easier to write (I did it in about 3 lines of code).
You've written a greedy algorithm, which I don't think fits the requirements here. Here's a quick example to demonstrate that point:
1
2 1
1 1 100
Using your algorithm you'll reach a sum of 4, although the optimal solution is 102.
It is a good question based on dynamic programming. You need to create a 2d data structure(like vector in c++) then follow the bottom to up approach of dp.
The formula is dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1]). Try coding on your own then if you are stuck at some point see my solution.
vector< vector<int> > dp(n); // n is the number of rows
for (int i = 0 ; i < n; i++){
for (int j = 0; j <= i; j++){
cin >> val;
dp[i].push_back(val);
}
}
for (int i = n - 2 ; i >= 0; i--)
{
for (int j = 0; j <= i; j++)
dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1]);
}
cout << dp[0][0] << endl;
return 0;
}
input: 3
2
4 5
6 8 9
output: 16
Recursive (not necessarily the best) approach:
static int q18(){
int matrix[][] = // BIG MATRIX;
return getMaxPath(matrix, 0, 0, 0);
}
static int getMaxPath(int matrix[][], int sum, int row, int col){
if(row==matrix.length) return sum;
return Math.max(getMaxPath(matrix, sum+matrix[row][col], row+1, col),
getMaxPath(matrix, sum+matrix[row][col], row+1, col+1));
}

Categories