Author Topic: How to measure elapsed time  (Read 318 times)

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
How to measure elapsed time
« on: August 28, 2016, 05:30:28 pm »
Is there a function like the Arduino millis or micros function?

I'm asking so that I can time events, ie store millis for event, then if it happens again within a window of time take action.

I realize there is Device.Uptime() but that only gives a resolution of seconds.

Thanks,

Share on Facebook Share on Twitter


mc-John

  • Global Moderator
  • Full Member
  • *****
  • Posts: 212
    • View Profile
Re: How to measure elapsed time
« Reply #1 on: August 28, 2016, 10:26:47 pm »
This is a difficult question. mc-OS keeps the time in cycles (62.5 nanoSec) and from there it is calculated in microSec, milliSec and Seconds. The issue is that we don't support the Long datatype yet. Even in millisecond the timer overflows every 24 days. (In microSeconds it is only 35 Minutes.)

There are a number of options that can solve this.
  • Return only the low 31 bits and let the developer compare them
  • Build a quick and dirty Long type
  • Wait until we have the Long type in the product

I understand the importance of the functionality so I will discuss it with the team.

-John-

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: How to measure elapsed time
« Reply #2 on: August 28, 2016, 10:50:47 pm »
Right now I'm not too worried about timing 24 day periods, I'm more looking at motion events within a few seconds. Device.uptime() gives me granularity of 1 second, and the debounce register in the accelerometer is good only for debouncing really.

I'm looking at events occurring within a few milli or micro seconds, to a few second (minutes at most).

So I would vote for option 1 for the moment.

Thanks for the quick reply.

mc-John

  • Global Moderator
  • Full Member
  • *****
  • Posts: 212
    • View Profile
Re: How to measure elapsed time
« Reply #3 on: August 31, 2016, 09:05:56 am »
We have implemented (quick and dirty) this functionality with Device.GetTimeSpan(). It is decribe in the release notes. Try it out and see if it works for you

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: How to measure elapsed time
« Reply #4 on: August 31, 2016, 10:47:04 am »
I saw it, Thanks!

I'll try it out when I have all the kinks worked out of 7-368 (I assume this is required).

Nick_W

  • Full Member
  • ***
  • Posts: 215
    • View Profile
Re: How to measure elapsed time
« Reply #5 on: September 02, 2016, 04:39:21 pm »
Update:

I have used the new function Device.GetTimeSpan() in a couple of places now, and it seems to work well. That said, there are some drawbacks:

1) You can only use it once in each program including libraries. I have used it in a device library, which may be a problem, as that means you can't use it anywhere else (and could accidentally include the library in a program that already uses it).
2) You have to do a test for > 0 as it returns -1 if it overflows, this makes programming award.

This is an example of where i have used it:

Code: [Select]
    Shared Event AccelerometerInt1()
        Dim int_source As Byte = accel.readIntSource()
        If (int_source & MMA8652.SRC_TRANS) = MMA8652.SRC_TRANS Then
            'Transient interrupt occured
            If (accel.readTransientSource() & MMA8652.TEA) = MMA8652.TEA Then
                'Any Transient Occured
                LedGreen = True
                If ReedSwitch = False Then //If door is closed
                    //if more than 10 seconds since Knock last triggered, and more than 5 seconds since door closed
                    If (Device.Uptime() - TimeSinceKnockTriggered > 10) And (Device.Uptime() - TimeSinceDoorClosed > 5) Then
                        Dim timeSinceLastTransient As Integer = Device.GetTimeSpan()
                        'If at least two transients within 0.5 seconds
                        If timeSinceLastTransient < 500000 And timeSinceLastTransient > 0 Then
                            TimeSinceKnockTriggered = Device.Uptime()
                            MQTT.Publish("Doorknock", True)
                        End If
                    End If
                End If
                LedGreen = False
            End If
        End If
    End Event
   
    Shared Event ReedSwitchChanged()
        Thread.Sleep(500000)
        Thread.ClearHardwareEvent()
        LedGreen = True
        Dim Door_Status As Boolean = ReedSwitch
        If Door_Status = False Then
            TimeSinceDoorClosed = Device.Uptime()
        End If
        If Publish_data Then
            MQTT.Publish("Door", Door_Status)
        End If
        MQTT.BeaconPublish(dataType.DOOR, Door_Status)
        LedGreen = False
    End Event

You can see that I'm using Device.Uptime() as a coarse millis equivalent, to time events over 1 second in duration. The function Device.GetTimeSpan() is used to time sub 1 second events (this is from a door sensor program to detect door open/close and knocking).
You can see I have to test for 0, otherwise if the duration was long, the routine would return -1 and falsely trigger the door knock event. See point 2) above.

In another application, I included it in the BME280 library, like this:

Code: [Select]
    Public Sub TakeReading()
        Dim conversion_time As Integer = getConversionTime()
        If Device.GetTimeSpan() > conversion_time Then //if time since last run is more than conversion time, take new reading
            write8(REGISTER_CONTROL, temp_press_oversample) //take reading
            Thread.Sleep(conversion_time) // wait ConversionTime for reading
        End If
    End Sub

This prevents subroutines which call getTemperature() or getHumidity() (which in turn calls getTemperature()) from requesting multiple readings one after the other. If the request is generated within the timespan it takes for a reading, the request for a new reading is ignored (and the cached values will be used). This is the easiest way to do this, as the conversion time ranges from a few ms to 2.1s (using default settings it's 69ms).

I would have liked to add it to the readAll() function, which reads the values (in burst mode) from the device registers, to prevent re-reading of values already stored in the class, but see 1) above. This would save some small amount of power, but the time saving using it in the above routine is significant, so I used it there.

Assuming this is a temporary function, until a long datatype is available, it serves it's purpose. I will update my code when a real millis or micros function is available.

Thanks for implementing this so quickly.

mc-John

  • Global Moderator
  • Full Member
  • *****
  • Posts: 212
    • View Profile
Re: How to measure elapsed time
« Reply #6 on: September 07, 2016, 10:52:20 am »
Great that it works for you.

I can see that only one version could be a problem. We will change this in one of the next releases.

-John-