Skip to content

Commit 3df5f1b

Browse files
committed
Initial Commit
1 parent 778739d commit 3df5f1b

13 files changed

+745
-1
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,9 @@ FodyWeavers.xsd
396396

397397
# JetBrains Rider
398398
*.sln.iml
399+
400+
# Mac
401+
.DS_Store
402+
403+
# VisualStudioCode
404+
.vscode

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
set(COMPONENT_SRCDIRS
2+
"src"
3+
)
4+
5+
set(COMPONENT_ADD_INCLUDEDIRS
6+
"src"
7+
)
8+
9+
register_component()
10+
11+
target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DESP32)
12+
target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti)

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# ESPressio-Threads
2-
Threading Components of the ESPressio Development Platform
2+
Threading Components of the Flowduino ESPressio Development Platform
3+
4+

component.mk

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
COMPONENT_ADD_INCLUDEDIRS := include
2+
COMPONENT_SRCDIRS := src
3+
CXXFLAGS += -fno-rtti
4+
CXXFLAGS += -DESPRESSIO_THREADS
5+
CXXFLAGS += -DESPRESSO_THREADS_VERSION_MAJOR=0
6+
CXXFLAGS += -DESPRESSO_THREADS_VERSION_MINOR=0
7+
CXXFLAGS += -DESPRESSO_THREADS_VERSION_PATCH=1
8+
CXXFLAGS += -DESPRESSO_THREADS_VERSION_STRING=\"0.0.1\"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/*
2+
An extremely simple example of an ESPressio Thread loop that runs on either core of the ESP32.
3+
*/
4+
5+
#include <Arduino.h>

library.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "Flowduino ESPressio-Threads",
3+
"description": "Threding Library intended for use with multi-core ESP microcontrollers",
4+
"keywords": "thread,threads,threading,esp,esp32,esp8266,espressif,multi-threading,multi-core",
5+
"authors": {
6+
"name": "Flowduino",
7+
"maintainer": true
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/Flowduino/ESPressio-Threads.git"
12+
},
13+
"version": "0.0.1",
14+
"license": "Apache-2.0",
15+
"frameworks": "arduino",
16+
"platforms": "espressif32,espressif8266",
17+
"dependencies": []
18+
}

library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=Flowduino ESPressio-Threads
2+
version=0.0.1
3+
author=Simon J. Stuart
4+
maintainer=Flowduino.com
5+
sentence=Threding Library intended for use with multi-core ESP microcontrollers
6+
paragraph=This library is intended to be used with the ESP32 and ESP32-S2 microcontrollers. It is designed to allow the user to very easily create and manage threads on the microcontroller. This library is intended to be used with PlatformIO and the Arduino framework.
7+
category=Threading
8+
url=https://github.com/Flowduino/ESPressio-Threads
9+
architectures=esp32, esp32s2

