Skip to content

Commit

Permalink
Node: Fully working Dispatcher setup + Examples (#52)
Browse files Browse the repository at this point in the history
Note, I also enforced styling/formatting standards with this PR. We're
now using Google Linting standards.


![Code_UsG5SEfEIY](https://github.com/smartuni/teamagochi/assets/25822956/bfa93567-43d9-4666-a603-bb5ce48809b0)
  • Loading branch information
AnnsAnns authored May 1, 2024
2 parents 9edd5dd + e9f74c0 commit 59d0b52
Show file tree
Hide file tree
Showing 16 changed files with 1,536 additions and 1,169 deletions.
11 changes: 8 additions & 3 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
{
"name": "Teamagochi",
"cStandard": "c11",
"cppStandard": "c++17",
"compileCommands": "${workspaceFolder}/node/code/compile_commands.json"
"cppStandard": "c++20",
"compileCommands": "${workspaceFolder}/node/code/compile_commands.json",
"compilerPath": "/usr/bin/arm-none-eabi-gcc",
"includePath": [
"${default}",
"${workspaceFolder}/node/code/RIOT/**"
]
}
],
"version": 4
}
}
57 changes: 56 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,66 @@
],
"editor.detectIndentation": false,
"files.insertFinalNewline": true,
"C_Cpp.clang_format_style": "Google",
"C_Cpp.clang_format_fallbackStyle": "Google",
"files.associations": {
"**/frontmatter.json": "jsonc",
"**/.frontmatter/config/*.json": "jsonc",
"Makefile.*": "makefile",
"*.mk": "makefile",
"timex.h": "c"
"timex.h": "c",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"limits": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"span": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"thread": "cpp",
"chrono": "cpp",
"iostream": "cpp",
"list": "cpp",
"ratio": "cpp",
"istream": "cpp"
},
"[shellscript][c][cpp]": {
"editor.tabSize": 4,
Expand All @@ -20,4 +74,5 @@
"editor.tabSize": 2,
"editor.insertSpaces": true,
},
"C_Cpp.errorSquiggles": "disabled",
}
26 changes: 25 additions & 1 deletion node/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
## Teamagochi Node

This is the folder for node (hardware) development.
### Setup

Make sure you have cloned the repository with the `--recursive` flag to include the submodules. If you haven't, you can run `git submodule update --init --recursive` to get them.

### Development

1. Install VSCode
2. Install the C++ extension
3. Open the workspace starting from the root of the repository (Not this folder) to get the correct include paths
1. This is also important for the linter and other settings to work correctly
4. Open a terminal at `node/code` and run `make compile-commands` to generate the compile commands file
1. This helps the C++ extension with intellisense

### Formatting

If you followed the development setup instructions, VSCode should automatically format the code based on the Google standards.
Please make sure to follow the Google standards to keep the code consistent.

### Useful Commands

- `make compile-commands` - Generate the compile commands file
- `make build` - Build the project
- `make flash` - Flash the project onto the Feather
- `make term` - Open a serial terminal to the Feather
- `make clean` - Clean the build directory
3 changes: 2 additions & 1 deletion node/code/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ FEATURES_REQUIRED += cpp
FEATURES_REQUIRED += libstdcpp

#Hardware specific configs
USEMODULE += cpp11-compat
USEMODULE += ili9341
USEMODULE += ztimer
USEMODULE += ztimer_msec
Expand All @@ -24,7 +25,7 @@ SHOULD_RUN_KCONFIG ?=
# Include "inc" directory for the header files
INCLUDES += -I$(CURDIR)/inc

CXXEXFLAGS +=
CXXEXFLAGS +=

include $(RIOTBASE)/Makefile.include

Expand Down
31 changes: 31 additions & 0 deletions node/code/dispatcher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "dispatcher.hpp"
#include "GLOBALS.hpp"

Dispatcher::Dispatcher() {
this->subscriptions = list<Subscription>();
}

void Dispatcher::subscribe(list<EVENTS> events, kernel_pid_t pid) {
Subscription sub;
sub.event = events;
sub.pid = pid;

this->subscriptions.push_back(sub);
}

