none
Serial Port - commands/responses sequence

    Question

  • Hello All,

    I want to write a MRDS service to communicate with my own hardware/protocol via RS232 and I need some basic guidelines.
    My protocol consists of commands sent by a remote PC and the corresponding responses sent back from the robot.

    So, the service should send driving commands and poll for sensor data. My question is: What is the correct way of handling the synchronization between commands and responses?

    For example, when the service polls for sensor data, shoud it wait for the response? Or should the service handle a response asynchronously when it is received on the serial port?

    Is it the same case when a command expects a simple acknowledgment as response?

    Thanks in advance.

     

    Carlos

    Thursday, August 21, 2008 11:33 PM

Answers

  • This is a common problem. There are several ways to handle this.

     

    You can use the APM model for Serial I/O and wrap it so that it works in a CCR environment. Have a look at Channel 9 for discussion of this approach.

     

    You can also create your own dispatcher and use a separate thread to do synchronous I/O. This will not affect the rest of the service. You should use ports to send commands, and you can send responses back to ports as well.

     

    Also, have a look at some of the implementations that are included with RDS. The Arcos drive, the LEGO NXT, the iRobot Create, etc. all use serial I/O, even though it is over Bluetooth. They use different approaches, but you might be able to just copy/paste some of the code.

     

    And lastly, if you look in the last couple of chapters of our book you will see that there are simple services that use serial I/O. The code is available here:

    www.promrds.com

     

    Trevor

     

    Friday, August 22, 2008 4:45 AM
    Owner