src/ESPressio_IThread.hpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#pragma once
2+
3+
// #define CORE_THREADING_DEBUG // Uncomment this to explicitly enable debugging for the threading module
4+
#include <Arduino.h>
5+
#include <cstdint>
6+
7+
namespace ESPressio {
8+
9+
enum ThreadState {
10+
Uninitialized,
11+
Initialized,
12+
Running,
13+
Paused,
14+
Terminating,
15+
Terminated,
16+
Destroyed
17+
};
18+
19+
/*
20+
`IThread` is a common Interface for all Thread Types provided by this library.
21+
You can use it to reference any Thread Type without knowing the actual type.
22+
*/
23+
class IThread {
24+
public:
25+
// Methods
26+
27+
/// `Initialize` is invoked automatically for all Threads when the `ThreadManager` is initialized in your `main()` (or `setup()` for MCU projects) function.
28+
virtual void Initialize() = 0;
29+
30+
/*
31+
`Terminate` is invoked automatically for all Threads when the `ThreadManager` is terminated in your `main()` (or `loop()` for MCU projects) function.
32+
You can, however, invoke it manually to terminate a Thread at any time!
33+
*/
34+
virtual void Terminate() = 0;
35+
36+
/*
37+
`Start` will start the Thread loop if it is not already running.
38+
It will also Resume the thread if it is `Paused`.
39+
*/
40+
virtual void Start() = 0;
41+
42+
/// `Pause` will pause the Thread loop if it is running.
43+
virtual void Pause() = 0;
44+
45+
// Getters
46+
47+
/// `GetCoreID` returns the ID of the Core the Thread is running on.
48+
virtual BaseType_t GetCoreID() = 0;
49+
50+
/// `GetStackSize` returns the size of the Stack the Thread is using.
51+
virtual uint32_t GetStackSize() = 0;
52+
53+
/// `GetPriority` returns the priority of the Thread.
54+
virtual UBaseType_t GetPriority() = 0;
55+
56+
/// `GetThreadID` returns the unique ID of the Thread.
57+
virtual uint8_t GetThreadID() = 0;
58+
59+
/// `GetThreadState` returns the current state of the Thread.
60+
virtual ThreadState GetThreadState() = 0;
61+
62+
/// `GetFreeOnTerminate` returns whether this Thread should be freed from memory when it is terminated.
63+
virtual bool GetFreeOnTerminate() = 0;
64+
65+
/// `GetStartOnInitialize` returns whether this Thread should start running when it is initialized.
66+
virtual bool GetStartOnInitialize() = 0;
67+
68+
// Utility Getters
69+
bool IsRunning() { return GetThreadState() == ThreadState::Running; }
70+
71+
bool IsPaused() { return GetThreadState() == ThreadState::Paused; }
72+
73+
bool IsTerminating() { return GetThreadState() == ThreadState::Terminating; }
74+
75+
bool IsTerminated() { return GetThreadState() == ThreadState::Terminated; }
76+
77+
// Setters
78+
/// `SetCoreID` sets the ID of the Core the Thread should run on.
79+
virtual void SetCoreID(BaseType_t value) = 0;
80+
81+
/// `SetStackSize` sets the size of the Stack the Thread should use.
82+
virtual void SetStackSize(uint32_t value) = 0;
83+
84+
/// `SetPriority` sets the priority of the Thread.
85+
virtual void SetPriority(UBaseType_t value) = 0;
86+
87+
/// `SetFreeOnTerminate` defines whether this Thread should be freed from memory when it is terminated.
88+
virtual void SetFreeOnTerminate(bool value) = 0;
89+
};
90+
91+
}

src/ESPressio_Thread.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "ESPressio_Thread.hpp"
2+
#include "ESPressio_ThreadManager.hpp"
3+
4+
#include "ESPressio_ThreadGarbageCollector.hpp"
5+
6+
namespace ESPressio {
7+
8+
// Define the Constructor and Destructor of `Thread` here
9+
Thread::Thread() : _threadID(0) {
10+
_threadID = ThreadManager::GetInstance()->GetThreadCount();
11+
SetCoreID(ThreadManager::GetInstance()->AddThread(this));
12+
}
13+
14+
Thread::~Thread() {
15+
SetThreadState(ThreadState::Destroyed);
16+
ThreadManager::GetInstance()->RemoveThread(this);
17+
if (_taskHandle != nullptr) { vTaskDelete(_taskHandle); }
18+
}
19+
20+
// Define the Terminate method of `Thread` here
21+
void Thread::Terminate() {
22+
SetThreadState(ThreadState::Terminated);
23+
if (GetFreeOnTerminate()) { ThreadGarbageCollector::GetInstance()->CleanUp(); } // Automatically trigger the Garbage Collector
24+
}
25+
26+
}

