Friday, March 28, 2014

c# update clock display once per second

For my heating controls project I display a clock on my main screen. It is just a label which I set the time in. Previously I had used a System.Threading.Timer with an interval of 50ms to do the updates, and this works fine, but on mono on the Raspberry Pi it takes up too much CPU. Top was showing that the process was taking 8-10% of the CPU when at idle.

The problem is that if you set a timer to run every 1000ms, sometimes expirations will be slightly longer, meaning that if you watch the clock every now and then it will skip displaying a second. If you go for something like 900ms update, that doesn't work either, you get 9 short seconds and one long one.

Googling turned up this stackoverflow article, and it contains the answer that got me started, but I wanted it to be a little more versatile. I wanted a timer that I could configure to fire every 'x' ms, and I could either set it to 1000, for each second, or if that was still too CPU hungry I could set it to 60000, which would only update the clock once per minute.

In my form_load I initialise the timer.

            clockUpdateTimer = new System.Timers.Timer();
            clockUpdateTimer.Elapsed += clockTimer_Elapsed;
            clockUpdateTimer.Interval = 100;
            clockUpdateTimer.Start();

I set the initial interval to 100ms which means my clockTimer_Elapsed() method gets its first call pretty much straight away.


        private long updateMainScreenIntervalMs = 1000;

        private void clockTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            clockUpdateTimer.Stop();
            TimerCallback(sender);
            //start the timer to run until 200ms after the next clock second boundary
            long timeInMs = System.DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            long wait = (updateMainScreenIntervalMs * (timeInMs / updateMainScreenIntervalMs + 1)) - timeInMs;
            //Debug.WriteLine("wait ms: " + wait);
            clockUpdateTimer.Interval = (int)wait + 200;
            clockUpdateTimer.Start();
        }

This method firstly stops the existing timer, and then calls my callback method to update the label (TimerCallback()). Next I get timeInMs which is the current system time in milliseconds. Then I do some maths which essentially finds the nearest full cycle of time, and subtracting the current time from this value figures out how long we have to wait until this time. 
Then I start the timer with that time. For a 1 second interval it typically waits about 750ms. 

Any improvements welcome, if it helps you please post a comment!

Kitesurfing - Friday 28th March 2014

I got to Benone just after an early exit to work, so I was there for about 4:20. It was blowing about 25 on my wind meter, so I set up the 9. However, after a couple of runs showed me that it was too small. The 12 was too big, but I'd rather be overpowered than underpowered.

It was a great session, long flats, nice waves. The only funny thing was the direction was East, which meant I was going the opposite way to normal, but it was still good practice, and it meant that I was able to ride a little toeside out over the breaking waves.

The water is still cold, and it felt even colder when I took my wetsuit socks off, feet were freezing, but at least I could feel the board. I really don't like having something on my feet, I find it very tricky.

Monday, March 24, 2014

Heating Touchscreen Screen Captures

I have made a few updates to my touchscreen client, and one of those has been a bit of work on the visual aspect. A few screenshots are posted below. (the windows are all border-less on mono, but display with borders for debugging on Windows)


Main Screen


PIN input form


Program Entry


Time entry for a specific program


System settings dialog (not themed)

Wednesday, March 12, 2014

How to hold modules from apt-get update

Recently I had to do an update, but the bootloader update broke my touchscreen driver. So I wanted to do an update without updating the bootloader, so I had to run this command:

 sudo apt-mark hold libraspberrypi-bin libraspberrypi-dev libraspberrypi-doc libraspberrypi0 raspberrypi-bootloader