Simple 64-bit timer for mbed. It is a drastically simplified version of Timer64 class by Tom Doyle. It is meant to be used in single-thread applications, where timer is used frequently, while standard 32-bit Timer is not enough.

Fork of Timer64 by Tom Doyle

Timer64.h

Committer:
tedoyle
Date:
2016-03-28
Revision:
5:e2a2d9790e36
Parent:
4:9ca673a83acb
Child:
7:381bafbb2218

File content as of revision 5:e2a2d9790e36:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2016 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modified by Tom Doyle    <ThomasEDoyle@gmail.com>
 *
 */
 
#ifndef __NEW_TIMER64__
#define __NEW_TIMER64__

#include "platform.h"
#include "ticker_api.h"
#include <stdint.h>
#include "rtos.h"

#define TIMER64_OK                                  0

#define TIMER64_ERROR_NOT_INITIALIZED               -1
#define TIMER64_ERROR_NULL_POINTER                  -2

#define TIMER64_WARNING_ALREADY_INITIALIZED         1
#define TIMER64_WARNING_ALREADY_RUNNING             2
#define TIMER64_WARNING_ALREADY_STOPPED             3
#define TIMER64_WARNING_ALREADY_RELEASED            4

#define TIMER64_DEFAULT_ROLLOVER_CHECK_IN_MSECS     30000
#define TIMER64_MIN_ROLLOVER_CHECK_IN_MSECS         1000
#define TIMER64_MAX_ROLLOVER_CHECK_IN_MSECS         65535

/** Timer64 class
 *  Used to define a 64 bit timer64 that is thread safe.  The Timer64 behaves in a 
 *  similiar fashion to the mbed Timer class with the most notable exception that 
 *  the Timer64 will not rollover after 2^31 microseconds (approximately 35.8 minutes).
 *  The Timer64 extends the rollover time to 2^64 microseconds (approximately 585,000 years!)
 *
 *  The Timer64 class is also designed to be thread safe. The following functions can be 
 *  called from any thread after the class is instaniated and initialized:
 *  
 *  - start()
 *  - stop()
 *  - reset()
 *  - read_us()
 *  - read_ms()
 *  - read()
 *  - reset()
 *  - isRunning()
 *
 *  It is to be noted that the init() and release() methods need to be called from the same thread.
 *
 *  Give the Timer64 library a try and let me know if it works for you. Will gladly take suggestions
 *  on how to make it better.
 *
 *  Simple Example
 *  @code
 *  #include "mbed.h"
 *  #include "rtos.h"
 *  #include "Timer64.h"
 *
 * Timer64 timer64;
 *
 *   int main()
 *   {
 *      uint64_t timeInUsec;
 *      timer64.init();
 *      timer64.start();
 *      Thread::wait(100);
 *      timer64.stop();
 *      timer64.read_us(&timeInUsec);
 *      printf("Test - Elapsed time = %llu usec\n\n", timeInUsec);
 *      timer64.reset();
 *      timer64.release();
 *       
 *      while (1)
 *      {
 *          Thread::wait(1000);
 *      }
 *  }
 *  @endcode
*/
 class Timer64
{

public:
    Timer64();
    ~Timer64();

    /** Initialize the timer - this must be called before the timer can be used
     *  
     *  @param rolloverCheckTimeInMsecc specifies how ofter a rollover check is performed.
     *      This parameter is bounded by TIMER64_MIN_ROLLOVER_CHECK_IN_MSECS and 
     *      TIMER64_MIN_ROLLOVER_CHECK_IN_MSECS with a default value of
     *      TIMER64_MIN_ROLLOVER_CHECK_IN_MSECS
     *
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_WARNING_ALREADY_INITIALIZED
     */
    int init(uint32_t rolloverCheckTimeInMsecc = TIMER64_DEFAULT_ROLLOVER_CHECK_IN_MSECS);

    /** Release the timer - must be called from the same thread calling init()
     *  
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_WARNING_ALREADY_RELEASED
     */
    int release(void);

    /** Start the timer - this method is thread safe
     *  
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED,
     *      TIMER64_WARNING_ALREADY_RUNNING
     */
    int start(void);

    /** Stop the timer - this method is thread safe
     *  
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED,
     *      TIMER64_WARNING_ALREADY_STOPPED
     */
    int stop(void);

    /** Reset the timer - this method is thread safe
     *  
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED
     */
    int reset(void);

    /** Read the timer value in microseconds - this method is thread safe
     *  
     *  @param timeInUsec specifies a pointer to a uint64_t where to save the current time in microseconds
     *
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED,
     *      TIMER64_ERROR_NULL_POINTER
     */
    int read_us(uint64_t* timeInUsec = NULL);

    /** Read the timer value in milliseconds - this method is thread safe
     *  
     *  @param timeInMsec specifies a pointer to a uint64_t where to save the current time in milliseconds
     *
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED,
     *      TIMER64_ERROR_NULL_POINTER
     */
    int read_ms(uint64_t* timeInMsec = NULL);

    /** Read the timer value in seconds - this method is thread safe
     *  
     *  @param timeInMsec specifies a pointer to a double where to save the current time in seconds
     *
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED,
     *      TIMER64_ERROR_NULL_POINTER,
     */
    int read(double* timeInSec = NULL);
    
    /** Check to see if timer is running - this method is thread safe
     *  
     *  @param running specifies a pointer to a bool where to save the running status
     *
     *  @returns
     *      TIMER64_OK,
     *      TIMER64_ERROR_NOT_INITIALIZED,
     *      TIMER64_ERROR_NULL_POINTER
     */
    int isRunning(bool* running);

private:
    bool _timerInitialized;
    bool _timerRunning;                 // whether the timer is running
    timestamp_t _tickerStartTimeUsec;   // the start time of the latest slice
    uint64_t _totalTimeUsec;            // any accumulated time from previous slices
    const ticker_data_t *_ticker_data;
    RtosTimer* _rollOverCheckTimer;
    uint32_t _rollOverCheckTimerPeriodInMsec;
    Semaphore* _sem;
    
    static void _rollOverCheck(void const* args);
    static uint64_t _read_us(void const* args);
};

#endif