src/ESPressio_Thread.hpp

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#pragma once
2+
3+
#include "ESPressio_IThread.hpp"
4+
#include "ThreadSafe.hpp"
5+
6+
namespace ESPressio {
7+
8+
// Forward Declaration for `ThreadGarbageCollector`
9+
class ThreadGarbageCollector;
10+
11+
/*
12+
`Thread` is a class that represents a "standard" Thread in the system.
13+
It is a wrapper around the system's Thread API, designed to make them much easier to use.
14+
*/
15+
class Thread : public IThread {
16+
private:
17+
// Members
18+
uint8_t _threadID; // This is idempotent so doesn't need a `Mutex` wrapper.
19+
ReadWriteMutex<ThreadState> _threadState = ReadWriteMutex<ThreadState>(ThreadState::Uninitialized);
20+
ReadWriteMutex<bool> _freeOnTerminate = ReadWriteMutex<bool>(false);
21+
ReadWriteMutex<bool> _startOnInitialize = ReadWriteMutex<bool>(true);
22+
TaskHandle_t _taskHandle = nullptr; // SHOULD be Atomic!
23+
ReadWriteMutex<uint32_t> _stackSize = ReadWriteMutex<uint32_t>(10000);
24+
ReadWriteMutex<UBaseType_t> _priority = ReadWriteMutex<UBaseType_t>(2);
25+
ReadWriteMutex<BaseType_t> _coreID = ReadWriteMutex<BaseType_t>(0);
26+
27+
// Methods
28+
void _loop() {
29+
for (;;) {
30+
switch (_threadState.Get()) {
31+
case ThreadState::Paused:
32+
case ThreadState::Initialized:
33+
case ThreadState::Uninitialized:
34+
delay(1);
35+
break;
36+
case ThreadState::Running:
37+
OnLoop();
38+
break;
39+
case ThreadState::Terminating:
40+
SetThreadState(ThreadState::Terminated);
41+
case ThreadState::Terminated:
42+
if (_taskHandle != nullptr) { vTaskDelete(_taskHandle); }
43+
return;
44+
}
45+
}
46+
}
47+
protected:
48+
// Methods
49+
50+
/// Override `OnLoop` to provide the main loop for the Thread.
51+
virtual void OnLoop() {}
52+
53+
/// Override `OnInitialization` to perform any setup required for the Thread before the Loop begins.
54+
virtual void OnInitialization() {}
55+
56+
// Getters (Internal)
57+
58+
59+
60+
// Setters (Internal)
61+
62+
void SetThreadState(ThreadState state) {
63+
_threadState.Set(state);
64+
}
65+
public:
66+
// Constructor/Destructor
67+
Thread();
68+
69+
~Thread();
70+
71+
// Methods
72+
void Initialize() {
73+
if (_taskHandle != nullptr) { vTaskDelete(_taskHandle); } // Delete any existing task handle if it's there!
74+
// Convert value of GetThreadID() to const char* for xTaskCreatePinnedToCore
75+
char threadIDStr[3];
76+
itoa(GetThreadID(), threadIDStr, 10);
77+
78+
xTaskCreatePinnedToCore(
79+
[](void* parameter) {
80+
Thread* instance = static_cast<Thread*>(parameter);
81+
instance->_loop();
82+
},
83+
threadIDStr, /* Name of the task. */
84+
GetStackSize(), /* Stack size of the task. */
85+
this, /* Parameter of the task (class instance). */
86+
GetPriority(), /* Priority of the task. */
87+
&_taskHandle, /* Task handle to keep track of the created task. */
88+
GetCoreID() /* Pin task to core 0. */
89+
);
90+
OnInitialization(); // Invoke any custom initialization behaviour before we change the state of the Thread
91+
// Check if the state was changed to Terminating or Terminate during the OnInitialization() method
92+
if (GetThreadState() == ThreadState::Terminating || GetThreadState() == ThreadState::Terminated) {
93+
vTaskDelete(_taskHandle);
94+
return;
95+
}
96+
SetThreadState(GetStartOnInitialize() ? ThreadState::Running : ThreadState::Initialized);
97+
}
98+
99+
void Terminate();
100+
101+
void Start() {
102+
if (GetThreadState() == ThreadState::Terminated) {
103+
Initialize();
104+
}
105+
SetThreadState(ThreadState::Running);
106+
}
107+
108+
void Pause() {
109+
SetThreadState(ThreadState::Paused);
110+
}
111+
112+
// Getters
113+
114+
BaseType_t GetCoreID() {
115+
return _coreID.Get();
116+
}
117+
118+
uint32_t GetStackSize() {
119+
return _stackSize.Get();
120+
}
121+
122+
UBaseType_t GetPriority() {
123+
return _priority.Get();
124+
}
125+
126+
uint8_t GetThreadID() {
127+
return _threadID;
128+
}
129+
130+
ThreadState GetThreadState() {
131+
return _threadState.Get();
132+
}
133+
134+
bool GetFreeOnTerminate() {
135+
return _freeOnTerminate.Get();
136+
}
137+
138+
bool GetStartOnInitialize() {
139+
return _startOnInitialize.Get();
140+
}
141+
142+
// Setters
143+
144+
void SetCoreID(BaseType_t value) {
145+
_coreID.Set(value);
146+
}
147+
148+
void SetStackSize(uint32_t value) {
149+
_stackSize.Set(value);
150+
}
151+
152+
void SetPriority(UBaseType_t value) {
153+
_priority.Set(value);
154+
}
155+
156+
void SetFreeOnTerminate(bool value) {
157+
_freeOnTerminate.Set(value);
158+
}
159+
160+
void SetStartOnInitialize(bool value) {
161+
_startOnInitialize.Set(value);
162+
}
163+
};
164+
165+
}

0 commit comments

Comments
 (0)