Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.pio
|
||||||
|
.vscode
|
||||||
176
README.md
Normal file
176
README.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# Block Party
|
||||||
|
|
||||||
|
Stack blocks in real life. See them stack in VR.
|
||||||
|
Play with blocks in VR. See them change in real life.
|
||||||
|
If you’re feeling brave, enter the doll house.
|
||||||
|
|
||||||
|
Virtual reality can be a powerful tool to connect the physical world and the digital world and connect people in different locations.
|
||||||
|
However, many VR experiences today are limited to the digital world.
|
||||||
|
Many multi-user VR experiences place all users into the same digital world and people in the VR headset are cut off from the physical world.
|
||||||
|
|
||||||
|
Block Party uses an asymmetric experience to connect a person using a VR headset with a person without a headset.
|
||||||
|
The person without a headset interacts with physical blocks on a physical board while the person in the VR headset interacts with digital blocks on a digital board.
|
||||||
|
When the physical user places a physical block on the physical board, the VR user sees a block in the corresponding location on the digital board.
|
||||||
|
When the physical user removes a block from the board, the corresponding digital block disappears for the VR user.
|
||||||
|
When the VR user hovers over or picks up a digital cube, the corresponding physical cube changes color to show the physical user what the VR user is doing.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
### Board Assemble
|
||||||
|
#### Parts List
|
||||||
|
- Foam core (scavenged)
|
||||||
|
- (4) Thor labs boxes (scavenged)
|
||||||
|
- (1) ESP32
|
||||||
|
- (1) breadboard
|
||||||
|
- copper tape
|
||||||
|
- (9) magnets
|
||||||
|
- (9) 10k resistors
|
||||||
|
board documentation can be found int he `documentation` directory.
|
||||||
|
|
||||||
|
### Cube Assembly
|
||||||
|
#### Parts List
|
||||||
|
- 3D printed case and cover (stl files are in the documentation folder)
|
||||||
|
- WS2812B LED (1 strip of 2 LEDs)
|
||||||
|
- (1) 10k resistor
|
||||||
|
- copper tape
|
||||||
|
- (2) magnets
|
||||||
|
- Kapton tape
|
||||||
|
- black electrical tape to mark the bottom
|
||||||
|
wiring diagram for the cube is in the `documentation` directory.
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
- Meta Quest headset. The included Unity project uses SDKs for Android so other Android-based headsets may work, but have not been tested.
|
||||||
|
- The physical board and physical blocks
|
||||||
|
- Two USB power sources to run the physical board. One for the LEDs and one for the sensors detecting where the blocks are.
|
||||||
|
|
||||||
|
### Software Dependencies
|
||||||
|
#### Unity
|
||||||
|
- [`the Singularity`](https://github.com/VRatMIT/TheSingularity-Unity)
|
||||||
|
- Meta Presence Platform: hand tracking, pokable item, interaction, hand-poke interaction, synthetic hands, grab interaction, hand-poke limiter, pass-through
|
||||||
|
- Unity package: [DOTween](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676)
|
||||||
|
|
||||||
|
#### Board
|
||||||
|
- Adafruit’s Neopixel library
|
||||||
|
- Arduino libraries
|
||||||
|
|
||||||
|
## Run
|
||||||
|
- Power up the board and pair it with the headset over bluetooth.
|
||||||
|
- Build and load the Unity project to the headset.
|
||||||
|
- The first time the Unity project starts on the headset, you will receive a request for Bluetooth permissions. Grant the permission and restart the app. The restart is required after permissions are granted due to current limitations on `the Singularity`.
|
||||||
|
- After restarting the app, the app should automatically connect to the physical board and respond to blocks being placed on the physical board.
|
||||||
|
- Enjoy the connection between the digital and physical world.
|
||||||
|
|
||||||
|
## Unity interactions
|
||||||
|
|
||||||
|
### Interacting with the digital blocks
|
||||||
|
Once the cube has been placed on the board a cube in VR will appear.
|
||||||
|
The VR user can poke and pickup the digital blocks which will be indicated in real life by changing the colors of the blocks. Poking will change the block color to blue and picking it up will change it to red.
|
||||||
|
|
||||||
|
### Passthrough mode
|
||||||
|
The user can activate passthrough mode inside the app to see the physical board and the digital board at the same time.
|
||||||
|
|
||||||
|
### Dollhouse mode
|
||||||
|
When the dollhouse mode is activated, the digital blocks are increased in size and the VR user is moved to the center square of the board.
|
||||||
|
Note that a physical cube on the center square of the board will not appear in the digital world.
|
||||||
|
|
||||||
|
## Board Command Docs
|
||||||
|
The board contains an ESP32 that uses bluetooth serial to send the state of the board and receive commands.
|
||||||
|
|
||||||
|
### Command Name: `BoardState`
|
||||||
|
Command Number: `0`
|
||||||
|
|
||||||
|
Format Example: `!0,X1,X2,X3,X4,X5,X6,X7,X8,X9;`
|
||||||
|
|
||||||
|
Description: This command is sent when the board state changes and describes how the board is populated.
|
||||||
|
|
||||||
|
| X1 X2 X3 |
|
||||||
|
|
||||||
|
| X4 X5 X6 |
|
||||||
|
|
||||||
|
| X7 X8 X9 |
|
||||||
|
|
||||||
|
0 corresponds with the command type. The command number for BoardState is 0.
|
||||||
|
X1 corresponds with board spot X1, and so on. The value in each of the spots indicates how many cubes are in that spot.
|
||||||
|
IE: If X1 where 3, then there would be 3 cubes in the top left spot.
|
||||||
|
|
||||||
|
If you would like to get the board state, you can send !0; to the ESP32 and it will respond with the current board state. Otherwise, the ESP32 will send the board state whenever it changes.
|
||||||
|
|
||||||
|
### Command Name `Ping`
|
||||||
|
Command Number: `1`
|
||||||
|
|
||||||
|
Format Example: `!1;`
|
||||||
|
|
||||||
|
Description: This command is sent to the ESP32 to check if it is still connected. The ESP32 will respond with `!1;` if it is still connected.
|
||||||
|
|
||||||
|
### Command Name: `SetStackColor`
|
||||||
|
Command Number: `2`
|
||||||
|
|
||||||
|
Format Example: `!2,StackNumber,Red1,Green1,Blue1,Red2,Green2,Blue2,...REDX,GREENX,BLUEX;`
|
||||||
|
|
||||||
|
Description Set the colors for one of the stacks.
|
||||||
|
- 2 corresponds with the command type. The command number for SetStackColor is 2.
|
||||||
|
- StackNumber corresponds with the stack number you want to set the colors for. See `BoardState` description for stack numbers.
|
||||||
|
- Red1, Green1, Blue1 correspond with the color of the first cube in the stack and so on. These values can be between 0-255.
|
||||||
|
You can add as many colors as you want, but they wont display if the corresponding cube doesn't physically exist.
|
||||||
|
|
||||||
|
### COmmand Name: `GoToIdle`
|
||||||
|
Command Number: `3`
|
||||||
|
|
||||||
|
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.
|
||||||
|
- Mentor Mark Steelman for showing us the value (and complications) of runtime list creation and showing us how to make an in-editor button for debugging.
|
||||||
|
- Fellow Reality Hack hacker Sean Feeser for help with debugging.
|
||||||
|
- Juan Gil for helping us 3D print.
|
||||||
BIN
documentation/Stack_Cube_Lid.stl
Normal file
BIN
documentation/Stack_Cube_Lid.stl
Normal file
Binary file not shown.
BIN
documentation/board documentation.pdf
Normal file
BIN
documentation/board documentation.pdf
Normal file
Binary file not shown.
BIN
documentation/board with cubes photo.png
Normal file
BIN
documentation/board with cubes photo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 MiB |
BIN
documentation/cube wiring diagram.pdf
Normal file
BIN
documentation/cube wiring diagram.pdf
Normal file
Binary file not shown.
BIN
documentation/stack cube.stl
Normal file
BIN
documentation/stack cube.stl
Normal file
Binary file not shown.
35
include/BOARD-DEFINITIONS.h
Normal file
35
include/BOARD-DEFINITIONS.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* @file BOARD-DEFINITIONS.h
|
||||||
|
* @brief This file contains the definitions for the board
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PINOUT.h"
|
||||||
|
#include "CubeStack.h"
|
||||||
|
|
||||||
|
// define the physical dimensions of the board
|
||||||
|
#define BOARD_WIDTH 3
|
||||||
|
#define BOARD_LENGTH 3
|
||||||
|
#define BOARD_HEIGHT 3
|
||||||
|
|
||||||
|
// define the number of stacks
|
||||||
|
#define NUMBER_STACKS BOARD_WIDTH * BOARD_LENGTH
|
||||||
|
|
||||||
|
// define the CubeStacks
|
||||||
|
CubeStack stack1(STACK1_ADC_PIN, STACK1_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack2(STACK2_ADC_PIN, STACK2_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack3(STACK3_ADC_PIN, STACK3_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack4(STACK4_ADC_PIN, STACK4_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack5(STACK5_ADC_PIN, STACK5_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack6(STACK6_ADC_PIN, STACK6_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack7(STACK7_ADC_PIN, STACK7_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack8(STACK8_ADC_PIN, STACK8_LED_PIN, BOARD_HEIGHT);
|
||||||
|
CubeStack stack9(STACK9_ADC_PIN, STACK9_LED_PIN, BOARD_HEIGHT);
|
||||||
|
|
||||||
|
// define the array of stacks
|
||||||
|
CubeStack * stacks[] = {
|
||||||
|
&stack1, &stack2, &stack3,
|
||||||
|
&stack4, &stack5, &stack6,
|
||||||
|
&stack7, &stack8, &stack9
|
||||||
|
};
|
||||||
44
include/PINOUT.h
Normal file
44
include/PINOUT.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* @file PINOUT.h
|
||||||
|
* @brief This file contains the pinout for the board
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Stack 1 pins
|
||||||
|
#define STACK1_ADC_PIN 34
|
||||||
|
#define STACK1_LED_PIN 5
|
||||||
|
|
||||||
|
// Stack 2 pins
|
||||||
|
#define STACK2_ADC_PIN 39
|
||||||
|
#define STACK2_LED_PIN 18
|
||||||
|
|
||||||
|
// Stack 3 pins
|
||||||
|
#define STACK3_ADC_PIN 36
|
||||||
|
#define STACK3_LED_PIN 19
|
||||||
|
|
||||||
|
// Stack 4 pins
|
||||||
|
#define STACK4_ADC_PIN 35
|
||||||
|
#define STACK4_LED_PIN 17
|
||||||
|
|
||||||
|
// Stack 5 pins
|
||||||
|
#define STACK5_ADC_PIN 32
|
||||||
|
#define STACK5_LED_PIN 16
|
||||||
|
|
||||||
|
// Stack 6 pins
|
||||||
|
#define STACK6_ADC_PIN 33
|
||||||
|
#define STACK6_LED_PIN 4
|
||||||
|
|
||||||
|
// Stack 7 pins
|
||||||
|
#define STACK7_ADC_PIN 25
|
||||||
|
#define STACK7_LED_PIN 0
|
||||||
|
|
||||||
|
// Stack 8 pins
|
||||||
|
#define STACK8_ADC_PIN 26
|
||||||
|
#define STACK8_LED_PIN 2
|
||||||
|
|
||||||
|
// Stack 9 pins
|
||||||
|
#define STACK9_ADC_PIN 27
|
||||||
|
#define STACK9_LED_PIN 15
|
||||||
|
|
||||||
|
|
||||||
39
include/README
Normal file
39
include/README
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
38
lib/Board/BoardLayout.cpp
Normal file
38
lib/Board/BoardLayout.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "BoardLayout.h"
|
||||||
|
|
||||||
|
uint8_t BoardLayout::GetNumberStacks(){
|
||||||
|
return this->boardWidth * this->boardHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoardLayout::SetStackColors(uint8_t stackNum, Color * colors){
|
||||||
|
CubeStack * stack = this->stacks[stackNum];
|
||||||
|
stack->SetLEDColors(colors, this->boardHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BoardLayout::BoardStateHasChanged(){
|
||||||
|
uint16_t boardState[this->boardWidth * this->boardLength];
|
||||||
|
this->GetBoardState(boardState);
|
||||||
|
|
||||||
|
// compare the board state to the last board state
|
||||||
|
for(int i = 0; i < (this->boardWidth * this->boardLength); i++){
|
||||||
|
uint16_t stackState = boardState[i];
|
||||||
|
uint16_t lastStackState = (this->lastBoardState)[i];
|
||||||
|
if(stackState != lastStackState){
|
||||||
|
// copy the board state into the last board state
|
||||||
|
for(int k = 0; k < (this->boardWidth * this->boardLength); k++){
|
||||||
|
this->lastBoardState[k] = boardState[k];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoardLayout::GetBoardState(uint16_t * boardStateBuffer){
|
||||||
|
for(int i = 0; i < (this->boardLength * this->boardWidth); i++){
|
||||||
|
CubeStack * stack = this->stacks[i];
|
||||||
|
stack->SendLEDData(); // Enable this if you want to constantly stream LED data
|
||||||
|
boardStateBuffer[i] = stack->GetNumberCubes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
69
lib/Board/BoardLayout.h
Normal file
69
lib/Board/BoardLayout.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* @brief This is the full board manager which handles the state of every stack on the board
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CubeStack.h"
|
||||||
|
#include "Color.h"
|
||||||
|
|
||||||
|
class BoardLayout{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief BoardLayout COnstructor
|
||||||
|
*/
|
||||||
|
BoardLayout(uint8_t boardWidth, uint8_t boardLength, uint8_t boardHeight, CubeStack ** stacks) :
|
||||||
|
boardWidth(boardWidth),
|
||||||
|
boardLength(boardLength),
|
||||||
|
boardHeight(boardHeight),
|
||||||
|
stacks(stacks)
|
||||||
|
{
|
||||||
|
this->lastBoardState = new uint16_t[boardWidth * boardLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if our board state has changed
|
||||||
|
* @return true if the board state has changed, false otherwise
|
||||||
|
*/
|
||||||
|
bool BoardStateHasChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Number of Stacks
|
||||||
|
* @return the number of stacks
|
||||||
|
*/
|
||||||
|
uint8_t GetNumberStacks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the LED Colors
|
||||||
|
* @param stackNum the stack index you would like to address.
|
||||||
|
* From top left to bottom right, the stack numbers are as follows:
|
||||||
|
* | 0 1 2 |
|
||||||
|
* | 3 4 5 |
|
||||||
|
* | 6 7 8 |
|
||||||
|
* @param Colors the array of colors to set the LEDs in a stack to
|
||||||
|
*/
|
||||||
|
void SetStackColors(uint8_t stackNum, Color * colors);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the board population state
|
||||||
|
* @param boardStateBuffer the buffer to write the board state to. It must be at least boardWidth * boardLength in length
|
||||||
|
*/
|
||||||
|
void GetBoardState(uint16_t * boardStateBuffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t boardWidth;
|
||||||
|
uint8_t boardLength;
|
||||||
|
uint8_t boardHeight;
|
||||||
|
/*
|
||||||
|
An array of arrays of stacks
|
||||||
|
[ [stack1, stack2, stack3],
|
||||||
|
[stack4, stack5, stack6],
|
||||||
|
[stack7, stack8, stack9] ]
|
||||||
|
etc
|
||||||
|
*/
|
||||||
|
CubeStack ** stacks;
|
||||||
|
|
||||||
|
// records the last known board state
|
||||||
|
uint16_t * lastBoardState;
|
||||||
|
|
||||||
|
};
|
||||||
21
lib/Board/Color.h
Normal file
21
lib/Board/Color.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* @file Color.h
|
||||||
|
* @brief This file contains the color struct
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// store a color
|
||||||
|
struct Color{
|
||||||
|
// create a constructor for this struct
|
||||||
|
Color(uint8_t red, uint8_t green, uint8_t blue) :
|
||||||
|
red(red),
|
||||||
|
green(green),
|
||||||
|
blue(blue)
|
||||||
|
{}
|
||||||
|
Color() = default;
|
||||||
|
uint8_t red{0};
|
||||||
|
uint8_t green{0};
|
||||||
|
uint8_t blue{0};
|
||||||
|
};
|
||||||
77
lib/Board/CubeStack.cpp
Normal file
77
lib/Board/CubeStack.cpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include "CubeStack.h"
|
||||||
|
|
||||||
|
CubeStack::CubeStack(uint16_t ADCPin, uint16_t ledPin, uint8_t numLEDs){
|
||||||
|
this->ADCPin = ADCPin;
|
||||||
|
this->blockLights = *(new Adafruit_NeoPixel(numLEDs*2, ledPin, NEO_GRB + NEO_KHZ800));
|
||||||
|
this->ledColors = new Color[numLEDs];
|
||||||
|
this->numLEDs = numLEDs;
|
||||||
|
|
||||||
|
// initialize the LED colors to off
|
||||||
|
for(int i = 0; i < numLEDs; i++){
|
||||||
|
this->ledColors[i] = *(new Color(0, 0, 0));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t CubeStack::GetNumberCubes(){
|
||||||
|
// read the ADC and return the number of cubes
|
||||||
|
/*
|
||||||
|
0 cubes: 1 : 4095-3071
|
||||||
|
1 cube: 1/2 3070-1706
|
||||||
|
2 cubes: 1/3 1705-1195
|
||||||
|
3 cubes: 1/4 1195-0
|
||||||
|
*/
|
||||||
|
uint16_t value = analogRead(this->ADCPin);
|
||||||
|
|
||||||
|
this->lowPassADCRead = static_cast<uint16_t>((static_cast<float>(this->lowPassADCRead) * 0.9) + (static_cast<float>(value) * 0.1));
|
||||||
|
|
||||||
|
// temporary definitions to define value ranges:
|
||||||
|
uint16_t zeroCubesHigh = 4095;
|
||||||
|
uint16_t zeroCubesLow = 3071;
|
||||||
|
uint16_t oneCubeLow = 1706;
|
||||||
|
uint16_t twoCubesLow = 1000;
|
||||||
|
uint16_t threeCubesLow = 0;
|
||||||
|
|
||||||
|
uint8_t stackHeight = 0;
|
||||||
|
|
||||||
|
if(this->lowPassADCRead >= zeroCubesLow && this->lowPassADCRead <= zeroCubesHigh){
|
||||||
|
stackHeight = 0;
|
||||||
|
}
|
||||||
|
else if(this->lowPassADCRead >= oneCubeLow){
|
||||||
|
stackHeight = 1;
|
||||||
|
}
|
||||||
|
else if(this->lowPassADCRead >= twoCubesLow){
|
||||||
|
stackHeight = 2;
|
||||||
|
}
|
||||||
|
else if(this->lowPassADCRead >= threeCubesLow){
|
||||||
|
stackHeight = 3;
|
||||||
|
}
|
||||||
|
if(this->lastStackHeight != stackHeight){
|
||||||
|
this->lastStackHeight = stackHeight;
|
||||||
|
this->SendLEDData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return stackHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubeStack::SetLEDColors(Color * colors, uint8_t numColors){
|
||||||
|
// copy the colors into the ledColors array
|
||||||
|
for(int i = 0; i < numColors; i++){
|
||||||
|
this->ledColors[i].red = colors[i].red;
|
||||||
|
this->ledColors[i].green = colors[i].green;
|
||||||
|
this->ledColors[i].blue = colors[i].blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->SendLEDData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubeStack::SendLEDData(){
|
||||||
|
// we always initialize before we do anything because other CubeStacks could be hogging the hardware
|
||||||
|
// between our writes
|
||||||
|
this->blockLights.begin();
|
||||||
|
// set the LED colors
|
||||||
|
for(int i = 0; i < this->numLEDs; i++){
|
||||||
|
this->blockLights.setPixelColor(i*2, this->blockLights.Color(this->ledColors[i].red, this->ledColors[i].green, this->ledColors[i].blue));
|
||||||
|
this->blockLights.setPixelColor((i*2 + 1), this->blockLights.Color(this->ledColors[i].red, this->ledColors[i].green, this->ledColors[i].blue));
|
||||||
|
}
|
||||||
|
this->blockLights.show();
|
||||||
|
}
|
||||||
52
lib/Board/CubeStack.h
Normal file
52
lib/Board/CubeStack.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* @brief this manages a single cube stack and the lighting / detecting of how many cubes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
#include "Color.h"
|
||||||
|
|
||||||
|
|
||||||
|
class CubeStack{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Cube Stack object
|
||||||
|
* @param ADCPin the pin that the ADC is connected to
|
||||||
|
* @param ledPin the pin that the LED is connected to
|
||||||
|
*/
|
||||||
|
CubeStack(uint16_t ADCPin, uint16_t ledPin, uint8_t numLEDs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of cubes in the stack
|
||||||
|
* @return the number of cubes in the stack
|
||||||
|
*/
|
||||||
|
uint8_t GetNumberCubes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the led color array and then send the data to the LED strip
|
||||||
|
* @param colors the array of colors to set the LEDs to
|
||||||
|
* @param numColors the number of colors in the array
|
||||||
|
*/
|
||||||
|
void SetLEDColors(Color * colors, uint8_t numColors);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sends the LED data to the LED strip
|
||||||
|
*/
|
||||||
|
void SendLEDData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ADCPin;
|
||||||
|
// we will probably need a pointer to a fastled object here
|
||||||
|
Adafruit_NeoPixel blockLights;
|
||||||
|
|
||||||
|
uint16_t lowPassADCRead{0};
|
||||||
|
|
||||||
|
// store the Color of each LED
|
||||||
|
Color * ledColors;
|
||||||
|
uint8_t numLEDs;
|
||||||
|
uint8_t lastStackHeight{0};
|
||||||
|
};
|
||||||
48
lib/ColorManager/ColorManager.cpp
Normal file
48
lib/ColorManager/ColorManager.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "ColorManager.h"
|
||||||
|
|
||||||
|
void ColorManager::Update(){
|
||||||
|
if(!(this->enabled)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// go through our colors and have them fade from r->g->b->r
|
||||||
|
for(uint8_t i = 0; i < 9; i++){
|
||||||
|
for(uint8_t j = 0; j < 3; j++){
|
||||||
|
Color * color = this->colors[i][j];
|
||||||
|
// fade from red to green
|
||||||
|
if(color->red > 0 && color->green >= 0 && color->blue == 0){
|
||||||
|
color->red--;
|
||||||
|
color->green++;
|
||||||
|
}
|
||||||
|
// fade from green to blue
|
||||||
|
else if(color->green > 0 && color->blue >= 0 && color->red == 0){
|
||||||
|
color->green--;
|
||||||
|
color->blue++;
|
||||||
|
}
|
||||||
|
// fade from blue to red
|
||||||
|
else if(color->blue > 0 && color->red >= 0 && color->green == 0){
|
||||||
|
color->blue--;
|
||||||
|
color->red++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the colors
|
||||||
|
for(uint8_t i = 0; i < 9; i++){
|
||||||
|
Color temp_colors[3] = {*(this->colors[i][0]), *(this->colors[i][1]), *(this->colors[i][2])};
|
||||||
|
this->board->SetStackColors(i, temp_colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorManager::Enable(bool enable){
|
||||||
|
this->enabled = enable;
|
||||||
|
|
||||||
|
if(this->enabled == false){
|
||||||
|
// set all the colors to black
|
||||||
|
Color black(0, 0, 0);
|
||||||
|
Color temp_colors[3] = {black, black, black};
|
||||||
|
// set the colors
|
||||||
|
for(uint8_t i = 0; i < 9; i++){
|
||||||
|
this->board->SetStackColors(i, temp_colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
lib/ColorManager/ColorManager.h
Normal file
44
lib/ColorManager/ColorManager.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* @file ColorManager.h
|
||||||
|
* @brief Generate pretty colors for the board and make it do something when unity isn't controlling it
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BoardLayout.h"
|
||||||
|
#include "Color.h"
|
||||||
|
|
||||||
|
class ColorManager{
|
||||||
|
public:
|
||||||
|
ColorManager(BoardLayout * board) :
|
||||||
|
board(board)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allows the color manager to update the board colors
|
||||||
|
*/
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables or disables the color manager
|
||||||
|
* @param enable true to enable, false to disable
|
||||||
|
*/
|
||||||
|
void Enable(bool enable);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
BoardLayout * board;
|
||||||
|
bool enabled{true};
|
||||||
|
|
||||||
|
Color * colors[9][3] = {
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)},
|
||||||
|
{new Color(255, 0, 0), new Color(0, 255, 0), new Color(0, 0, 255)}
|
||||||
|
};
|
||||||
|
};
|
||||||
46
lib/README
Normal file
46
lib/README
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
58
lib/SerialMessage/BluetoothSerialMessage.cpp
Normal file
58
lib/SerialMessage/BluetoothSerialMessage.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include "BluetoothSerialMessage.h"
|
||||||
|
|
||||||
|
BluetoothSerialMessage::BluetoothSerialMessage(BluetoothSerial *serial){
|
||||||
|
this->serial = serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BluetoothSerialMessage::Init(unsigned int baud_rate){
|
||||||
|
// Don't need to do anything here, just let the user init bluetooth serial
|
||||||
|
}
|
||||||
|
|
||||||
|
void BluetoothSerialMessage::PrintArgs(){
|
||||||
|
serial->print("Current number of args: ");
|
||||||
|
serial->println(populated_args);
|
||||||
|
for (int i = 0; i < populated_args; i++) {
|
||||||
|
serial->print(args[i]);
|
||||||
|
serial->print(" ");
|
||||||
|
}
|
||||||
|
serial->println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BluetoothSerialMessage::readSerial(){
|
||||||
|
boolean recvInProgress = false;
|
||||||
|
byte ndx = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
// read the incoming serial data:
|
||||||
|
while (serial->available() > 0 && data_recieved == false) {
|
||||||
|
// get the neext character in the serial buffer
|
||||||
|
c = serial->read();
|
||||||
|
Serial.print(c);
|
||||||
|
|
||||||
|
// only execute this if the startMarker has been received
|
||||||
|
if (recvInProgress == true) {
|
||||||
|
// if the incoming character is not the endMarker...
|
||||||
|
if (c != endMarker) {
|
||||||
|
// add it to the data array
|
||||||
|
data[ndx] = c;
|
||||||
|
ndx++; // increment the data array index
|
||||||
|
// if the index is greater than the maximum data array size,
|
||||||
|
// keep overwriting the last element until the endMarker is received.
|
||||||
|
if (ndx >= num_chars) {
|
||||||
|
ndx = num_chars - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the incoming character is the endMarker clean up and set the flags
|
||||||
|
else {
|
||||||
|
data[ndx] = '\0'; // terminate the string
|
||||||
|
recvInProgress = false;
|
||||||
|
ndx = 0;
|
||||||
|
data_recieved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the incoming character is the startMarker, set the recvInProgress flag
|
||||||
|
else if (c == startMarker) {
|
||||||
|
recvInProgress = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
lib/SerialMessage/BluetoothSerialMessage.h
Normal file
31
lib/SerialMessage/BluetoothSerialMessage.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "SerialMessage.h"
|
||||||
|
#include <BluetoothSerial.h>
|
||||||
|
|
||||||
|
class BluetoothSerialMessage : public SerialMessage{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Bluetooth Serial Message object
|
||||||
|
*/
|
||||||
|
BluetoothSerialMessage(BluetoothSerial *serial);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the BluetoothSerialMessage object
|
||||||
|
*/
|
||||||
|
void Init(unsigned int baud_rate = 115200) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief prints the args array to the serial monitor
|
||||||
|
*/
|
||||||
|
void PrintArgs() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief reads the serial data and stores it in the data array
|
||||||
|
*/
|
||||||
|
void readSerial() override;
|
||||||
|
|
||||||
|
BluetoothSerial *serial;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
111
lib/SerialMessage/SerialMessage.cpp
Normal file
111
lib/SerialMessage/SerialMessage.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* @file SerialMessage.cpp
|
||||||
|
* @brief This file contains the SerialMessage class
|
||||||
|
* @details This file contains the SerialMessage class which is used to parse serial messages
|
||||||
|
* @version 1.0.0
|
||||||
|
* @author Quinn Henthorne. Contact: quinn.henthorne@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SerialMessage.h"
|
||||||
|
|
||||||
|
SerialMessage::SerialMessage(HardwareSerial *serial) :
|
||||||
|
serial(serial){}
|
||||||
|
|
||||||
|
void SerialMessage::Init(unsigned int baud_rate){
|
||||||
|
serial->begin(baud_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialMessage::readSerial(){
|
||||||
|
char c;
|
||||||
|
|
||||||
|
// read the incoming serial data:
|
||||||
|
while (serial->available() > 0 && data_recieved == false) {
|
||||||
|
// get the neext character in the serial buffer
|
||||||
|
c = serial->read();
|
||||||
|
// only execute this if the startMarker has been received
|
||||||
|
// if the incoming character is the endMarker clean up and set the flags
|
||||||
|
if (recvInProgress == true) {
|
||||||
|
if (c == endMarker) {
|
||||||
|
data[ndx] = '\0'; // terminate the string
|
||||||
|
recvInProgress = false;
|
||||||
|
ndx = 0;
|
||||||
|
data_recieved = true;
|
||||||
|
}
|
||||||
|
// if the incoming character is not the endMarker
|
||||||
|
else {
|
||||||
|
// add it to the data array
|
||||||
|
data[ndx] = c;
|
||||||
|
ndx++; // increment the data array index
|
||||||
|
// if the index is greater than the maximum data array size,
|
||||||
|
// keep overwriting the last element until the endMarker is received.
|
||||||
|
if (ndx >= num_chars) {
|
||||||
|
ndx = num_chars - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the incoming character is the startMarker, set the recvInProgress flag
|
||||||
|
else if (c == startMarker) {
|
||||||
|
recvInProgress = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialMessage::parseData() { // split the data into its parts
|
||||||
|
this->populated_args = 0; // reset the populated args counter
|
||||||
|
char * indx; // this is used by strtok() as an index
|
||||||
|
int i = 0;
|
||||||
|
indx = strtok(temp_data, ","); // get the first part - the string
|
||||||
|
while(indx != NULL){
|
||||||
|
this->args[i] = atoi(indx);
|
||||||
|
populated_args++;
|
||||||
|
i++;
|
||||||
|
indx = strtok(NULL, ","); // this continues where the previous call left off
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialMessage::Update(){
|
||||||
|
readSerial();
|
||||||
|
if (data_recieved == true) {
|
||||||
|
// for debug only:
|
||||||
|
// Serial.print("Received:");
|
||||||
|
// Serial.print(data);
|
||||||
|
// Serial.println(":End");
|
||||||
|
strcpy(temp_data, data);
|
||||||
|
// this temporary copy is necessary to protect the original data
|
||||||
|
// because strtok() used in parseData() replaces the commas with \0
|
||||||
|
parseData();
|
||||||
|
//PrintArgs();
|
||||||
|
data_recieved = false;
|
||||||
|
new_data = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialMessage::IsNewData(){
|
||||||
|
return new_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialMessage::ClearNewData(){
|
||||||
|
new_data = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int * SerialMessage::GetArgs(){
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialMessage::GetArgsLength(){
|
||||||
|
return args_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialMessage::GetPopulatedArgs(){
|
||||||
|
return populated_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialMessage::PrintArgs(){
|
||||||
|
serial->print("Current number of args: ");
|
||||||
|
serial->println(populated_args);
|
||||||
|
for (int i = 0; i < populated_args; i++) {
|
||||||
|
serial->print(args[i]);
|
||||||
|
serial->print(" ");
|
||||||
|
}
|
||||||
|
serial->println();
|
||||||
|
}
|
||||||
87
lib/SerialMessage/SerialMessage.h
Normal file
87
lib/SerialMessage/SerialMessage.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* @file SerialMessage.h
|
||||||
|
* @brief This file contains the SerialMessage class
|
||||||
|
* @details This file contains the SerialMessage class which is used to parse serial messages
|
||||||
|
* @version 1.0.0
|
||||||
|
* @author Quinn Henthorne. Contact: quinn.henthorne@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SERIALMESSAGE_H
|
||||||
|
#define SERIALMESSAGE_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#define num_chars 500
|
||||||
|
|
||||||
|
class SerialMessage{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Serial Message object
|
||||||
|
*/
|
||||||
|
SerialMessage(HardwareSerial *serial = &Serial);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the SerialMessage object
|
||||||
|
*/
|
||||||
|
virtual void Init(unsigned int baud_rate = 115200);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the SerialMessage object and parse any data that's available
|
||||||
|
*/
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns true if there is new data available
|
||||||
|
* @return true if there is new data available
|
||||||
|
*/
|
||||||
|
bool IsNewData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the new data flag
|
||||||
|
*/
|
||||||
|
virtual void ClearNewData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the args array
|
||||||
|
* @return a pointer to the args array
|
||||||
|
*/
|
||||||
|
int * GetArgs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of args that have been populated for the current message
|
||||||
|
* @return the number of args that have been populated for the current message
|
||||||
|
*/
|
||||||
|
int GetArgsLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of args that have been populated for the current message
|
||||||
|
* @return the number of args that have been populated for the current message
|
||||||
|
*/
|
||||||
|
int GetPopulatedArgs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints the args array to the serial monitor
|
||||||
|
*/
|
||||||
|
virtual void PrintArgs();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void readSerial();
|
||||||
|
virtual void parseData();
|
||||||
|
|
||||||
|
bool new_data = false;
|
||||||
|
bool data_recieved = false;
|
||||||
|
bool recvInProgress = false;
|
||||||
|
char data[num_chars]; // an array to store the received data
|
||||||
|
char temp_data[num_chars]; // an array that will be used with strtok()
|
||||||
|
uint16_t ndx = 0;
|
||||||
|
const static int args_length = 30;
|
||||||
|
int populated_args = 0; // the number of args that have been populated for the current message
|
||||||
|
int args[args_length];
|
||||||
|
const char startMarker = '!';
|
||||||
|
const char endMarker = ';';
|
||||||
|
|
||||||
|
private:
|
||||||
|
HardwareSerial *serial;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
16
platformio.ini
Normal file
16
platformio.ini
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:denky32]
|
||||||
|
platform = espressif32
|
||||||
|
board = denky32
|
||||||
|
framework = arduino
|
||||||
|
monitor_speed = 115200
|
||||||
|
lib_deps = adafruit/Adafruit NeoPixel@^1.12.0
|
||||||
141
src/main.cpp
Normal file
141
src/main.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// Other peoples libraries
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <BluetoothSerial.h>
|
||||||
|
|
||||||
|
// project specific libraries
|
||||||
|
#include "BluetoothSerialMessage.h"
|
||||||
|
#include "BoardLayout.h"
|
||||||
|
#include "BOARD-DEFINITIONS.h"
|
||||||
|
#include "Color.h"
|
||||||
|
#include "ColorManager.h"
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// ----------------- Types ----------------------
|
||||||
|
// --------------------------------------------------
|
||||||
|
enum Commands : uint8_t{
|
||||||
|
BoardState = 0,
|
||||||
|
PING = 1,
|
||||||
|
SetStackColors = 2,
|
||||||
|
GoToIdle = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// ------------- OBJECT DEFINITIONS -----------------
|
||||||
|
// --------------------------------------------------
|
||||||
|
BluetoothSerial SerialBT;
|
||||||
|
BluetoothSerialMessage serialMessageBT(&SerialBT);
|
||||||
|
SerialMessage serialMessage(&Serial);
|
||||||
|
BoardLayout board(BOARD_WIDTH, BOARD_LENGTH, BOARD_HEIGHT, stacks);
|
||||||
|
|
||||||
|
// Temporary thing until we can get bluetooth color management working on the quest
|
||||||
|
ColorManager colorManager(&board);
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// ----------------- VARIABLES ----------------------
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// ----------------- FUNCTIONS ----------------------
|
||||||
|
// --------------------------------------------------
|
||||||
|
void printBoardState(){
|
||||||
|
// create a buffer to hold the board state
|
||||||
|
uint16_t boardState[BOARD_WIDTH * BOARD_LENGTH];
|
||||||
|
// read in the board state
|
||||||
|
board.GetBoardState(boardState);
|
||||||
|
|
||||||
|
Serial.print("!0,");
|
||||||
|
SerialBT.print("!0,");
|
||||||
|
|
||||||
|
for(int i = 0; i < (BOARD_WIDTH * BOARD_LENGTH); i++){
|
||||||
|
Serial.print(boardState[i]);
|
||||||
|
SerialBT.print(boardState[i]);
|
||||||
|
if(i == (BOARD_WIDTH * BOARD_LENGTH) - 1){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.print(",");
|
||||||
|
SerialBT.print(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(";");
|
||||||
|
SerialBT.println(";");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStackColor(int * args, int argsLength){
|
||||||
|
int stackNum = args[1];
|
||||||
|
int numColors = (argsLength - 2) / 3;
|
||||||
|
Color colors[numColors];
|
||||||
|
|
||||||
|
for(int i = 0; i < numColors; i++){
|
||||||
|
int red = args[2 + (i * 3)];
|
||||||
|
int green = args[3 + (i * 3)];
|
||||||
|
int blue = args[4 + (i * 3)];
|
||||||
|
colors[i] = Color(red, green, blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
board.SetStackColors(stackNum, colors);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseData(int * args, int argsLength){
|
||||||
|
int command = args[0];
|
||||||
|
switch(command){
|
||||||
|
case Commands::BoardState:
|
||||||
|
printBoardState();
|
||||||
|
break;
|
||||||
|
case Commands::PING:
|
||||||
|
Serial.print("!");
|
||||||
|
SerialBT.print("!");
|
||||||
|
Serial.print(Commands::PING);
|
||||||
|
SerialBT.print(Commands::PING);
|
||||||
|
Serial.println(";");
|
||||||
|
SerialBT.println(";");
|
||||||
|
break;
|
||||||
|
case Commands::SetStackColors:
|
||||||
|
Serial.println("!2;");
|
||||||
|
SerialBT.println("!2;");
|
||||||
|
colorManager.Enable(false);
|
||||||
|
setStackColor(args, argsLength);
|
||||||
|
break;
|
||||||
|
case Commands::GoToIdle:
|
||||||
|
Serial.println("!3;");
|
||||||
|
SerialBT.println("!3;");
|
||||||
|
colorManager.Enable(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println("INVALID COMMAND");
|
||||||
|
SerialBT.println("INVALID COMMAND");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// ----------------- SETUP AND LOOP -----------------
|
||||||
|
// --------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
SerialBT.begin("blockPartyBT");
|
||||||
|
Color colors[] = {Color(255, 0, 0), Color(0, 0, 0), Color(0, 0, 0)};
|
||||||
|
board.SetStackColors(2, colors);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if(board.BoardStateHasChanged()){
|
||||||
|
printBoardState();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO serial processing
|
||||||
|
serialMessage.Update();
|
||||||
|
if(serialMessage.IsNewData()){
|
||||||
|
parseData(serialMessage.GetArgs(), serialMessage.GetArgsLength());
|
||||||
|
serialMessage.ClearNewData();
|
||||||
|
}
|
||||||
|
serialMessageBT.Update();
|
||||||
|
if(serialMessageBT.IsNewData()){
|
||||||
|
parseData(serialMessageBT.GetArgs(), serialMessageBT.GetArgsLength());
|
||||||
|
serialMessageBT.ClearNewData();
|
||||||
|
}
|
||||||
|
colorManager.Update();
|
||||||
|
}
|
||||||
11
test/README
Normal file
11
test/README
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||||
Reference in New Issue
Block a user