1

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

Daniel Minnaar
  • 5,865
  • 5
  • 31
  • 52

2 Answers2

1

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);
            }
        }
    }
}
Paul Sullivan
  • 2,865
  • 2
  • 19
  • 25
  • I don't think storing the entire date is necessary. All I need is the day, it's hour, and the amount of minutes accumulated in it. The best I have so far is to use just the Day and Hour, and the minutes count for it. Something like log[0] = 913 (09th day, 13th hour - 3 bytes), log[1] = 56 (56 minutes for the 13th hour - 1 byte). Then log[2] = 914, log[3] = 10, etc. This is still too inefficient because that means I'll use 4 bytes for every hour, which leaves me 14 hours to hold the data. I need at least a couple days worth. Am I going about this wrong? – Daniel Minnaar Jul 29 '13 at 06:39
  • see update for how to cram the bits. We can store the whole time in 26 bits (4 bytes) – Paul Sullivan Jul 29 '13 at 07:12
  • By 'Day' do you mean day of year or day of month (one requires 9 bits the other 4) – Paul Sullivan Jul 29 '13 at 07:17
  • Day of month :) So, maximum would 3124 (3 bytes) – Daniel Minnaar Jul 29 '13 at 09:27
  • I'll do some code for you this evening as I don't think you are grasping what I mean (31 days in a month is 5bits (just over a nibble)) – Paul Sullivan Jul 29 '13 at 11:20
  • @drminnaar have a look at the answer I have updated and given a working example. Please read the notes - I reckon you want a record of journeys in each hour of each day... This would consume too much memory so I think you will just have to settle for 'amount of minutes driven in each day' – Paul Sullivan Jul 29 '13 at 18:15
  • To trim it further we can break `minute` into blocks of say 5 minutes (driver was driving sometime between 12.00 and 12.05). This would reduce the size of the minute bit array... – Paul Sullivan Jul 29 '13 at 18:25
  • @drminnaar added code to store/retrieve as BitArray (which is actually bits unlike bools which internally in .net are stored as bytes...) – Paul Sullivan Jul 29 '13 at 19:59
0

You could represent the start time using minutes in case it doesn't start at an exact hour, so 24x60 = 1440 is the highest number you'd have to account for in start time. 1440 represented in binary is 0000010110100000 (2 bytes), so have the first elements 0-1 of the array represent the start time. Next, you say 9999 minutes is an acceptable upper limit for runtime which in binary is 0010011100001111 (2 bytes) so have array elements 2-3 represent runtime.

Taylor Tvrdy
  • 163
  • 1
  • 11