1
\$\begingroup\$

My program gets continuously raw input from a stream (TCP), then process the data and output the data to a graph. It should also save the data to a file so it can be read afterwards. To archive this I tried to serialize the processed data with protobuf-net.

The difficulty is that the program should save the processed data after some minutes so if the program/pc crashes the data is not lost. So I need a file format which is similar to a capture format. The file should start with an header and then add the processed buffered data once in a while.

To archive this I tried to work with SerializeWithLengthPrefix and DeserializeWithLengthPrefix/ DeserializeItems. I'm not sure if this is the cleanest solution, this is why I would like you to ask if you may could watch my code. I also would be thankful for coders who had a similar problem and which other ways are out there to solve this problem.

using System;
using System.IO;
using System.Collections.Generic;
using ProtoBuf;
using System.Linq;

namespace ConsoleApp2
{
    class Program
    {
        const int RUNS = 1300;
        const int STEP = 600;
        static SGSFile sgsFile;
        static MemoryStream stream;
        static SGSFile.SGS readSGS, writeSGS;
        [STAThread]
        static void Main()
        {
            SGSFile.Values debugVales;

            stream = new MemoryStream();
            sgsFile = new SGSFile(stream);

            //Test the writing
            TestWrite();
            //Test the reading...
            TestRead();


            //File.WriteAllBytes("bleg.dat", stream.ToArray());

            Console.WriteLine("Stream Size: " + stream.Length);
            Console.WriteLine("Write:");
            Console.WriteLine("\tHdr: {0:X}", writeSGS.header.SerialNumberSensaGuard);
            Console.WriteLine("\tValues Count: " + writeSGS.values.Count);

            debugVales = writeSGS.values.First();
            Console.WriteLine("\tFirst SGS: " + (debugVales.Val * 256 + debugVales.Avg1));
            debugVales = writeSGS.values.Last();
            Console.WriteLine("\tLast SGS: " + (debugVales.Val * 256 + debugVales.Avg1));


            Console.WriteLine("Read:");
            Console.WriteLine("\tHdr: {0:X}", readSGS.header.SerialNumberSensaGuard);
            Console.WriteLine("\tValues Count: " + readSGS.values.Count);


            debugVales = readSGS.values.First();
            Console.WriteLine("\tFirst SGS: " + (debugVales.Val * 256 + debugVales.Avg1));
            debugVales = readSGS.values.Last();
            Console.WriteLine("\tLast SGS: " + (debugVales.Val * 256 + debugVales.Avg1));
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();


        }

        static void TestWrite()
        {
            Random random = new Random();
            int i;

            //Create the SGS Class and fill it
            writeSGS = new SGSFile.SGS
            {
                header = new SGSFile.Header()
                {
                    VersionMajor = 1,
                    AdditionalHardware = 0x02,
                    SerialNumberSensaGuard = 0xabcd
                },
                values = new List<SGSFile.Values>()
            };

            //At first add the header to stream
            sgsFile.AddToStream(writeSGS.header);

            //the for loop represents the main program
            for (i = 0; i < RUNS; i++)
            {
                //Add Values to writeSGS.values' list
                writeSGS.values.Add(new SGSFile.Values()
                {
                    Val = (byte)(i >> 8),
                    Avg1 = (byte)i,
                    Avg2 = (byte)random.Next(0, 255),
                    SumDyn1 = (byte)random.Next(0, 255),
                    SumDyn2 = (byte)random.Next(0, 255),
                    Timestamp = 1505401128 + i
                });
                //every STEP (default 600) times add the last 600 items to stream
                if (i > 0 && i % STEP == 0)
                {
                    sgsFile.AddRangeToStream(writeSGS.values, i - STEP, STEP);
                }
            }
            //If there are some values left, add them. this represents the end of the program
            if (RUNS - i % STEP > 0)
            {
                sgsFile.AddRangeToStream(writeSGS.values, RUNS - i % STEP, i % STEP);
            }

        }

        static void TestRead()
        {
            readSGS = sgsFile.ReadStream();
        }

    }

    //*************SGS File class*************

    public class SGSFile
    {
        Stream stream;

        public SGSFile(Stream stream)
        {
            this.stream = stream;
        }

        //void AddToStream(Values data)
        //{
        //Serializer.SerializeWithLengthPrefix(stream, data, PrefixStyle.Base128, 2);
        //}

        public void AddToStream(List<Values> data)
        {
            //Add a List of Values with Length Prefix to stream
            Serializer.SerializeWithLengthPrefix(stream, data, PrefixStyle.Base128, 0);
        }

        public void AddToStream(Header hdr)
        {
            //Add the Header with Length Prefix[1] to stream
            Serializer.SerializeWithLengthPrefix(stream, hdr, PrefixStyle.Base128, 1);
        }




        public void AddRangeToStream(List<Values> data, int index, int count)
        {
            //Add a Range of a List of Values' to the stream (from-to)
            Serializer.SerializeWithLengthPrefix(stream, data.GetRange(index, count), PrefixStyle.Base128, 0);
        }


        public SGS ReadStream()
        {
            //Initalize 
            SGS sgs = new SGS { values = new List<Values>() };
            IEnumerable<List<Values>> deserializedLists;

            //Starting over the stream (Set it to the beginning)
            stream.Position = 0;

            //Read header
            sgs.header = Serializer.DeserializeWithLengthPrefix<Header>(stream, PrefixStyle.Base128, 1);

            //Read an IEnumerable of Values-Lists. 
            deserializedLists = Serializer.DeserializeItems<List<Values>>(stream, PrefixStyle.Base128, 0);

            foreach (List<Values> dataContainer in deserializedLists)
            {
                sgs.values.AddRange(dataContainer);
            }
            return sgs;
        }

        [ProtoContract]
        public struct Header
        {
            [ProtoMember(1)]
            public byte VersionMajor;
            [ProtoMember(2)]
            public byte VersionMinor;
            [ProtoMember(3)]
            public byte AdditionalHardware;
            [ProtoMember(4)]
            public byte Rsvd;
            [ProtoMember(5)]
            public ushort SerialNumberDisc;
            [ProtoMember(6)]
            public ushort SerialNumberSensaGuard;
        }
        [ProtoContract]
        public class Values
        {
            [ProtoMember(1)]
            public long Timestamp { get; set; }
            [ProtoMember(2)]
            public byte Val { get; set; }
            [ProtoMember(3)]
            public byte Avg1 { get; set; }
            [ProtoMember(4)]
            public byte Avg2 { get; set; }
            [ProtoMember(5)]
            public byte SumDyn1 { get; set; }
            [ProtoMember(6)]
            public byte SumDyn2 { get; set; }
        }
        public struct SGS
        {
            public Header header;
            public List<Values> values;
        }
    }


}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.