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
Revision 9:79633fe7d95b, committed 2017-06-09
- Comitter:
- andriym
- Date:
- Fri Jun 09 13:32:48 2017 +0000
- Parent:
- 8:5d17ff4f9c23
- Commit message:
- Simplified version (removed semaphore and rollover check timer).
Changed in this revision
--- a/Timer64.cpp Tue Apr 05 19:07:09 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ - /* - * 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. - */ - -#include "Timer64.h" -#include "ticker_api.h" -#include "us_ticker_api.h" - -Timer64::Timer64() : - _timerInitialized(false), - _timerRunning(false), - _tickerStartTimeUsec(0u), - _totalTimeUsec(0llu), - _ticker_data(get_us_ticker_data()), - _rollOverCheckTimer(NULL), - _rollOverCheckTimerPeriodInMsec(TIMER64_DEFAULT_ROLLOVER_CHECK_IN_MSECS), - _sem(NULL) -{ - ; -} - -Timer64::~Timer64() -{ - release(); -} - -int Timer64::init(uint32_t rolloverCheckTimeInMsec) -{ - if (_timerInitialized) - { - return(TIMER64_WARNING_ALREADY_INITIALIZED); - } - - if (rolloverCheckTimeInMsec < TIMER64_MIN_ROLLOVER_CHECK_IN_MSECS) - { - rolloverCheckTimeInMsec = TIMER64_MIN_ROLLOVER_CHECK_IN_MSECS; - } - else if (rolloverCheckTimeInMsec > TIMER64_MAX_ROLLOVER_CHECK_IN_MSECS) - { - rolloverCheckTimeInMsec = TIMER64_MAX_ROLLOVER_CHECK_IN_MSECS; - } - - _timerRunning = false; - _tickerStartTimeUsec = 0u; - _totalTimeUsec = 0llu; - _rollOverCheckTimerPeriodInMsec = rolloverCheckTimeInMsec; - _rollOverCheckTimer = new RtosTimer(_rollOverCheck, osTimerPeriodic, this); - _sem = new Semaphore(1); - _timerInitialized = true; - - return(TIMER64_OK); -} - -int Timer64::release(void) -{ - if (!_timerInitialized) - { - return(TIMER64_WARNING_ALREADY_RELEASED); - } - - if (_timerRunning) - { - stop(); - } - - _tickerStartTimeUsec = 0u; - _totalTimeUsec = 0llu; - _timerInitialized = false; - _rollOverCheckTimer->stop(); - delete _rollOverCheckTimer; - _rollOverCheckTimer = NULL; - delete _sem; - _sem = NULL; - - return(TIMER64_OK); -} - -int Timer64::start(void) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else if (_timerRunning) - { - status = TIMER64_WARNING_ALREADY_RUNNING; - } - else - { - _tickerStartTimeUsec = ticker_read(_ticker_data); - _timerRunning = true; - _rollOverCheckTimer->start(_rollOverCheckTimerPeriodInMsec); - } - } - _sem->release(); - - return(status); -} - -int Timer64::stop(void) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else if (!_timerRunning) - { - status = TIMER64_WARNING_ALREADY_STOPPED; - } - else - { - _read_us(this); - _timerRunning = false; - _rollOverCheckTimer->stop(); - } - } - _sem->release(); - - return(status); -} - -int Timer64::reset(void) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else - { - if (_timerRunning) - { - _tickerStartTimeUsec = ticker_read(_ticker_data); - _rollOverCheckTimer->start(_rollOverCheckTimerPeriodInMsec); - } - - _totalTimeUsec = 0llu; - } - } - _sem->release(); - - return(status); -} - -int Timer64::read_us(uint64_t* timeInUsec) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else if (timeInUsec == NULL) - { - status = TIMER64_ERROR_NULL_POINTER; - } - else - { - if (_timerRunning) - { - *timeInUsec = _read_us(this); - } - else - { - *timeInUsec = _totalTimeUsec; - } - } - } - _sem->release(); - - return(status); -} - -int Timer64::read_ms(uint64_t* timeInMsec) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else if (timeInMsec == NULL) - { - status = TIMER64_ERROR_NULL_POINTER; - } - else - { - if (_timerRunning) - { - *timeInMsec = _read_us(this)/1000LU; - } - else - { - *timeInMsec = _totalTimeUsec/1000LU; - } - } - } - _sem->release(); - - return(status); -} - -int Timer64::read(double* timeInSec) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else if (timeInSec == NULL) - { - status = TIMER64_ERROR_NULL_POINTER; - } - else - { - if (_timerRunning) - { - *timeInSec = (double)_read_us(this)/1000000.0L; - } - else - { - *timeInSec = (double)_totalTimeUsec/1000000.0L; - } - } - } - _sem->release(); - - return(status); -} - -int Timer64::isRunning(bool* running) -{ - int status = TIMER64_OK; - - _sem->wait(); - { - if (!_timerInitialized) - { - status = TIMER64_ERROR_NOT_INITIALIZED; - } - else - { - *running = _timerRunning; - } - } - _sem->release(); - - return(status); -} - -void Timer64::_rollOverCheck(void const* args) -{ - Timer64* timer = (Timer64*)args; - timer->_read_us(timer); - return; -} - -uint64_t Timer64::_read_us(void const* args) -{ - Timer64* timer = (Timer64*)args; - timestamp_t ticker_current_timeUsec = ticker_read(timer->_ticker_data); - - // check for ticker time rollover - - if (ticker_current_timeUsec >= timer->_tickerStartTimeUsec) - { - timer->_totalTimeUsec += (uint64_t)(ticker_current_timeUsec - timer->_tickerStartTimeUsec); - } - else - { - // rollover! - timer->_totalTimeUsec += (uint64_t)(4294967296U - timer->_tickerStartTimeUsec) + (uint64_t)ticker_current_timeUsec; - - } - - timer->_rollOverCheckTimer->start(timer->_rollOverCheckTimerPeriodInMsec); - timer->_tickerStartTimeUsec = ticker_current_timeUsec; - return(timer->_totalTimeUsec); -} -
--- a/Timer64.h Tue Apr 05 19:07:09 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,205 +0,0 @@ -/* 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 __TIMER64__ -#define __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 //__TIMER64__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Timer64Simple.cpp Fri Jun 09 13:32:48 2017 +0000 @@ -0,0 +1,112 @@ + /* + * 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. + */ + +#include "Timer64Simple.h" +#include "ticker_api.h" +#include "us_ticker_api.h" + +Timer64Simple::Timer64Simple() : + _timerRunning(false), + _tickerLastTimeUsec(0u), + _totalTimeUsec(TIMER64_TOTAL_TIME_INIT), + _ticker_data(get_us_ticker_data()) +{ + ; +} + +Timer64Simple::~Timer64Simple() +{ + ; +} + +void Timer64Simple::start(void) +{ + if (!_timerRunning) + { + _tickerLastTimeUsec = ticker_read(_ticker_data); + _timerRunning = true; + } +} + +void Timer64Simple::stop(void) +{ + if (_timerRunning) + { + _read_us(); + _timerRunning = false; + } +} + +void Timer64Simple::reset(void) +{ + if (_timerRunning) + { + _tickerLastTimeUsec = ticker_read(_ticker_data); + } + + _totalTimeUsec = TIMER64_TOTAL_TIME_INIT; +} + +uint64_t Timer64Simple::read_us() +{ + if (_timerRunning) + { + return _read_us(); + } + return _totalTimeUsec; +} + +uint64_t Timer64Simple::read_ms() +{ + if (_timerRunning) + { + return _read_us()/1000LU; + } + return _totalTimeUsec/1000LU; +} + +double Timer64Simple::read() +{ + if (_timerRunning) + { + return (double)_read_us()/1000000.0L; + } + return (double)_totalTimeUsec/1000000.0L; +} + +bool Timer64Simple::is_running() +{ + return(_timerRunning); +} + +uint64_t Timer64Simple::_read_us() +{ + timestamp_t tickerCurrentTimeUsec = ticker_read(_ticker_data); + + // check for ticker time rollover + + if (tickerCurrentTimeUsec >= _tickerLastTimeUsec) + { + _totalTimeUsec += (uint64_t)(tickerCurrentTimeUsec - _tickerLastTimeUsec); + } + else + { + // rollover! + _totalTimeUsec += (uint64_t)(4294967296U - _tickerLastTimeUsec) + (uint64_t)tickerCurrentTimeUsec; + + } + + _tickerLastTimeUsec = tickerCurrentTimeUsec; + return(_totalTimeUsec); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Timer64Simple.h Fri Jun 09 13:32:48 2017 +0000 @@ -0,0 +1,129 @@ +/* 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, 2016 + * <ThomasEDoyle@gmail.com> + * + * Modified by Andriy Makukha, 2017 + * <andriy@mzjtechnology.com> + * Shenzhen MZJ Technology, Co. + */ + +#ifndef __TIMER64SIMPLE__ +#define __TIMER64SIMPLE__ + +#include "platform.h" +#include "ticker_api.h" +#include <stdint.h> + +#define TIMER64_TOTAL_TIME_INIT 0llu + +/** Timer64Simple class + * Used to define a 64 bit timer that is NOT thread safe. The Timer64Simple + * behaves in a similiar fashion to the mbed Timer class with the most notable + * exception that the Timer64Simple will not rollover after 2^31 microseconds + * (approximately 35.8 minutes). The Timer64Simple extends the rollover time + * to 2^64 microseconds (more than 584,000 years!) + * + * Unlike the Timer64 class by Tom Doyle, Timer64Simple class is simplified to + * be NOT thread safe. It is also assumed that read(), read_ms() or read_us() + * functions are called at least once per 17 minutes (preferably faster!) + * while the timer is running (since this class lacks internal rollover check + * timer). In fact, Timer64Simple is simplifed to the point where it's almost + * trivial. + * + * If you need smarter version, check out the original code here: + * https://developer.mbed.org/users/tedoyle/code/Timer64/ + * + * Demo program: + * @code + * #include "mbed.h" + * #include "Timer64Simple.h" + * + * Timer64Simple timer64; + * + * int main() + * { + * timer64.start(); + * wait_ms(100); + * timer64.stop(); + * wait_ms(100); + * printf("Test - Elapsed time = %llu usec\r\n", timer64.read_us()); // %llu -- unsigned long long int + * + * timer64.reset(); + * timer64.start(); + * while (1) + * { + * wait(60); // wait 1 minute + * printf("Time = %llu ms\r\n", timer64.read_ms()); + * } + * } + * @endcode +*/ + +class Timer64Simple +{ + +public: + Timer64Simple(); + ~Timer64Simple(); + + /** Start the timer */ + void start(void); + + /** Stop the timer */ + void stop(void); + + /** Reset the timer */ + void reset(void); + + /** Read the timer value in microseconds + * + * @returns + * timeInUsec - current time in microseconds + */ + uint64_t read_us(void); + + /** Read the timer value in milliseconds + * + * @returns + * timeInMsec - current time in milliseconds + */ + uint64_t read_ms(void); + + /** Read the timer value in seconds + * + * @returns + * timeInMsec - current time in seconds + */ + double read(void); + + /** Check to see if timer is running + * + * @returns + * boolean running status + */ + bool is_running(); + +private: + bool _timerRunning; // whether the timer is running + timestamp_t _tickerLastTimeUsec; // the start time of the latest slice + uint64_t _totalTimeUsec; // any accumulated time from previous slices + const ticker_data_t *_ticker_data; + + uint64_t _read_us(void); +}; + +#endif //__TIMER64SIMPLE__