• UDP Networking & Bytes
    8 replies, posted
I think this question is alittle bit to large for the "what do you need help with" so I'm posting it here. I'm sure one of you guy's may be able to give me some insight. I have a (school) project that I must send UDP packets to a remote machine that controls a robot arm. You can choose any language, I choose C#. I setup the socket, and I can properly send/receive data. My issue is understanding what they want me to send. I have two message, stop and raise/lower. Both contain a header and a message length. There's also a status command sending back from the remote machine, that I must respond too. Here's a scan from my project book. [url]http://s24.postimg.org/l8r526t5h/sdfsd.jpg[/url] Again, I setup the socket and it works just fine. My issue is deciphering how exactly the message should look. I'm not good with bits/bytes. All I currently was doing was: [CODE]Encoding.ASCII.GetBytes("some string data");[/CODE] Which when I send down the wire, I can reassemble it on the other end just fine. But they want me to use UInt16, and what not. No idea how I would work this into the program. Thanks.
Well firstly you should post your full code, that might be helpful.
There isn't much to show. As it doesn't do anything. [code] namespace SocketTest { public partial class Form1 : Form { private Socket m_Socket; private IPAddress m_hSendingIP; private bool m_RequestStatus = false; private int m_Port = 1337; private byte[] header = { 0, 3, 0 }; public Form1() { InitializeComponent(); MessageBox.Show( BitConverter.ToInt16(header,1).ToString() ); } private void textBox4_Leave(object sender, EventArgs e) { m_hSendingIP = IPAddress.Parse(mmcp_server.Text.ToString()); } private void btnStart_Click(object sender, EventArgs e) { try { int.TryParse(mmcp_port.Text, out m_Port); m_hSendingIP = IPAddress.Parse(mmcp_server.Text); m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); m_Socket.EnableBroadcast = true; m_Socket.Bind(new IPEndPoint(m_hSendingIP, m_Port)); ThreadWorker.RunWorkerAsync(false); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { MessageBox.Show("Program started successfully"); btnStart.Enabled = false; } } private void ThreadWorker_DoWork(object sender, DoWorkEventArgs e) { while(true) { Byte[] gotBytes = new byte[1024]; try { IPEndPoint senderIP = new IPEndPoint(IPAddress.Any, 0); EndPoint senderRemote = (EndPoint)senderIP; m_Socket.ReceiveFrom(gotBytes, ref senderRemote); ThreadWorker.ReportProgress(0, gotBytes); } catch (Exception ex) { gotBytes = Encoding.UTF8.GetBytes( "failed to grab socket data" ); ThreadWorker.ReportProgress(0, gotBytes); } } } private void ThreadWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { Byte[] gotBytes = new byte[1024]; gotBytes = (Byte[])e.UserState; mmcp_get.Text = BitConverter.ToString(gotBytes); mmcp_dec.Text = BitConverter.ToUInt16(gotBytes, 1).ToString(); mmcp_string.Text = Encoding.UTF8.GetString(gotBytes); } // request status button private void button2_Click(object sender, EventArgs e) { m_RequestStatus = !m_RequestStatus; if (m_RequestStatus) button2.Text = "Stop Request Command"; else button2.Text = "Start Request Command"; } // stop command button private void button3_Click(object sender, EventArgs e) { // this is the request status command in hex byte[] sentBytes = { 1, 3, 0 }; IPEndPoint plcEnd = new IPEndPoint(m_hSendingIP, m_Port); m_Socket.SendTo(sentBytes, plcEnd); } private void sendTimer_Tick(object sender, EventArgs e) { // this is the request status command in hex byte[] sentBytes = { 82 }; IPEndPoint plcEnd = new IPEndPoint(m_hSendingIP, m_Port); m_Socket.SendTo(sentBytes,plcEnd); } // raise private void button4_Click(object sender, EventArgs e) { } } } [/code] It's a garbled mess, it just simulates the external device i'm going to be communicating with. I can send UDP packets to myself, but I need them in the exact format that document calls for.
Well, the specification shows that you firstly need to construct the header from ushorts (AKA UInt16-s) and if needed append another ushort value for elevation control. An important thing to notice is the MSN. You need to increment it every time you send a packet. So, lets say this is the 6th packet you send, and you want to send the Stop command. The Stop command is described in table 3, but I can't see any actual description of what the "Stop" message type is. I'll assume it is 3 or 0x03 just for the sake of the example. This is how you would construct the packet: [code] ushort messageType = 3; // assuming the message type for Stop is 3 ushort messageLength = 3; // as described in the Limit/Range column of Stop ushort messageSequenceNumber = 6; // this is the 6th packet we send //create a buffer to contain the data to send var buf = new byte[6]; // copy the values one by one into the buffer Array.Copy(BitConverter.GetBytes(messageType), 0, buf, 0, 2); Array.Copy(BitConverter.GetBytes(messageLength), 0, buf, 2, 2); Array.Copy(BitConverter.GetBytes(messageSequenceNumber), 0, buf, 4, 2); [/code] [editline]17th April 2013[/editline] In the case of the Move command, the difference is that Message Length is now 4, which means there's one more value you send. This means you need to change messageLength to 4 and when constructing the byte array you need to allocate 2 more bytes, the size of an UInt16 (the 16 means 16 bits, which is 2 bytes as each byte is 8 bits). You also need to Copy over this extra ushort, which would be 1 in the case of elevation and 2 in the case of lowering. [editline]17th April 2013[/editline] Oh and you also need to change the messageType to whatever it is for the Move command.
Ah, gotcha! That's amazingly helpful, thank you. There was one table I forgot to include that's stumping me now. I have to send back an "acknowledge" response. Which is just a bunch of ushorts, however, one is a "bit array (16 bits)" If I'm sending ONE packet of data, as it's asking me too, how can I put an array... in an array. That sounds silly. [url]http://s4.postimg.org/pv26yf6al/sdfsd_1.jpg[/url]
Well, what you're sending is an array of bytes. Every byte is an array of 8 bits, but normally you don't modify the individual bits in a byte except when you need to pack a lot of data in small values. What they [b]are[/b] saying is that you need to send 2 bytes (16 bits). Now, in these 2 bytes you need to pack all the statuses of the subsystems. While it may seem like a lot to shove in one ushort, in reality you have 16 bits to flip on or off, so that's 16 "fault or not" values you can send. What you have to do here is take an ushort or 2 bytes and modify the bits individually to set the statuses. [code] // create a 2-byte / 16-bit bitArray BitArray ba = new BitArray(16); // set individual values ba[0] = true; ba[5] = true; // copy these bits to a byte array (to turn them into bytes you could send) byte[] ba_buf = new byte[16]; ba.CopyTo(ba_buf, 0); [/code]
Again, thank you. That pretty much sums up everything that I need.
[QUOTE=Perl;40315199]Well, the specification shows that you firstly need to construct the header from ushorts (AKA UInt16-s) and if needed append another ushort value for elevation control. An important thing to notice is the MSN. You need to increment it every time you send a packet. So, lets say this is the 6th packet you send, and you want to send the Stop command. The Stop command is described in table 3, but I can't see any actual description of what the "Stop" message type is. I'll assume it is 3 or 0x03 just for the sake of the example. This is how you would construct the packet: [code] ushort messageType = 3; // assuming the message type for Stop is 3 ushort messageLength = 3; // as described in the Limit/Range column of Stop ushort messageSequenceNumber = 6; // this is the 6th packet we send //create a buffer to contain the data to send var buf = new byte[6]; // copy the values one by one into the buffer Array.Copy(BitConverter.GetBytes(messageType), 0, buf, 0, 2); Array.Copy(BitConverter.GetBytes(messageLength), 0, buf, 2, 2); Array.Copy(BitConverter.GetBytes(messageSequenceNumber), 0, buf, 4, 2); [/code] [editline]17th April 2013[/editline] In the case of the Move command, the difference is that Message Length is now 4, which means there's one more value you send. This means you need to change messageLength to 4 and when constructing the byte array you need to allocate 2 more bytes, the size of an UInt16 (the 16 means 16 bits, which is 2 bytes as each byte is 8 bits). You also need to Copy over this extra ushort, which would be 1 in the case of elevation and 2 in the case of lowering. [editline]17th April 2013[/editline] Oh and you also need to change the messageType to whatever it is for the Move command.[/QUOTE] Man, "Array.Copy(BitConverter.GetBytes(messageType), 0, buf, 0, 2);" brings me back to the halo mod times. You should use a Stream and BinaryWriter instead. [code]void WriteHeader(Stream s) { var bw = new BinaryWriter(s); bw.Write(MessageType); bw.Write(MessageLength); bw.Write(MessageSequenceNumber); } byte[] CreateHeader() { using (var ms = new MemoryStream()) { var bw = new BinaryWriter(s); bw.Write(MessageType); bw.Write(MessageLength); bw.Write(MessageSequenceNumber); return ms.ToArray(); } } Packet.WriteHeader(NetworkStream); SendPacket(Packet.CreateHeader()); [/code]
[QUOTE=high;40326646]Man, "Array.Copy(BitConverter.GetBytes(messageType), 0, buf, 0, 2);" brings me back to the halo mod times. You should use a Stream and BinaryWriter instead. [code]void WriteHeader(Stream s) { var bw = new BinaryWriter(s); bw.Write(MessageType); bw.Write(MessageLength); bw.Write(MessageSequenceNumber); } byte[] CreateHeader() { using (var ms = new MemoryStream()) { var bw = new BinaryWriter(s); bw.Write(MessageType); bw.Write(MessageLength); bw.Write(MessageSequenceNumber); return ms.ToArray(); } } Packet.WriteHeader(NetworkStream); SendPacket(Packet.CreateHeader()); [/code][/QUOTE] Oh, right. I'd completely forgotten streams existed.
Sorry, you need to Log In to post a reply to this thread.