Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 941449
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 15, 20262026-05-15T22:07:15+00:00 2026-05-15T22:07:15+00:00

I’m revisiting a communications protocol parser design for a stream of bytes (serial data,

  • 0

I’m revisiting a communications protocol parser design for a stream of bytes (serial data, received 1 byte at a time).

The packet structure (can’t be changed) is:

|| Start Delimiter (1 byte) | Message ID (1 byte) | Length (1 byte) | Payload (n bytes) | Checksum (1 byte) ||

In the past I have implemented such systems in a procedural state-machine approach. As each byte of data arrives, the state machine is driven to see where/if the incoming data fits into a valid packet a byte at a time, and once a whole packet has been assembled, a switch statement based on the Message ID executes the appropriate handler for the message. In some implementations, the parser/state machine/message handler loop sits in its own thread so as not to burden the serial data received event handler, and is triggered by a semaphore indicating bytes have been read.

I’m wondering if there is a more elegant solution to this common problem, exploiting some of the more modern language features of C# and OO design. Any design patterns that would solve this problem? Event-driven vs polled vs combination?

I’m interested to hear your ideas. Thanks.

Prembo.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-15T22:07:15+00:00Added an answer on May 15, 2026 at 10:07 pm

    First of all I would separate the packet parser from the data stream reader (so that I could write tests without dealing with the stream). Then consider a base class which provides a method to read in a packet and one to write a packet.

    Additionally I would build a dictionary (one time only then reuse it for future calls) like the following:

    class Program {
        static void Main(string[] args) {
            var assembly = Assembly.GetExecutingAssembly();
            IDictionary<byte, Func<Message>> messages = assembly
                .GetTypes()
                .Where(t => typeof(Message).IsAssignableFrom(t) && !t.IsAbstract)
                .Select(t => new {
                    Keys = t.GetCustomAttributes(typeof(AcceptsAttribute), true)
                           .Cast<AcceptsAttribute>().Select(attr => attr.MessageId),
                    Value = (Func<Message>)Expression.Lambda(
                            Expression.Convert(Expression.New(t), typeof(Message)))
                            .Compile()
                })
                .SelectMany(o => o.Keys.Select(key => new { Key = key, o.Value }))
                .ToDictionary(o => o.Key, v => v.Value); 
                //will give you a runtime error when created if more 
                //than one class accepts the same message id, <= useful test case?
            var m = messages[5](); // consider a TryGetValue here instead
            m.Accept(new Packet());
            Console.ReadKey();
        }
    }
    
    [Accepts(5)]
    public class FooMessage : Message {
        public override void Accept(Packet packet) {
            Console.WriteLine("here");
        }
    }
    
    //turned off for the moment by not accepting any message ids
    public class BarMessage : Message {
        public override void Accept(Packet packet) {
            Console.WriteLine("here2");
        }
    }
    
    public class Packet {}
    
    public class AcceptsAttribute : Attribute {
        public AcceptsAttribute(byte messageId) { MessageId = messageId; }
    
        public byte MessageId { get; private set; }
    }
    
    public abstract class Message {
        public abstract void Accept(Packet packet);
        public virtual Packet Create() { return new Packet(); }
    }
    

    Edit: Some explanations of what is going on here:

    First:

    [Accepts(5)]
    

    This line is a C# attribute (defined by AcceptsAttribute) says the the FooMessage class accepts the message id of 5.

    Second:

    Yes the dictionary is being built at runtime via reflection. You need only to do this once (I would put it into a singleton class that you can put a test case on it that can be run to ensure that the dictionary builds correctly).

    Third:

    var m = messages[5]();
    

    This line gets the following compiled lambda expression out of the dictionary and executes it:

    ()=>(Message)new FooMessage();
    

    (The cast is necessary in .NET 3.5 but not in 4.0 due to the covariant changes in how delagates work, in 4.0 an object of type Func<FooMessage> can be assigned to an object of the type Func<Message>.)

    This lambda expression is built by the Value assignment line during dictionary creation:

    Value = (Func<Message>)Expression.Lambda(Expression.Convert(Expression.New(t), typeof(Message))).Compile()
    

    (The cast here is necessary to cast the compiled lambda expression to Func<Message>.)

    I did that this way because I happen to already have the type available to me at that point. You could also use:

    Value = ()=>(Message)Activator.CreateInstance(t)
    

    But I believe that would be slower (and the cast here is necessary to change Func<object> into Func<Message>).

    Fourth:

    .SelectMany(o => o.Keys.Select(key => new { Key = key, o.Value }))
    

    This was done because I felt that you might have value in placing the AcceptsAttribute more than once on a class(to accept more than one message id per class). This also has the nice side affect of ignoring message classes that do not have a message id attribute (otherwise the Where method would need to have the complexity of determining if the attribute is present).

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have a string like this: La Torre Eiffel paragonata all&#8217;Everest What PHP function
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I have this code: - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock { NSString *someString = [[NSString
I don't have much knowledge about the IPv6 protocol, so sorry if the question
I want to construct a data frame in an Rcpp function, but when I
I have some data like this: 1 2 3 4 5 9 2 6
I have a .ini file as follows: [playlist] numberofentries=2 File1=http://87.230.82.17:80 Title1=(#1 - 365/1400) Example
That's pretty much it. I'm using Nokogiri to scrape a web page what has
I have just tried to save a simple *.rtf file with some websites and

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.