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

RTOSIface.h « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0e7d5afd3db395f39ffa2133edde4b0353019397 (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
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
/*
 * RTOS.h
 *
 *  Created on: 30 Mar 2018
 *      Author: David
 */

#ifndef SRC_RTOSIFACE_H_
#define SRC_RTOSIFACE_H_

#include <cstdint>

// Type declarations to hide the type-unsafe definitions in the FreeRTOS headers

class Task_undefined;					// this class is never defined
typedef Task_undefined *TaskHandle;

#ifdef RTOS
# include "FreeRTOS.h"
# include "task.h"
# include "semphr.h"
#else
# include "asf.h"
#endif

class Mutex
{
public:
	Mutex() { handle = nullptr; }

	void Create();
	bool Take(uint32_t timeout = TimeoutUnlimited) const;
	bool Release() const;
	TaskHandle GetHolder() const;

	static constexpr uint32_t TimeoutUnlimited = 0xFFFFFFFF;

	Mutex(const Mutex&) = delete;
	Mutex& operator=(const Mutex&) = delete;

private:

#ifdef RTOS
	SemaphoreHandle_t handle;
	StaticSemaphore_t storage;
#else
	void *handle;
#endif

};

#ifdef RTOS

class TaskBase
{
public:
	TaskBase() { handle = nullptr; }

	TaskHandle GetHandle() const { return static_cast<TaskHandle>(handle); }
	void Suspend() const { vTaskSuspend(handle); }
	const TaskBase *GetNext() const { return next; }

	TaskBase(const TaskBase&) = delete;
	TaskBase& operator=(const TaskBase&) = delete;

	static const TaskBase *GetTaskList() { return taskList; }

	static constexpr int SpinPriority = 1;			// priority for tasks that rarely block
	static constexpr int HeatPriority = 2;

protected:
	TaskHandle_t handle;
	TaskBase *next;
	StaticTask_t storage;

	static TaskBase *taskList;
};

template<unsigned int StackWords> class Task : public TaskBase
{
public:
	// The Create function assumes that only the main task creates other tasks, so we don't need a mutex to protect the task list
	void Create(TaskFunction_t pxTaskCode, const char * pcName, void *pvParameters, unsigned int uxPriority)
	{
		next = taskList;
		taskList = this;
		handle = xTaskCreateStatic(pxTaskCode, pcName, StackWords, pvParameters, uxPriority, stack, &storage);
	}

private:
	uint32_t stack[StackWords];
};

#endif

// Class to lock a mutex and automatically release it when it goes out of scope
// If we pass a null mutex handle to the Locker constructor, it means there is nothing to lock and we pretend the lock has been acquired.
class MutexLocker
{
public:
	MutexLocker(const Mutex *pm, uint32_t timeout = Mutex::TimeoutUnlimited);	// acquire lock
	MutexLocker(const Mutex& pm, uint32_t timeout = Mutex::TimeoutUnlimited);	// acquire lock
	void Release();															// release the lock early (else gets released by destructor)
	~MutexLocker();
	operator bool() const { return acquired; }

	MutexLocker(const MutexLocker&) = delete;
	MutexLocker& operator=(const MutexLocker&) = delete;

private:
	const Mutex *handle;
	bool acquired;
};

// Interface to RTOS or RTOS substitute
namespace RTOSIface
{
	TaskHandle GetCurrentTask();

#ifndef RTOS
	static volatile unsigned int interruptCriticalSectionNesting = 0;
#endif

	// Enter a critical section, where modificatio0n to variables by interrupts (and perhaps also other tasks) must be avoided
	inline void EnterInterruptCriticalSection()
	{
#ifdef RTOS
		taskENTER_CRITICAL();
#else
		cpu_irq_disable();
		++interruptCriticalSectionNesting;
#endif
	}

	// Leave an interrupt-critical section
	inline void LeaveInterruptCriticalSection()
	{
#ifdef RTOS
		taskEXIT_CRITICAL();
#else
		--interruptCriticalSectionNesting;
		if (interruptCriticalSectionNesting == 0)
		{
			cpu_irq_enable();
		}
#endif
	}

	// Enter a task-critical region. Used to protect concurrent access to variable form different tasks, where the variable are ont used/modified by interrupts.
	inline void EnterTaskCriticalSection()
	{
#ifdef RTOS
		vTaskSuspendAll();
#else
		// nothing to do here because there is on task preemption
#endif
	}

	// Exit a task-critical region, returning true if a task switch occurred
	inline bool LeaveTaskCriticalSection()
	{
#ifdef RTOS
		return xTaskResumeAll() == pdTRUE;;
#else
		// nothing to do here because there is on task preemption
		return false;
#endif
	}

	inline void Yield()
	{
#ifdef RTOS
		taskYIELD();
#endif
	}
}

class InterruptCriticalSectionLocker
{
public:
	InterruptCriticalSectionLocker() { RTOSIface::EnterInterruptCriticalSection(); }
	~InterruptCriticalSectionLocker() { (void)RTOSIface::LeaveInterruptCriticalSection(); }
};

class TaskCriticalSectionLocker
{
public:
	TaskCriticalSectionLocker() { RTOSIface::EnterTaskCriticalSection(); }
	~TaskCriticalSectionLocker() { RTOSIface::LeaveTaskCriticalSection(); }
};

#endif /* SRC_RTOSIFACE_H_ */