001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
Min/Max


















Min/Max








































































































































































































/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* DEV_NOTE: this file is not intended to be used directly by any user code!

i.e. do not #include <omni/xxx_impl.hxx> and do not compile this source directly.
this file is included directly in other source.
*/

// so as not to accidentally build this file with the source
// these macros are defined in chrono
#if !defined(OMNI_TIMER_T_FW) || !defined(OMNI_TMR_ALOCK_FW) || !defined(OMNI_TMR_MLOCK_FW) || !defined(OMNI_TMR_ULOCK_FW)
    #error "invalid preprocessor directive detected"
#endif

#if !defined(OMNI_TIMER_EX_STOP_FW)
    #define OMNI_TIMER_EX_STOP_FW
#endif

#if !defined(OMNI_TIMER_EX_RUN_BEG_FW)
    #define OMNI_TIMER_EX_RUN_BEG_FW
#endif

#if !defined(OMNI_TIMER_EX_RUN_END_FW)
    #define OMNI_TIMER_EX_RUN_END_FW
#endif

omni::chrono::OMNI_TIMER_T_FW::~OMNI_TIMER_T_FW()
{
    OMNI_TRY_FW
    OMNI_DTOR_FW
    this->stop();
    OMNI_CATCH_FW
    OMNI_D5_FW("destroyed");
}

bool omni::chrono::OMNI_TIMER_T_FW::auto_reset() const
{
    OMNI_TMR_ALOCK_FW
    return OMNI_VAL_HAS_FLAG_BIT(this->m_status, OMNI_TIMER_AUTO_FLAG_FW);
}

uint32_t omni::chrono::OMNI_TIMER_T_FW::interval() const
{
    OMNI_TMR_ALOCK_FW
    return static_cast<uint32_t>(this->m_int);
}

bool omni::chrono::OMNI_TIMER_T_FW::is_running() const
{
    OMNI_TMR_ALOCK_FW
    return OMNI_VAL_HAS_FLAG_BIT(this->m_status, OMNI_TIMER_RUN_FLAG_FW);
}

void omni::chrono::OMNI_TIMER_T_FW::reset()
{
    this->stop();
    this->start();
}

void omni::chrono::OMNI_TIMER_T_FW::set_auto_reset(bool autoreset)
{
    OMNI_TMR_ALOCK_FW
    if (autoreset) {
        OMNI_VAL_SET_FLAG_BIT(this->m_status, OMNI_TIMER_AUTO_FLAG_FW);
    } else {
        OMNI_VAL_UNSET_FLAG_BIT(this->m_status, OMNI_TIMER_AUTO_FLAG_FW);
    }
}

void omni::chrono::OMNI_TIMER_T_FW::set_interval(uint32_t ival)
{
    OMNI_TMR_ALOCK_FW
    this->m_int = ival;
}

void omni::chrono::OMNI_TIMER_T_FW::start()
{
    this->start(0);
}

void omni::chrono::OMNI_TIMER_T_FW::start(uint32_t delay)
{
    if (!this->is_running()) {
        { // error check scope (for auto mutex)
            OMNI_TMR_ALOCK_FW
            if (!this->tick) {
                OMNI_ERR_RET_FW(OMNI_INVALID_DELEGATE_FUNC_STR, omni::exceptions::invalid_delegate())
            }
            if (this->m_int == 0) {
                OMNI_ERRV_RET_FW("Start error: ", OMNI_INDEX_OOR_STR, omni::exceptions::index_out_of_range())
            }
            OMNI_VAL_UNSET_FLAG_BIT(this->m_status, OMNI_TIMER_STOP_FLAG_FW);
        }
        if (delay == 0) {
            this->m_thread =
                omni::sync::allocate_basic_thread<omni::chrono::OMNI_TIMER_T_FW,
                                                 &omni::chrono::OMNI_TIMER_T_FW::_run>(*this);
        } else {
            this->m_thread =
                omni::sync::allocate_basic_thread_parameterized<
                    omni::chrono::OMNI_TIMER_T_FW,
                    &omni::chrono::OMNI_TIMER_T_FW::_run_delayed>
                    (*this, &delay);
        }
        OMNI_SLEEP_INIT();
        while (!this->is_running()) { OMNI_SLEEP1(); }
    }
    #if defined(OMNI_DBG_L2)
    else { OMNI_D2_FW("The timer is already running"); }
    #endif
}