All replies

  • This is a common problem. There are several ways to handle this.

     

    You can use the APM model for Serial I/O and wrap it so that it works in a CCR environment. Have a look at Channel 9 for discussion of this approach.

     

    You can also create your own dispatcher and use a separate thread to do synchronous I/O. This will not affect the rest of the service. You should use ports to send commands, and you can send responses back to ports as well.

     

    Also, have a look at some of the implementations that are included with RDS. The Arcos drive, the LEGO NXT, the iRobot Create, etc. all use serial I/O, even though it is over Bluetooth. They use different approaches, but you might be able to just copy/paste some of the code.

     

    And lastly, if you look in the last couple of chapters of our book you will see that there are simple services that use serial I/O. The code is available here:

    www.promrds.com

     

    Trevor

     

    Friday, August 22, 2008 4:45 AM
    Owner
  • Thank you Trevor! I will try to write my service based on your code for the Hemisson robot.

    Regards,

    Carlos.

    Tuesday, August 26, 2008 4:50 PM
  • Tq for the info, but anyway, i cannot find the code you mention in the web site you provide after i tried to search in the web site, but sorry for trouble, but may i hv the directory code for simple services that use serial I/O? Actually i'm doing the service for serial port for my project as well, i fail to send and receive data thru the service in MSRS..i tried the tutorial in help, but still fail to get the idea for serial port..
    Wednesday, October 15, 2008 8:25 AM
  • Over the next week I will try to put together a sample. I've just been very busy the last couple of weeks.

     

    Trevor

     

     

    Thursday, October 16, 2008 2:30 AM
    Owner
  • Tq Trevor, I found the smaple code, its helpful, i found the content of the book you mention in this site:
    http://www.promrds.com/Chapter1/Readme.htm

    and the code by install the exe file(Samples Package for July CTP) which i downloaded from this site:
    http://www.promrds.com/Downloads.htm


    anyway, may i know is there any other source for the book u mention?the content of the book i found in the first site i mention is like the summary, so i wonder is there any other source for the book besides the one i found in the first site, thanks!

    Thursday, October 16, 2008 3:27 AM
  • What you see on http://www.promrds.com is what you get. The web site is just a summary. All of the sample code is include in the download.

     

    If you want the book, only one chapter was released for free download. Apart from that I'm afraid you will have to buy it :-)

     

    Trevor

     

     

    Thursday, October 16, 2008 5:14 AM
    Owner
  • Tq Trevol..anyway, currently i got a service(let say service A) which can send data thru serial(in string), but when i receive the data thru serial port, i cannot pass the receiveced data thru the service A to service B, i just wish to do simple service for receive data(in string) and pass it to other service, is it anything to with the SerialDataReceivedEventHandler?or i need another handler to do that?please help...
    Thursday, October 16, 2008 9:19 AM
  • OK, the usual scenario is this:

    • Service A wants to communicate with a serial port, and this must be done via Service B.
    • Service A partners with B. On startup, Service A also subscribes to B for notifications.
    • Once it is running, Service A sends a request to Service B to send some data.
    • Service B sends the data to the serial port.
    • Some time later, some new data (an acknowledgement) comes back on the serial port and Service B receives it.
    • Service B now sends a notification message containing the new data.
    • Note that Service B does not have to know who is listening becasue the RDS Subscription Manager takes care of this as long as you have a Subscribe operation implemented properly.
    • The notification handler in Service A should now run and receive the data.

    So, Service B must implement some operation for sending data, probably based on the Update message type. Assume this is called SendData and it takes a string as the parameter.

    You should also define a similar operation called ReceiveData (also based on an Update). This is not intended as a request, but as a notification message type.

    Service B must also implement the Subscribe operation.

    When it receives data on the serial port it must send a ReceiveData message to the Subscription Manager which will take care of sending a copy to all subscribers.

     

    Trevor

     

     

     

     

    Saturday, October 18, 2008 3:42 AM
    Owner
  • tq Trevor, this is the code i try to send notification to another service inside SubscribeHandler
    code snippet:
    base.SendNotificationToTarget<Replace>(request.Subscriber, _submgrPort, _state);
                 base.SendNotificationToTarget<SendData>(request.Subscriber, _submgrPort, _state);
                 base.SendNotificationToTarget<ReceiveData>(request.Subscriber, _submgrPort, _state);

    i dunno it is correct method, and how do i send the message after the notification?it must send thru main port?
    Actually, I do refer with the example in MSRS, likes Arcosdrive, Lego NXT, they have a class which specially due with com port, and the thing that make me confuse there so many .cs file in the project, is hard for me to understand which part is due with the serial communication, which is use to send data, which part is use to receive and process data.. Er...actually, refering to the example, does it mean that i also have to do so?or can i just have 2 .cs file (let say ComPort.cs and ComPortTypes.cs which generated in DSS command prompt thru dssnewservice)and process the ComPort thing within these 2 files?please help...
    Monday, October 20, 2008 8:55 AM
  • Yes, you send a notification when somebody subscribes to your service. You also have to send a notification whenever the state of your service changes, such as when you receive data on the serial port. So the handler for serial data needs to call SendNotification. (This method sends to all subscribers).

     

    The different platform services were written by different people who used different approaches for handling the serial communications. This simply demonstrates that there is no "right" way to do it, just lots of different ways.

     

    All you really need is two files as you suggest. You can create the basic skeleton of the service using the DssNewService command-line tool or the Wizard in Visual Studio.

     

    I've been trying to write a serial port service for the last couple of weeks but I have been too busy working on the 2.0 release. I will post a message in this forum as soon as I have an example available.

     

    Trevor

     

     

    Wednesday, October 22, 2008 7:38 AM
    Owner
  • Hi Trevor, really thanks a lot for the help, just to let you know, i can send and receive serial port data thru service already, although it is just a very simple service, but i think it will be a good start point for me to continue my project..really thanks a lot for the help given.. mm...and i found that you also reply my question in this link:
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=4031286&SiteID=1

    really appreciate that..

    mm...maybe my code not a correct and proper way to send and receive serial data thru service, but just sharing if there is anyone also wish to have a simple serial service:

    code snippet:
    //----------------------------------------------------------------//
    the part for serial port :
    //----------------------------------------------------------------//

    void OpenSerial(int comPort, int baudRate)
            {
                try
                {
                    serialPort = new SerialPort("COM" + comPort.ToString(), baudRate);
                
                    serialPort.Parity = Parity.None;
                    serialPort.DataBits = 8;
                    serialPort.StopBits = StopBits.One;
                    serialPort.ReadTimeout = 5000;
                   serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
                    serialPort.Open();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }

            }

            //Send data that your robot understands
            void SendData(string data)
            {
                serialPort.Write(data);
            }

            void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                  ReceiveData receive = new ReceiveData();
                    
                  string msgr = serialPort.ReadExisting();             
                  receive.Body.DataReceived = msgr;                    
                  base.SendNotification(_submgrPort, receive);                  ///the notification send to other service
                  LogInfo("Receive ");
                  LogInfo("Command:" + receive.Body.DataReceived);  
            }

    //----------------------------------------------------------------//
    handler for send and receive
    //----------------------------------------------------------------//

    ///<summary>
            /// Send handler
            /// </summary>
            [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
            public IEnumerator<ITask> UpdateSendHandler(SendData send)
            {
                string msg = send.Body.DataSent;
                SendData(msg);
                base.SendNotification(_submgrPort, send);
                send.ResponsePort.Post(DefaultUpdateResponseType.Instance);
                yield break;
            }

            ///<summary>
            /// Receive handler
            /// </summary>
            [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
            public IEnumerator<ITask> UpdateReceiveHandler(ReceiveData receive)
            {                    
                base.SendNotification(_submgrPort,receive);
                receive.ResponsePort.Post(DefaultUpdateResponseType.Instance);
                yield break;
            }

    //----------------------------------------------------------------//
    service port for send and receive
    //----------------------------------------------------------------//

    [ServicePort]
        public class serialOperations : PortSet<DsspDefaultLookup, DsspDefaultDrop, Get, HttpGet, Config,Subscribe, SendData, ReceiveData>
        {
        }
    //-----------------------------------------------------------------------------------------------------------
        [Description("Send Data to Com Port")]
        public class SendData : Update<UpdateSendRequestType, DsspResponsePort<DefaultUpdateResponseType>>
        {
            public SendData()
            {
            }

            public SendData(string Command)
                : base(new UpdateSendRequestType(Command))
            {
            }
        }
     


        [DataContract]
        public class UpdateSendRequestType
        {
           // public DsspResponsePort<DefaultUpdateResponseType> ResponsePort;

            // public DsspResponsePort<DefaultUpdateResponseType> ResponsePort;
            public UpdateSendRequestType()
            {
            }

            public UpdateSendRequestType(string command)
            {
                DataSent = command;
            }

            private string datasent;
            [DataMember]
            public string DataSent
            {

                get { return datasent; }

                set { this.datasent = value; }

            }


           
        }

    //-----------------------------------------------------------------------------------------------------------
        [Description("Receive Data from com port")]
        public class ReceiveData : Update<UpdateReceiveRequestType, DsspResponsePort<DefaultUpdateResponseType>>
        {
            public ReceiveData()
            {
            }

            public ReceiveData(string Command)
                : base(new UpdateReceiveRequestType(Command))
            {
            }
        }

        [DataContract]
        public class UpdateReceiveRequestType
        {
           // public DsspResponsePort<DefaultUpdateResponseType> ResponsePort;
            public UpdateReceiveRequestType()
            {
            }

            public UpdateReceiveRequestType(string command)
            {
                DataReceived = command;
            }

            private string datareceived;
            [DataMember]
            public string DataReceived
            {

                get { return datareceived; }

                set { this.datareceived = value; }

            }

        }
    //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
    end of code snippet
    //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//

    so in conclusion, i use Update for receive and send data, and Replace for the initial configuration of serial port(COM port and baud rate)

    mm...please give comment, thanks....

    Thursday, October 23, 2008 2:54 AM
  • er ..Trevor,need your help again..sorry for trouble, but, how if i want to send the data in 8bits data thru serail port?currently i can send and receive string, but if i can send and receive data in byte then i can reduce the data send(for example, if i only can send data in string, then when i need a data 255 in microcontroller, i need send 2, follow by 5, then 5, byte by byte, if i can send the 8bits data, i would only need to send FF  in hex/11111111 in binary(which in 1 byte only) and i would still able to process the data after i send thru serial port)

    er..it is possible? and actually when i refer to my friend who has experience in VB.net, they say they face a problem in unable to read data for bit number 8 from serial port by using the serial port class in VB.net , so they did not process the data in bits, it is also happen in C#? asking this question, because i also consult my friend when i learn for C#, the language actually is quite similar...
    Thursday, October 23, 2008 10:05 AM
  • Yes, you can send and receive 8-bit data. I generally don't do it because it is easier to see what is going on if you send everything in human-readable form.

     

    Rather than using strings, you can use an array of bytes. Byte values are 8-bit unsigned, i.e. 0 to 255.

     

    I think you have your settings correct with 8-bit and no parity. If it is set to 7-bit with (odd or even) parity then the top bit will get messed up. However, 8-bit should be OK.

     

    The SerialPort object in VB.NET is exactly the same as in C# because it is part of the .NET Common Language Runtime (CLR) not part of a particular language.

     

    Trevor

     

     

    Friday, October 24, 2008 4:54 PM
    Owner
  • hi..just FYI, i can get data in byte already,  my serial port service and send and receive data in string and byte,this is the code:

    code snippet:
     //Send data in string  that your robot understands
            void SendDataS(string data)
            {
                serialPort.Write(data);

              
            }

            //Send data in byte  that your robot understands
            void SendDataB(byte data)
            {
                byte[] d = new byte[1];
                   
                d[0] = data;
                         
                serialPort.Write(d,0,1);
              
            }


             
       
    //receive data in byte, and convert it to string. i send 2 notification in the data receive handler, so that my serial port can be //more flexible for the data receive.

            void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                ReceiveDataByteArray receiveB = new ReceiveDataByteArray();
                ReceiveDataString receiveS = new ReceiveDataString();
                int i = serialPort.BytesToRead;
                bool a ;
                byte[] b = new byte[ i];   
                serialPort.Read(b, 0, i);
                StringBuilder sb = new StringBuilder(i); //need to include using System.Text; to call this class
                foreach (byte c in b)
                    sb.Append((char)c);

                receiveB.Body.DataReceivedByteArray = b;
                base.SendNotification(_submgrPort,receiveB);
                a = true;
                if(a == true)
                {
                    receiveS.Body.DataReceivedString = sb.ToString();
                    base.SendNotification(_submgrPort,receiveS);
                    a = false;
                }        
                             
            }

    //-----------------------------------------end-------------------------------------------------------------------

    however, i found that if i use ReadExisting to read data from serial port, the data will not be the original data if it is 8bits, for example, when i read byte255 and convert to byte array(because ReadExisting will read data in string, so to use the data in byte, need to use string to byte array converter), i won't get 255, but the other data, below is the code i used to convert string to byte array, it makes not different when i use
    ASCIIEncoding  or UTF8....

    code snippet:

     //string to byte array converter
            public static byte[] StrToByteArray(string str)
            {
            //System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

            //return encoding.GetBytes(str);
                return System.Text.Encoding.UTF8.GetBytes(str);

              
            }

    mm...so i use Read to get the byte, then after that only convert it to string...anyway, any comment for the ReadExisting and the string to byte array converter?it is really make me confuse, why the we i send data in 7 bits, it can process well, but when 8 bits, the data after the string to array converter become not the original one..am i miss anything in my code?

    at first wish to use ReadExisting become the data can be receive faster...tq..



    Tuesday, October 28, 2008 5:13 AM
  • This is really a question about the SerialPort object in .NET. Did you set the Encoding property of the SerialPort? The data will be converted according to the encoding when you call ReadExisting.

     

    Trevor

     

     

    Wednesday, October 29, 2008 6:17 AM
    Owner
  • er...thanks for the suggestion, but i tried to set the encoding property like this:
     a.serialPort.Encoding = Encoding.Default;
    b.serialPort.Encoding = Encoding.UTF8;

    still cannot get the correct 8 bits data...mm...am i do any mistake?

    i found one more problem, when i integrate the serial port code in the service which will communicate to my hardware, let say sensor 1 and sensor 2 one 1 controller board,(i did not control the sensor through 1 service because i want to control it in VPL separately) which mean i need to access the same ComPort (let say Com1), but i face the problem to access the same ComPort in VPL (i open Com1 in service for sensor 1 and also service for sensor2)...mm... may i know what method should i use so that i can use different service to send data thru 1 ComPort?

    thanks for the help...
    Saturday, November 01, 2008 6:23 AM
  • Just a quick update ...

     

    I wrote a simple Serial Port service but it was too late for the RDS 2008 release. I am trying to figure out how to release it separately.

     

    Trevor

     

     

     

    Friday, December 05, 2008 6:54 PM
    Owner
  • Thanks Trevor. sorry for reply late, i was busy for other task before that, and just a update for my progress in MSRS, i can actually communicate with my control board thru a serial service, anyhow, i need to drag the serial service in MSRS in order to use it, i not sure am i leading a correct way, so i still looking forward for the serial service that you have..thanks again!!
    Tuesday, December 16, 2008 11:22 AM
  • Yes, I figured that you had it working.

    If you are using VPL it should be easy enough to use your service. I have VPL samples for my service.

    Due to the way Microsoft handles code releases, I might have to wait until the next version of RDS to release my serial port service.

    Trevor


    Thursday, December 18, 2008 4:52 AM
    Owner