Compare commits
8 Commits
v0.1-alpha
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3954624413 | ||
|
|
5c3f2730ec | ||
|
|
ff9bb57665 | ||
|
|
17af6e4faf | ||
| 331cbe4f82 | |||
| a5652102a0 | |||
|
|
1df45a2d2b | ||
| 59bafb2549 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Quinn Henthorne, Y. Jenny Wang, Stanton Nash
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
49
README.md
49
README.md
@@ -127,55 +127,6 @@ Format Example `!3;`
|
||||
|
||||
Description: This command will tell the ESP32 to re-enable its idle animation. It will respond with a `!3;` when it recieves this command.
|
||||
|
||||
**HERE IS A GUIDE TO GET YOU STARTED ON YOUR [MAYBE] FIRST REPOSITORY**:
|
||||
|
||||
<https://docs.codeberg.org/getting-started/first-repository/#2.-clone-the-repository>
|
||||
|
||||
Obviously, this is not what your README should say on-submission. Change it. Yes, the whole thing.
|
||||
|
||||
This is where a description of your project will go. README.md files support [Markdown syntax](https://www.markdownguide.org/basic-syntax/).
|
||||
|
||||
## Setup
|
||||
|
||||
**Oh yeah, by the way, don't forget to set up `git lfs` on your machine.**
|
||||
|
||||
Tell everyone what your project needs in order to run. This might involve many components or software. Maybe some cool libraries?
|
||||
|
||||
### Hardware Required
|
||||
|
||||
- Some polyphonic headset on OS version `3.14159265358979323846233832795028841971` with room-temperature hyperconductors
|
||||
- Some macrocontroller with specific hardware revision `4.2`
|
||||
- With tank wheels
|
||||
- Some computer with a holoported underdisplay cap
|
||||
- Some fancy smart device that is worn and knows your favorite toothpaste
|
||||
|
||||
### Software Dependencies
|
||||
|
||||
- Division Game Engine version `2024.1.26`
|
||||
- Michaelsoft Binbows `XD`
|
||||
|
||||
## Run
|
||||
|
||||
1. Open the thing
|
||||
- You know, that thing over there
|
||||
- No, not that one
|
||||
- Go back
|
||||
- Yes, that one
|
||||
2. Click the button and type the following text:
|
||||
|
||||
```shell
|
||||
# install the sotware
|
||||
sudo apt install -y cmatrix
|
||||
# run the trap
|
||||
cmatrix
|
||||
```
|
||||
|
||||
3. After the process completes and you don't even see the code, anymore, you are ready. Here is what it looks like:
|
||||
|
||||
```js
|
||||
"b" + "a" + +"a" + "a"; // 'baNaNa'
|
||||
```
|
||||
|
||||
## Shout-Outs
|
||||
- Thank you to all the organizers at Reality Hack and the Hardware track.
|
||||
- Lucas De Bonet for creating `the Singularity` which allowed us to connect the board to Quest headsets.
|
||||
|
||||
25
THIRD-PARTY-LICENSES.md
Normal file
25
THIRD-PARTY-LICENSES.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Open Source Software Used in the Project
|
||||
|
||||
[BlockParty](https://codeberg.org/reality-hack-2024/BlockParty)
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Reality-Hack-Inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -133,7 +133,10 @@ void BoardManager<BOARD_DIMS>::Update(){
|
||||
// create a cube slice array buffer
|
||||
BOARD_TYPES::Cube* sliceBuffer[BOARD_DIMS.z];
|
||||
// have the board slice get read into our buffer
|
||||
this->board.SliceBoard(sliceVector, sliceBuffer);
|
||||
uint32_t sliceSize = this->board.SliceBoard(sliceVector, sliceBuffer);
|
||||
if(sliceSize < BOARD_DIMS.z){
|
||||
return;
|
||||
}
|
||||
// send the board slice to the driver to update its LED colors
|
||||
this->driver.UpdateStackLEDs(stackIndex, sliceBuffer, BOARD_DIMS.z);
|
||||
}
|
||||
@@ -146,9 +149,14 @@ void BoardManager<BOARD_DIMS>::updateStackColors(const V3D<uint32_t> &column){
|
||||
V3D<uint32_t> sliceVector{column.x, column.y, BOARD_TYPES::Z};
|
||||
// create a buffer for slice board to write the cube slice into
|
||||
BOARD_TYPES::Cube * cubeSlice[BOARD_DIMS.z];
|
||||
this->board.SliceBoard(column, cubeSlice);
|
||||
uint32_t sliceSize = this->board.SliceBoard(column, cubeSlice);
|
||||
|
||||
uint32_t numCubes{this->getColumnHeight(static_cast<BOARD_TYPES::PLANE_NORMAL>(column.z))};
|
||||
|
||||
if(sliceSize < numCubes){
|
||||
return;
|
||||
}
|
||||
|
||||
this->driver.UpdateStackLEDs(BOARD_DIMS.x, cubeSlice, numCubes);
|
||||
}
|
||||
|
||||
@@ -168,6 +176,11 @@ void BoardManager<BOARD_DIMS>::SetColumnColors(const V3D<uint32_t> &column, cons
|
||||
uint32_t sliceLength{this->board.SliceBoard(column, slicedBoard)};
|
||||
|
||||
uint32_t maxIndex{std::min(numColors, columnHeight)};
|
||||
|
||||
if(sliceLength < maxIndex){
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < maxIndex; i++){
|
||||
slicedBoard[i]->color = color[i];
|
||||
}
|
||||
|
||||
47
lib/CommandHandler/CommandHandler.cpp
Normal file
47
lib/CommandHandler/CommandHandler.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "CommandHandler.h"
|
||||
|
||||
CommandHandler::CommandHandler(){
|
||||
for(uint32_t i = 0; i < MAX_COMMAND_SIZE; i++){
|
||||
commandCallbacks[i] = nullptr;
|
||||
commandCallbackIDs[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandHandler::RegisterCommand(uint32_t commandID, CommandCallback callback){
|
||||
for(uint32_t i = 0; i < MAX_COMMAND_SIZE; i++){
|
||||
if(commandCallbacks[i] == nullptr){
|
||||
commandCallbacks[i] = callback;
|
||||
commandCallbackIDs[i] = commandID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CommandHandler::RemoveCommand(uint32_t commandID){
|
||||
for(uint32_t i = 0; i < MAX_COMMAND_SIZE; i++){
|
||||
if(commandCallbackIDs[i] == commandID){
|
||||
commandCallbacks[i] = nullptr;
|
||||
commandCallbackIDs[i] = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandHandler::CommandStatus CommandHandler::ProcessCommand(uint32_t * command, uint32_t commandSize){
|
||||
if(commandSize == 0){
|
||||
return CommandStatus::INVALID;
|
||||
}
|
||||
|
||||
uint32_t commandID{command[0]};
|
||||
// get a pointer to the second element in the array because the first element is the command ID
|
||||
uint32_t * args{&(command[1])};
|
||||
|
||||
for(uint32_t i = 0; i < MAX_COMMAND_SIZE; i++){
|
||||
if(commandCallbacks[i] != nullptr && commandCallbackIDs[i] == commandID){
|
||||
return commandCallbacks[i](args, commandSize-1);
|
||||
}
|
||||
}
|
||||
return CommandStatus::INVALID;
|
||||
}
|
||||
47
lib/CommandHandler/CommandHandler.h
Normal file
47
lib/CommandHandler/CommandHandler.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
class CommandHandler{
|
||||
public:
|
||||
// create an enum for command return values
|
||||
enum CommandStatus{
|
||||
SUCCESS,
|
||||
FAILURE,
|
||||
INVALID
|
||||
};
|
||||
|
||||
// create a typedef for a command callback function which takes an array pointer and an array size as an argument and returns a CommandStatus
|
||||
typedef CommandStatus (*CommandCallback)(uint32_t * command, uint32_t commandSize);
|
||||
|
||||
CommandHandler();
|
||||
~CommandHandler() = default;
|
||||
|
||||
/**
|
||||
* @brief Register a command callback function to a command ID
|
||||
* @param commandID The command ID to register the callback to
|
||||
* @param callback The callback function to register
|
||||
* @return true if the callback was registered successfully, false otherwise
|
||||
*/
|
||||
bool RegisterCommand(uint32_t commandID, CommandCallback callback);
|
||||
|
||||
/**
|
||||
* @brief Remove a command callback function from a command ID
|
||||
* @param commandID The command ID to remove the callback from
|
||||
* @return true if the callback was removed successfully, false otherwise
|
||||
*/
|
||||
bool RemoveCommand(uint32_t commandID);
|
||||
|
||||
/**
|
||||
* @brief Process a command
|
||||
* @param command The command to process
|
||||
*/
|
||||
CommandStatus ProcessCommand(uint32_t * command, uint32_t commandSize);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t MAX_COMMAND_SIZE{10};
|
||||
|
||||
// an array of command callbacks
|
||||
CommandCallback commandCallbacks[MAX_COMMAND_SIZE];
|
||||
// an array of command callback IDs
|
||||
uint32_t commandCallbackIDs[MAX_COMMAND_SIZE];
|
||||
};
|
||||
100
src/main.cpp
100
src/main.cpp
@@ -15,6 +15,7 @@
|
||||
#include "BluetoothSerial.h"
|
||||
#include "SerialMessage.h"
|
||||
#include "GlobalPrint.h"
|
||||
#include "CommandHandler.h"
|
||||
|
||||
#include "BoardManager.h"
|
||||
#include "BoardDriver.h"
|
||||
@@ -36,6 +37,8 @@ std::array<std::vector<AnimationFrame>*, 2> animations = {
|
||||
&RotatingCubes::rotating,
|
||||
};
|
||||
|
||||
CommandHandler commandHandler{};
|
||||
|
||||
// BluetoothSerial SerialBT;
|
||||
// BluetoothSerialMessage serialMessageBT(&SerialBT);
|
||||
SerialMessage<SERIAL_CHAR_LENGTH, SERIAL_ARG_LENGTH> serialMessage(&Serial);
|
||||
@@ -73,7 +76,6 @@ void SetupBluetoothModule(){
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
void printBoardState(){
|
||||
GlobalPrint::Print("!0,");
|
||||
String boardString;
|
||||
@@ -82,63 +84,63 @@ void printBoardState(){
|
||||
GlobalPrint::Println(";");
|
||||
}
|
||||
|
||||
void SetStackColor(uint32_t * args, int argsLength){
|
||||
uint32_t stackNum = args[1];
|
||||
void SetStackColor(uint32_t * args, uint32_t argsLength){
|
||||
uint32_t stackNum = args[0];
|
||||
uint32_t X_COORD{stackNum};
|
||||
while(X_COORD > BOARD_DIMENSIONS.x - 1){
|
||||
X_COORD -= BOARD_DIMENSIONS.x;
|
||||
}
|
||||
uint32_t Y_COORD{(stackNum - X_COORD) / BOARD_DIMENSIONS.y};
|
||||
Serial.println("StackNum: " + String(stackNum));
|
||||
Serial.println("X: " + String(X_COORD) + " Y: " + String(Y_COORD));
|
||||
uint32_t numColors = (argsLength - 1) / 3;
|
||||
|
||||
uint32_t numColors = (argsLength - 2) / 3;
|
||||
// nothing to do if no colors were given
|
||||
if(numColors == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Num Colors: " + String(numColors));
|
||||
V3D<uint32_t> colors[numColors];
|
||||
|
||||
for(int i = 0; i < numColors; i++){
|
||||
uint32_t red = args[2 + (i * 3)];
|
||||
uint32_t green = args[3 + (i * 3)];
|
||||
uint32_t blue = args[4 + (i * 3)];
|
||||
uint32_t red = args[1 + (i * 3)];
|
||||
uint32_t green = args[2 + (i * 3)];
|
||||
uint32_t blue = args[3 + (i * 3)];
|
||||
colors[i] = V3D<uint32_t>{red, green, blue};
|
||||
Serial.println("Color: " + String(red) + "," + String(green) + "," + String(blue));
|
||||
}
|
||||
boardManager.SetColumnColors(V3D<uint32_t>{X_COORD, Y_COORD, BOARD_TYPES::PLANE_NORMAL::Z}, colors, numColors);
|
||||
}
|
||||
|
||||
void parseData(Message<SERIAL_CHAR_LENGTH, SERIAL_ARG_LENGTH> &message){
|
||||
int32_t * args{message.GetArgs()};
|
||||
uint32_t argsLength{message.GetPopulatedArgs()};
|
||||
uint32_t command = args[0];
|
||||
switch(command){
|
||||
case Commands::BoardState:{
|
||||
printBoardState();
|
||||
break;
|
||||
}
|
||||
case Commands::PING:{
|
||||
GlobalPrint::Println("!" + String(Commands::PING) + ";");
|
||||
boardManager.PrintColorState();
|
||||
break;
|
||||
}
|
||||
case Commands::SetStackColors:{
|
||||
GlobalPrint::Println("!2;");
|
||||
animator.isEnabled = false;
|
||||
V3D<uint32_t> black{};
|
||||
boardManager.FillColor(black);
|
||||
SetStackColor(reinterpret_cast<uint32_t *>(args), argsLength);
|
||||
break;
|
||||
}
|
||||
case Commands::GoToIdle:{
|
||||
GlobalPrint::Println("!3;");
|
||||
animator.isEnabled = true;
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
GlobalPrint::Println("INVALID COMMAND");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// now that we have run the command we can clear the data for the next command.
|
||||
serialMessage.ClearNewData();
|
||||
// command handling functions
|
||||
CommandHandler::CommandStatus BoardStateCommandHandler(uint32_t * /*args*/, uint32_t /*argsLength*/){
|
||||
printBoardState();
|
||||
return CommandHandler::CommandStatus::SUCCESS;
|
||||
}
|
||||
|
||||
CommandHandler::CommandStatus PingCommandHandler(uint32_t * /*args*/, uint32_t /*argsLength*/){
|
||||
GlobalPrint::Println("!" + String(Commands::PING) + ";");
|
||||
return CommandHandler::CommandStatus::SUCCESS;
|
||||
}
|
||||
|
||||
CommandHandler::CommandStatus SetColorCommandHandler(uint32_t * args, uint32_t argsLength){
|
||||
GlobalPrint::Println("!2;");
|
||||
animator.isEnabled = false;
|
||||
V3D<uint32_t> black{};
|
||||
boardManager.FillColor(black);
|
||||
SetStackColor(args, argsLength);
|
||||
return CommandHandler::CommandStatus::SUCCESS;
|
||||
}
|
||||
|
||||
CommandHandler::CommandStatus GoToIdleCommandHandler(uint32_t * /*args*/, uint32_t /*argsLength*/){
|
||||
GlobalPrint::Println("!3;");
|
||||
animator.isEnabled = true;
|
||||
return CommandHandler::CommandStatus::SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
// ----------------- FREERTOS TASKS -----------------
|
||||
// --------------------------------------------------
|
||||
@@ -148,12 +150,14 @@ void UpdateCommunication(void * params){
|
||||
// DO serial processing
|
||||
serialMessage.Update();
|
||||
if(serialMessage.IsNewData()){
|
||||
parseData(serialMessage);
|
||||
// We reinterpret cast the args to a uint32_t pointer because we know that the args will always be positive
|
||||
commandHandler.ProcessCommand(reinterpret_cast<uint32_t *>(serialMessage.GetArgs()), serialMessage.GetPopulatedArgs());
|
||||
serialMessage.ClearNewData();
|
||||
}
|
||||
// serialMessageBT.Update();
|
||||
// if(serialMessageBT.IsNewData()){
|
||||
// parseData(serialMessageBT.GetArgs(), serialMessageBT.GetArgsLength());
|
||||
// serialMessageBT.ClearNewData();
|
||||
// commandHandler.ProcessCommand(reinterpret_cast<uint32_t *>(serialMessage.GetArgs()), serialMessage.GetPopulatedArgs());
|
||||
// serialMessage.ClearNewData();
|
||||
// }
|
||||
vTaskDelay(3);
|
||||
}
|
||||
@@ -214,6 +218,12 @@ void setup() {
|
||||
SetupBluetoothModule();
|
||||
Serial.begin(9600);
|
||||
|
||||
// Register all of our commands with the command handler
|
||||
commandHandler.RegisterCommand(Commands::BoardState, BoardStateCommandHandler);
|
||||
commandHandler.RegisterCommand(Commands::PING, PingCommandHandler);
|
||||
commandHandler.RegisterCommand(Commands::SetStackColors, SetColorCommandHandler);
|
||||
commandHandler.RegisterCommand(Commands::GoToIdle, GoToIdleCommandHandler);
|
||||
|
||||
Serial.println("Configuring communication methods");
|
||||
serialMessage.Init(9600);
|
||||
// SerialBT.begin("blockPartyBT");
|
||||
|
||||
Reference in New Issue
Block a user