miracle8304 / aforge

Automatically exported from code.google.com/p/aforge
0 stars 0 forks source link

Provide a way to listen to raw protocol (NXT brick) #196

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
I would like to be able to read sent messages and their responses. I think 
belove change would be great.

namespace AForge.Robotics.Lego.Internals
    {
        using System;
        using System.IO;
        using System.IO.Ports;

        public class MessageEventArgs : EventArgs
        {
            public byte[] Message { get; set; }
            public string MessageString
            {
                get
                {
                    return Encoding.Default.GetString(Message);
                }
            }
            public MessageEventArgs(byte[] message)
            {
                Message = message;
            }
        }
        public interface INXTCommunicationInterface
        {

        }
        /// <summary>
        /// Implementation of serial communication interface with LEGO Mindstorm NXT brick.
        /// </summary>
        /// 
        internal class SerialCommunication : INXTCommunicationInterface
        {
            // serial port for communication with NXT brick
            SerialPort port = null;

            /// <summary>
            /// Maximum message size, which can be sent over this communication interface to NXT
            /// brick.
            /// </summary>
            /// 
            public const int MaxMessageSize = 64;

            /// <summary>
            /// Serial port name used for communication.
            /// </summary>
            /// 
            public string PortName
            {
                get { return port.PortName; }
            }

            /// <summary>
            /// Get connection status.
            /// </summary>
            /// 
            public bool IsConnected
            {
                get { return port.IsOpen; }
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="SerialCommunication"/> class.
            /// </summary>
            /// 
            /// <param name="portName">Serial port name to use for communication.</param>
            /// 
            /// <remarks>This constructor initializes serial port with default write and read
            /// timeout values, which are 1000 milliseconds.</remarks>
            /// 
            public SerialCommunication(string portName) :
                this(portName, 1000, 1000)
            {
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="SerialCommunication"/> class.
            /// </summary>
            /// 
            /// <param name="portName">Serial port name to use for communication.</param>
            /// <param name="writeTimeout">Timeout value used for write operations.</param>
            /// <param name="readTimeout">Timeout value used for read operations.</param>
            /// 
            public SerialCommunication(string portName, int writeTimeout, int readTimeout)
            {
                this.port = new SerialPort(portName);
                this.port.WriteTimeout = writeTimeout;
                this.port.ReadTimeout = readTimeout;
            }

            /// <summary>
            /// Connect to NXT brick.
            /// </summary>
            /// 
            /// <returns>Returns <b>true</b> if connection was established successfully or <b>false</b>
            /// otherwise.</returns>
            /// 
            /// <remarks>If communication interface was connected before the call, existing connection will be reused.
            /// If it is required to force reconnection, then <see cref="Disconnect"/> method should be called before.
            /// </remarks>
            /// 
            public bool Connect()
            {
                if (!port.IsOpen)
                {
                    // try to connect 
                    try
                    {
                        port.Open();
                    }
                    catch
                    {
                        return false;
                    }
                }
                return true;
            }

            /// <summary>
            /// Disconnect from NXT brick.
            /// </summary>
            public void Disconnect()
            {
                if (port.IsOpen)
                {
                    port.Close();
                }
            }

            /// <summary>
            /// Send message to NXT brick over the communication interface.
            /// </summary>
            /// 
            /// <param name="message">Buffer containing the message to send.</param>
            /// 
            /// <returns>Returns <b>true</b> if message was sent successfully or <b>false</b>
            /// otherwise.</returns>
            /// 
            /// <remarks>This method assumes that message starts from the start of the
            /// specified buffer and occupies entire buffer.</remarks>
            /// 
            public bool SendMessage(byte[] message)
            {
                return SendMessage(message, 0, message.Length);
            }

            /// <summary>
            /// Send message to NXT brick over the communication interface.
            /// </summary>
            /// 
            /// <param name="message">Buffer containing the message to send.</param>
            /// <param name="length">Length of the message to send.</param>
            /// 
            /// <returns>Returns <b>true</b> if message was sent successfully or <b>false</b>
            /// otherwise.</returns>
            /// 
            /// <remarks>This method assumes that message starts from the start of the
            /// specified buffer.</remarks>
            /// 
            public bool SendMessage(byte[] message, int length)
            {
                return SendMessage(message, 0, length);
            }

            public event EventHandler MessageSent;

            public virtual void OnMessageSent(object sender, EventArgs e)
            {
                EventHandler handler = MessageSent;
                if (handler != null)
                    handler(sender, e);
            }

            /// <summary>
            /// Send message to NXT brick over the communication interface.
            /// </summary>
            /// 
            /// <param name="message">Buffer containing the message to send.</param>
            /// <param name="offset">Offset of the message in the buffer.</param>
            /// <param name="length">Length of the message to send.</param>
            /// 
            /// <returns>Returns <b>true</b> if message was sent successfully or <b>false</b>
            /// otherwise.</returns>
            /// 
            public bool SendMessage(byte[] message, int offset, int length)
            {
                // check connection status
                if (!port.IsOpen)
                {
                    throw new NullReferenceException("Serial port is not opened");
                }

                // check message size
                if (length > MaxMessageSize)
                {
                    throw new ArgumentException("Too large message");
                }

                try
                {
                    // send 2 bytes of message length
                    byte[] messageLength = new byte[2] { (byte)length, 0 };
                    port.Write(messageLength, 0, 2);
                    // send actual message
                    port.Write(message, offset, length);
                    OnMessageSent(this, new MessageEventArgs(message));
                }
                catch
                {
                    return false;
                }

                return true;
            }

            /// <summary>
            /// Read message from NXT brick over the communication interface.
            /// </summary>
            /// 
            /// <param name="buffer">Buffer to use for message reading.</param>
            /// <param name="length">On successful return the variable keeps message length.</param>
            /// 
            /// <returns>Returns <b>true</b> if message was read successfully or <b>false</b>
            /// otherwise.</returns>
            /// 
            public bool ReadMessage(byte[] buffer, out int length)
            {
                return ReadMessage(buffer, 0, out length);
            }

            public event EventHandler MessageRead;

            public virtual void OnMessageRead(object sender, EventArgs e)
            {
                EventHandler handler = MessageRead;
                if (handler != null)
                    handler(sender, e);
            }

            /// <summary>
            /// Read message from NXT brick over the communication interface.
            /// </summary>
            /// 
            /// <param name="buffer">Buffer to use for message reading.</param>
            /// <param name="offset">Offset in the buffer for message.</param>
            /// <param name="length">On successful return the variable keeps message length.</param>
            /// 
            /// <returns>Returns <b>true</b> if message was read successfully or <b>false</b>
            /// otherwise.</returns>
            /// 
            public bool ReadMessage(byte[] buffer, int offset, out int length)
            {
                // check connection status
                if (!port.IsOpen)
                {
                    throw new NullReferenceException("Serial port is not opened");
                }

                length = 0;

                try
                {
                    // read 2 bytes of message length
                    // - first byte keeps the length
                    int toRead = port.ReadByte();
                    // - second byte is zero
                    port.ReadByte();
                    // check buffer size
                    if (toRead > buffer.Length - offset)
                    {
                        // remove incomming message from the port
                        while (toRead != 0)
                        {
                            port.ReadByte();
                            toRead--;
                        }
                        throw new ArgumentException("Reply buffer is too small");
                    }
                    // read the message
                    length = port.Read(buffer, offset, toRead);

                    while (length != toRead)
                    {
                        buffer[offset + length] = (byte)port.ReadByte();
                        length++;
                    }
                    OnMessageRead(this, new MessageEventArgs(buffer));
                }
                catch
                {
                    return false;
                }

                return true;
            }
        }
    }

Also there should be a public property for NXtBrick communicationInterface 
field.

Original issue reported on code.google.com by krzysztof.blacha on 3 Apr 2011 at 11:55

GoogleCodeExporter commented 9 years ago
>> I think belove change would be great.
Send a patch then.

Original comment by andrew.k...@gmail.com on 4 Apr 2011 at 8:11

GoogleCodeExporter commented 9 years ago
Attached you can find prepared patch files.

Original comment by krzysztof.blacha on 4 Apr 2011 at 10:16

Attachments:

GoogleCodeExporter commented 9 years ago
By the way, whould it be enough if NXTBrick.SendCommand() would just become 
public? It would give access to raw protocol as well.

Original comment by andrew.k...@gmail.com on 4 Apr 2011 at 10:19

GoogleCodeExporter commented 9 years ago
Yes this could be also usefull but I need it for a different approach. I'm 
working on a small robotics IDE for my master thesis and I need to review all 
commands which are send/received to/from the NXT brick. So I need those events 
as well. I could extend SerialCommunication with my own class but NXT brick 
does't allow to swap communication interface implementer (you could add this as 
well - strategy pattern).

Original comment by krzysztof.blacha on 4 Apr 2011 at 11:25

GoogleCodeExporter commented 9 years ago

Original comment by andrew.k...@gmail.com on 19 Apr 2011 at 8:54

GoogleCodeExporter commented 9 years ago
Issue 196: Provide a way to listen to raw protocol (NXT brick) 

1) NXTBrick.SendCommand() is made public, so users may send their own custom 
messages.
2) Added NXTBrick.MessageRead and NXTBrick.MessageSent events, so a 
communication listener could be implemented.

Committed in revision 1418. Will be released in 2.1.6.

Notes: implementation was changed a bit because of the following reasons:
1) Don’t need to expose internal interface INXTCommunicationInterface, so 
user could access its methods.
2) Also don’t need to have MessageRad/Sent event in every communication class 
– it can be done once in the NXT brick.
3) The MessageEventArgs was allowing to modify sent/received buffer. What for?
4) Also create dedicated delegate for the event, so user don’t need to do any 
casting.

Original comment by andrew.k...@gmail.com on 20 Apr 2011 at 8:16

GoogleCodeExporter commented 9 years ago

Original comment by andrew.k...@gmail.com on 28 Jul 2011 at 9:46

GoogleCodeExporter commented 9 years ago

Original comment by andrew.k...@gmail.com on 10 Aug 2011 at 9:31