void omni::chrono::OMNI_TIMER_T_FW::stop()
{
    this->stop(0, true);
}

void omni::chrono::OMNI_TIMER_T_FW::stop(uint32_t join_timeout)
{
    this->stop(join_timeout, true);
}

void omni::chrono::OMNI_TIMER_T_FW::stop(uint32_t join_timeout, bool kill_on_timeout)
{
    if (this->is_running()) {
        OMNI_TMR_MLOCK_FW
        OMNI_VAL_SET_FLAG_BIT(this->m_status, OMNI_TIMER_STOP_FLAG_FW);
        OMNI_TMR_ULOCK_FW
        if (join_timeout == 0) {
            this->m_thread->join();
        } else {
            this->m_thread->join(join_timeout);
            if (kill_on_timeout && this->is_running()) { // still running?
                OMNI_D2_FW("timer still running after stop request, killing thread...");
                this->m_thread->kill();
            }
        }
        OMNI_TIMER_EX_STOP_FW
        OMNI_FREE(this->m_thread);
    }
    #if defined(OMNI_DBG_L2)
    else { OMNI_D2_FW("the timer is not running"); }
    #endif
}

void omni::chrono::OMNI_TIMER_T_FW::_run_delayed(omni::sync::thread_arg_t dly) // only called if delay > 0
{
    uint32_t delay = *(static_cast<uint32_t*>(dly));
    OMNI_DV1_FW("timer thread: ", omni::sync::thread_id());
    OMNI_D2_FW("waiting to start, delay " << delay << "ms");
    OMNI_TMR_MLOCK_FW
    OMNI_VAL_SET_FLAG_BIT(this->m_status, OMNI_TIMER_RUN_FLAG_FW);
    OMNI_TMR_ULOCK_FW
    OMNI_SLEEP_INIT();
    omni::chrono::tick_t st = omni::chrono::monotonic_tick();
    while (!this->_stopreq() && (omni::chrono::elapsed_ms(st) < delay)) {
        OMNI_SLEEP1();
    }
    this->_do_run();
}

void omni::chrono::OMNI_TIMER_T_FW::_run()
{
    OMNI_DV1_FW("timer thread: ", omni::sync::thread_id());
    OMNI_D2_FW("start timer");
    OMNI_TMR_MLOCK_FW
    OMNI_VAL_SET_FLAG_BIT(this->m_status, OMNI_TIMER_RUN_FLAG_FW);
    OMNI_TMR_ULOCK_FW
    this->_do_run();
}

void omni::chrono::OMNI_TIMER_T_FW::_do_run()
{
    OMNI_TIMER_EX_RUN_BEG_FW
    omni::chrono::tick_t tickt;
    OMNI_SLEEP_INIT();
    omni::chrono::monotonic::initialize();
    do {
        if (this->_stopreq()) { break; }
        tickt = omni::chrono::monotonic_tick();
        while (omni::chrono::elapsed_ms(tickt) < this->interval()) {
                OMNI_SLEEP1();
                if (this->_stopreq()) { break; }
        }
        if (this->_stopreq()) { break; }
        this->_do_tick();
    } while (this->auto_reset());
    OMNI_TIMER_EX_RUN_END_FW
    OMNI_TMR_MLOCK_FW
    OMNI_VAL_UNSET_FLAG_BIT(this->m_status, OMNI_TIMER_RUN_FLAG_FW);
    OMNI_TMR_ULOCK_FW
}

bool omni::chrono::OMNI_TIMER_T_FW::_stopreq() const
{
    OMNI_TMR_ALOCK_FW
    return OMNI_VAL_HAS_FLAG_BIT(this->m_status, OMNI_TIMER_STOP_FLAG_FW);
}

#undef OMNI_TIMER_EX_STOP_FW
#undef OMNI_TIMER_EX_RUN_BEG_FW
#undef OMNI_TIMER_EX_RUN_END_FW