void Dispatcher::handleEvent(msg_t *event) {
for (Subscription sub : this->subscriptions) {
for (EVENTS e : sub.event) {
if (e == event->type) {
cout << "👀 PID: " << sub.pid << " was interested in event " << event->type << " notifying them" << endl;

msg_t msg;
msg.content.ptr = event->content.ptr;
msg.content.value = event->content.value;
msg.type = event->type;

msg_try_send(&msg, sub.pid);
}
}
}
}
10 changes: 10 additions & 0 deletions node/code/inc/EVENTS.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <cstdint>

enum EVENTS: uint16_t {
TERMINATE,
WILDCARD, // Subscribe to all events [Special case]
PING,
PONG,
};
14 changes: 14 additions & 0 deletions node/code/inc/GLOBALS.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @file GLOBALS.hpp
* @brief Global variables for the project.
* @author AnnsAnn <[email protected]>
*/

#pragma once

#include "thread.h"

/**
* @brief The dispatcher PID. Used to send events to the dispatcher.
*/
extern kernel_pid_t DISPATCHER_PID;
105 changes: 105 additions & 0 deletions node/code/inc/dispatch_handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* @brief DispatchHandler is an abstract class that receives events.
* @author Tom <[email protected]>
*/
#pragma once

using namespace std;

#include <iostream>

#include "msg.h"
#include "GLOBALS.hpp"
#include "EVENTS.hpp"
#include "thread.h"

/**
* DispatchHandler is an abstract class that receives events.
* @see Dispatcher
* If you want to receive events, you should inherit from this class and
* implement the handleEvent function. handleData is optional, but you should
* implement it if you want to receive data from the heightsensor.
*/
class DispatchHandler {
private:
/**
* @brief The event queue.
*/
static const int QUEUE_SIZE = 8;
msg_t rcv_queue[QUEUE_SIZE];
char internal_thread_stack [THREAD_STACKSIZE_MAIN];
kernel_pid_t internal_thread_pid;

public:
/**
* @brief Constructor.
* @details Initializes the event queue and starts the event loop.
*/
DispatchHandler() { }

/**
* @brief Send an event to the dispatcher.
* @param event The event to send.
*/
void sendEvent(msg_t *event) {
if (DISPATCHER_PID == -1) {
cout << "Dispatcher PID not set yet!" << endl;
return;
}

msg_try_send(event, DISPATCHER_PID);
}

kernel_pid_t getPID() { return this->internal_thread_pid; }

/**
* This quirky function does heinous things in order to make riot threads work with C++ classes.
* @warning Warcrimes :3
*/
void startInternalThread() {
cout << "Starting internal thread" << endl;
this->internal_thread_pid = thread_create(internal_thread_stack, sizeof(internal_thread_stack),
THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_WOUT_YIELD, internalThreadEntryFunction, this, "DispatchHandler for Class");
}

/**
* @brief Starts the event loop.
* @details This function will run forever and call the handleEvent function
* for each event.
*/
void startHandler() {
msg_init_queue(rcv_queue, QUEUE_SIZE);

// Event loop - Blocks when no events are available
while (true) {
msg_t message;
msg_receive(&message);

if (message.type == EVENTS::TERMINATE) {
cout << "Received TERMINATE event, exiting..." << endl;
return;
}

this->handleEvent(&message);
}
}

/**
* @brief Handle an event.
* @param event The event to handle.
* @warning Make sure to implement this function in your subclass.
*/
virtual void handleEvent(msg_t *event) = 0;

private:
/**
* @brief Internal thread entry function.
* The C++11 thread compat layer doesn't appear to properly support C++ classes
* so we have to do some (really) cursed pthread stuff to make it work.
*/
static void *internalThreadEntryFunction(void *This) {
((DispatchHandler *)This)->startHandler();

return NULL;
}
};
35 changes: 35 additions & 0 deletions node/code/inc/dispatcher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "dispatch_handler.hpp"
#include "EVENTS.hpp"

#include <list>

using namespace std;

struct Subscription {
list<EVENTS> event;
kernel_pid_t pid;
};

class Dispatcher : public DispatchHandler {
private:
list<Subscription> subscriptions;

public:
Dispatcher();

/**
* @brief Registers a PID to an event.
* @details This function will register a PID to an event. When the event
* is received, the PID will be sent the event.
* @param events List of events to subscribe to.
* @param pid The PID to send the event to.
*/
void subscribe(list<EVENTS> events, kernel_pid_t pid);

/**
* Internally used to send an event to a PID.
*/
void handleEvent(msg_t *event);
};
Loading

0 comments on commit 59d0b52

Please sign in to comment.