Search code examples
c#arraysbytereal-timenetduino

56 bytes and 99 problems to hold a date and number


I have a 56 byte register available on some eeprom that I'd like to store engine hours with. Currently I just use 3 bytes to increment a 60 second timer and then download the information (the number rarely exceeds 9999 minutes before it transmits).

The problem is that I need to associate a date with this. Every time the vehicle is started I need to start my hours recording, but I need to determine which hour that hour was incremented on.

So if I have a byte[56] array, what would the be the easiest way to store a date (or just an hour of the date), followed by a number, and be able to tell them apart?

For transmitting, I'd need a way to iterate through the array and extract the date or hour, and the hours count.

Any ideas for this would be great, thanks a ton.

End results on a report would look similar to:

06:00 - 38 minutes 09:00 - 60 minutes 10:00 - 60 minutes etc


Solution

  • Okay here is an idea of a scheme to fit all the data you need in your 56 bytes (in fact we can fit upto 11 dates and times into 56 bytes):

    Assuming you don't expect this system to last more than a thousand years we can define the first part of the year as i.e. year 2013 is split into two, the epoch and year.

    • Epoch: 5 bits (or one byte) allowing 0-31
    • Year: 7 bits (or one byte) allowing 0-99
    • Day: 9 bits (two bytes) allowing 0-365
    • Hour: 5 bits (one byte) allowing 0-24
    • Second:12bits (two bytes) allowing 0-3600

    Now you could simply use 7 bytes and increment the values of each and would allow you to store upto 8 dates and times but you could create a struct and bit bang the individual bits to compact it down further allowing you to cramm it into 40 bits (or 5 bytes) allwing you 11 dates.

    You could also drop the epoch if you are really cramming but the above scheme will allow you to work with dates upto 3199.

    I am sure there are other and more compact ways i.e. number of milliseconds since 01.01.1970 upto say a few years in the future might reduce it by a few bits but reduce the longevity of your code but I haven't had a look at the actual values.

    Some example code (Have updated to use BitArray as bool is internally a byte(?!) but BitArray is actually bits... Very important in OPS case.:

    OP should note that I believe you are wanting to store the amounts of minutes driven in each hour BUT this would then require a whole lot more space (a record for each hour they have driven in or a start and stop record for each day indicating the minute they started and stopped (a stop has to come after a start afterall). The code below will allow you to record how many minutes have been driven in a given day.

    using System;
    using System.Collections;
    
    namespace BitBangingDate
    {
        class Program
        {
            static void Main(string[] args)
            {
                CompactDateManipulator x = new CompactDateManipulator();
                Console.WriteLine(x.ToString());
                x.Month = 7;
                x.Day = 27;
                x.Minute = 1234;
                Console.WriteLine(x.ToString());
    
                var bitArr = x.GetCompactedArray();
    
                CompactDateManipulator x1 = new CompactDateManipulator();//create new blank date to test whether can be reiitialised from BitArray
    
                x1.ReinitialiseDateFromBitArray(bitArr);
    
                Console.WriteLine(x1.ToString());
            }
        }
    
        class CompactDateManipulator
        {
            CompactDate _date = new CompactDate();
    
            public int Month
            {
                get
                {
                    return BoolArrayToInt(_date.month);
                }
                set
                {
                    IntToBoolArray(ref _date.month, value);
                }
            }
            public int Day
            {
                get
                {
                    return BoolArrayToInt(_date.day);
                }
                set
                {
                    IntToBoolArray(ref _date.day, value);
                }
            }
            public int Minute
            {
                get
                {
                    return BoolArrayToInt(_date.minute);
                }
                set
                {
                    IntToBoolArray(ref _date.minute, value);
                }
            }
    
            public BitArray GetCompactedArray()
            {
                return _date.GetFullArray();
            }
    
            public void ReinitialiseDateFromBitArray(BitArray arr)
            {
                _date.SetDate(arr);
            }
    
            //utility methods
            void IntToBoolArray(ref bool[] bits, int input)
            {
                var len = bits.Length;
                for (int i = 0; i < len; i++)
                {
                    bits[i] = (input & 1) == 1 ? true : false;
                    input >>= 1;
                }
            }
            int BoolArrayToInt(bool[] bits)
            {
                if (bits.Length > 32) throw new ArgumentException("Can only fit 32 bits in a int");
                int r = 0;
                for (int i = 0; i < bits.Length; i++)
                {
                    if (bits[i]) r |= 1 << i;
                }
                return r;
            }
            public override string ToString()
            {
                return String.Format("Stored Date mm/dd/ss: {0}/{1}/{2}", Month, Day, Minute);
            }
        }
    
        class CompactDate
        {
            //Layout  Month(5)    Day(9)     Minute (12)
            //        11111       111111111  111111111111 
            public bool[] month = new bool[5];
            public bool[] day = new bool[9];
            public bool[] minute = new bool[12];
            public BitArray GetFullArray()
            {
                int fullLen = month.Length + day.Length + minute.Length;
                BitArray full = new BitArray(fullLen);
                int index = 0;
                for (int i = 0; i < month.Length; i++,index++)
                {
                    full.Set(index,month[i]);
                }
                for (int i = 0; i < day.Length; i++, index++)
                {
                    full.Set(index, day[i]);
                }
                for (int i = 0; i < minute.Length; i++, index++)
                {
                    full.Set(index, minute[i]);
                }
                return full;
            }
            public void SetDate(BitArray arr)
            {
                int index = 0;
                for (int i = 0; i < month.Length; i++, index++)
                {
                    month[i] = arr.Get(index);
                }
                for (int i = 0; i < day.Length; i++, index++)
                {
                    day[i] = arr.Get(index);
                }
                for (int i = 0; i < minute.Length; i++, index++)
                {
                    minute[i] = arr.Get(index);
                }
            }
        }
    }