Welcome to mirror list, hosted at ThFree Co, Russian Federation.

SoftTimer.cpp « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8b0a5d7770b6df8611e25a94e6e7692c94f198eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
 * SoftTimer.cpp
 *
 *  Created on: 21 Jul 2017
 *      Author: David
 */

#include "SoftTimer.h"
#include "Platform.h"
#include "Movement/DDA.h"

SoftTimer * volatile SoftTimer::pendingList = nullptr;

SoftTimer::SoftTimer() : next(nullptr), callback(nullptr)
{
}

// Schedule a callback at a particular tick count, returning true if it was not scheduled because it is already due or imminent.
// There must be no callback already scheduled for this timer, else the linked list will get messed up. If in doubt, call CancelCallback before calling this.
bool SoftTimer::ScheduleCallback(Ticks when, Callback cb, void *param)
{
	whenDue = when;
	callback = cb;
	cbParam = param;

	const irqflags_t flags = cpu_irq_save();
	const Ticks now = GetTimerTicksNow();
	const int32_t howSoon = (int32_t)(when - now);
	SoftTimer** ppst = const_cast<SoftTimer**>(&pendingList);
	if (*ppst == nullptr || howSoon < (int32_t)((*ppst)->whenDue - now))
	{
		// No other callbacks are scheduled, or this one is due earlier than the first existing one
		if (Platform::ScheduleSoftTimerInterrupt(when))
		{
			cpu_irq_restore(flags);
			return true;
		}
	}
	else
	{
		while (*ppst != nullptr && (int32_t)((*ppst)->whenDue - now) < howSoon)
		{
			ppst = &((*ppst)->next);
		}
	}

	next = *ppst;
	*ppst = this;
	cpu_irq_restore(flags);
	return false;
}

// Cancel any scheduled callback for this timer. Harmless if there is no callback scheduled.
void SoftTimer::CancelCallback()
{
	const irqflags_t flags = cpu_irq_save();
	for (SoftTimer** ppst = const_cast<SoftTimer**>(&pendingList); *ppst != nullptr; ppst = &((*ppst)->next))
	{
		if (*ppst == this)
		{
			*ppst = this->next;		// unlink this from the pending list
			break;
		}
	}
	cpu_irq_restore(flags);
}

// Get the current tick count
/*static*/ SoftTimer::Ticks SoftTimer::GetTimerTicksNow()
{
	return Platform::GetInterruptClocks();
}

// Get the tick rate
/*static*/ SoftTimer::Ticks SoftTimer::GetTickRate()
{
	return DDA::stepClockRate;			// the software timer uses the same counter as the step timer
}

// ISR called from Platform. May sometimes get called prematurely.
/*static*/ void SoftTimer::Interrupt()
{
	for (;;)
	{
		SoftTimer * const tmr = pendingList;
		if (tmr == nullptr)
		{
			break;
		}

		// On the first iteration, the timer at the head of the list is probably expired.
		// Try to schedule another interrupt for it, if we get a true return then it has indeed expired and we need to execute the callback.
		// On subsequent iterations this just sets up the interrupt for the next timer that is due to expire.
		if (Platform::ScheduleSoftTimerInterrupt(tmr->whenDue))
		{
			pendingList = tmr->next;														// remove it from the pending list
			if (tmr->callback != nullptr && tmr->callback(tmr->cbParam, tmr->whenDue))		// execute its callback
			{
				// Schedule another callback for this timer
				SoftTimer** ppst = const_cast<SoftTimer**>(&pendingList);
				while (*ppst != nullptr && (int32_t)(tmr->whenDue - (*ppst)->whenDue) > 0)
				{
					ppst = &((*ppst)->next);
				}
				tmr->next = *ppst;
				*ppst = tmr;
			}
		}
		else
		{
			break;
		}
	}
}

// End