commit
26df06e55f
10 changed files with 232 additions and 9 deletions
|
@ -7,7 +7,9 @@ You see an armed time bomb but don't know how to disarm it. Your friends found a
|
||||||
1. [Install](https://www.arduino.cc/en/Guide/#install-the-arduino-desktop-ide) the Arduino IDE.
|
1. [Install](https://www.arduino.cc/en/Guide/#install-the-arduino-desktop-ide) the Arduino IDE.
|
||||||
2. Clone this repository with Git in a permanent location on your drive.
|
2. Clone this repository with Git in a permanent location on your drive.
|
||||||
3. Symlink the library: `ln -s /ABSOLUTE/PATH/TO/REPO/lib /PATH/TO/Arduino/libraries/obus`
|
3. Symlink the library: `ln -s /ABSOLUTE/PATH/TO/REPO/lib /PATH/TO/Arduino/libraries/obus`
|
||||||
4. TODO
|
(on most Linux distro's, this the Arduino folder is in `$HOME/Arduino`)
|
||||||
|
4. Follow [these steps](https://github.com/autowp/arduino-mcp2515/#software-usage) to install the CAN library
|
||||||
|
5. Execute `./src/new_module.sh` to create a new module
|
||||||
|
|
||||||
# Background
|
# Background
|
||||||
## Game
|
## Game
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
|
|
||||||
#include "obus_can.h"
|
#include "obus_can.h"
|
||||||
|
|
||||||
|
// Chip select for the CAN module
|
||||||
|
#define MCP_CS 8
|
||||||
|
|
||||||
namespace obus_can {
|
namespace obus_can {
|
||||||
|
|
||||||
MCP2515 mcp2515(10);
|
MCP2515 mcp2515(MCP_CS);
|
||||||
bool is_init = false;
|
bool is_init = false;
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,6 +139,9 @@ bool receive(struct message *msg) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_error_condition() {
|
||||||
|
return mcp2515.getInterrupts() & MCP2515::CANINTF_ERRIF;
|
||||||
|
}
|
||||||
|
|
||||||
void send(struct message *msg) {
|
void send(struct message *msg) {
|
||||||
if (!is_init) {
|
if (!is_init) {
|
||||||
|
|
|
@ -77,7 +77,7 @@ void init();
|
||||||
/**
|
/**
|
||||||
* Receive a message
|
* Receive a message
|
||||||
*
|
*
|
||||||
* @param msg Pointer to memory where the received message will be wriitten
|
* @param msg Pointer to memory where the received message will be written
|
||||||
* @return true if a message was received, false otherwise
|
* @return true if a message was received, false otherwise
|
||||||
*/
|
*/
|
||||||
bool receive(struct message *msg);
|
bool receive(struct message *msg);
|
||||||
|
@ -90,6 +90,8 @@ bool receive(struct message *msg);
|
||||||
*/
|
*/
|
||||||
void send(struct message *msg);
|
void send(struct message *msg);
|
||||||
|
|
||||||
|
bool is_error_condition();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For internal use only
|
* For internal use only
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
#include "obus_can.h"
|
#include "obus_can.h"
|
||||||
#include "obus_module.h"
|
#include "obus_module.h"
|
||||||
|
|
||||||
|
#define RED_LED A4
|
||||||
|
#define GREEN_LED A5
|
||||||
|
|
||||||
|
#define MCP_INT 2
|
||||||
|
|
||||||
namespace obus_module {
|
namespace obus_module {
|
||||||
|
|
||||||
|
|
||||||
struct obus_can::module this_module;
|
struct obus_can::module this_module;
|
||||||
uint8_t strike_count;
|
uint8_t strike_count;
|
||||||
|
bool active;
|
||||||
|
uint32_t time_stop_strike_led;
|
||||||
|
|
||||||
void setup(uint8_t type, uint8_t id) {
|
void setup(uint8_t type, uint8_t id) {
|
||||||
this_module.type = type;
|
this_module.type = type;
|
||||||
|
@ -14,19 +21,83 @@ void setup(uint8_t type, uint8_t id) {
|
||||||
obus_can::init();
|
obus_can::init();
|
||||||
|
|
||||||
strike_count = 0;
|
strike_count = 0;
|
||||||
|
active = false;
|
||||||
|
pinMode(RED_LED, OUTPUT);
|
||||||
|
pinMode(GREEN_LED, OUTPUT);
|
||||||
|
digitalWrite(RED_LED, LOW);
|
||||||
|
digitalWrite(GREEN_LED, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
bool loopPuzzle(obus_can::message* message) {
|
||||||
|
// Check if we need to turn the red "strike" LED back off after
|
||||||
|
// turning it on because of a strike
|
||||||
|
if (time_stop_strike_led && time_stop_strike_led > millis()) {
|
||||||
|
digitalWrite(RED_LED, LOW);
|
||||||
|
time_stop_strike_led = 0;
|
||||||
|
}
|
||||||
|
// TODO this can be more efficient by only enabling error interrupts and
|
||||||
|
// reacting to the interrupt instead of checking if the flag is set in a loop
|
||||||
|
// We will need to fork our CAN library for this, because the needed functions
|
||||||
|
// are private
|
||||||
|
if (obus_can::is_error_condition()) {
|
||||||
|
bool blink = false;
|
||||||
|
while (true) {
|
||||||
|
digitalWrite(RED_LED, blink);
|
||||||
|
digitalWrite(GREEN_LED, blink);
|
||||||
|
blink = !blink;
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obus_can::receive(message)) {
|
||||||
|
switch(message->msg_type) {
|
||||||
|
case OBUS_MSGTYPE_C_GAMESTART:
|
||||||
|
active = true;
|
||||||
|
callback_game_start();
|
||||||
|
break;
|
||||||
|
case OBUS_MSGTYPE_C_HELLO:
|
||||||
|
obus_can::send_m_hello(this_module);
|
||||||
|
break;
|
||||||
|
case OBUS_MSGTYPE_C_SOLVED:
|
||||||
|
case OBUS_MSGTYPE_C_TIMEOUT:
|
||||||
|
case OBUS_MSGTYPE_C_STRIKEOUT:
|
||||||
|
active = false;
|
||||||
|
callback_game_stop();
|
||||||
|
break;
|
||||||
|
case OBUS_MSGTYPE_C_ACK:
|
||||||
|
break;
|
||||||
|
case OBUS_MSGTYPE_C_STATE:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loopNeedy(obus_can::message* message) {
|
||||||
|
// For now this is the same function
|
||||||
|
return loopPuzzle(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void strike() {
|
void strike() {
|
||||||
|
if (!active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
strike_count++;
|
strike_count++;
|
||||||
|
digitalWrite(RED_LED, HIGH);
|
||||||
|
time_stop_strike_led = millis() + 1000;
|
||||||
obus_can::send_m_strike(this_module, strike_count);
|
obus_can::send_m_strike(this_module, strike_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void solve() {
|
void solve() {
|
||||||
|
if (!active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
obus_can::send_m_solved(this_module);
|
obus_can::send_m_solved(this_module);
|
||||||
|
digitalWrite(GREEN_LED, HIGH);
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_active() {
|
||||||
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,24 @@
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include <obus_can.h>
|
#include <obus_can.h>
|
||||||
|
|
||||||
|
void callback_game_start();
|
||||||
|
|
||||||
|
void callback_game_stop();
|
||||||
|
|
||||||
namespace obus_module {
|
namespace obus_module {
|
||||||
|
|
||||||
void setup(uint8_t type, uint8_t id);
|
void setup(uint8_t type, uint8_t id);
|
||||||
|
|
||||||
void loop();
|
bool loopPuzzle(obus_can::message* message);
|
||||||
|
|
||||||
|
bool loopNeedy(obus_can::message* message);
|
||||||
|
|
||||||
void strike();
|
void strike();
|
||||||
|
|
||||||
void solve();
|
void solve();
|
||||||
|
|
||||||
|
bool is_active();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* end of include guard: OBUS_MODULE_H */
|
#endif /* end of include guard: OBUS_MODULE_H */
|
||||||
|
|
6
src/modules/testmodule_buttons/doc/index.md
Normal file
6
src/modules/testmodule_buttons/doc/index.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
## Testmodule buttons
|
||||||
|
|
||||||
|
Don't press the red button. Press the green button to solve the module.
|
||||||
|
|
||||||
|
### Credits
|
||||||
|
Module developed by redfast00.
|
44
src/modules/testmodule_buttons/testmodule_buttons.ino
Normal file
44
src/modules/testmodule_buttons/testmodule_buttons.ino
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// (c) 2020, redfast00
|
||||||
|
// See the LICENSE file for conditions for copying
|
||||||
|
|
||||||
|
#include <obus_module.h>
|
||||||
|
#include <ezButton.h>
|
||||||
|
|
||||||
|
ezButton red_button(5);
|
||||||
|
ezButton green_button(6);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
// WARNING: do not use 255 for your module
|
||||||
|
obus_module::setup(OBUS_TYPE_PUZZLE, 255);
|
||||||
|
red_button.setDebounceTime(100);
|
||||||
|
green_button.setDebounceTime(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
obus_can::message message;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
bool received = obus_module::loopPuzzle(&message);
|
||||||
|
// TODO handle update frames (not needed for this module, but could be useful as example code)
|
||||||
|
|
||||||
|
red_button.loop();
|
||||||
|
green_button.loop();
|
||||||
|
|
||||||
|
if (red_button.getCount() > 0) {
|
||||||
|
red_button.resetCount();
|
||||||
|
obus_module::strike();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (green_button.getCount() > 0) {
|
||||||
|
green_button.resetCount();
|
||||||
|
obus_module::solve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_game_start() {
|
||||||
|
// Intentionally emtpy
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_game_stop() {
|
||||||
|
// Intentionally empty
|
||||||
|
}
|
6
src/modules/testmodule_needy_buttons/doc/index.md
Normal file
6
src/modules/testmodule_needy_buttons/doc/index.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
## Testmodule needy buttons
|
||||||
|
|
||||||
|
If the module starts making a sound, press the button.
|
||||||
|
|
||||||
|
### Credits
|
||||||
|
Module developed by redfast00.
|
|
@ -0,0 +1,68 @@
|
||||||
|
// (c) 2020, redfast00
|
||||||
|
// See the LICENSE file for conditions for copying
|
||||||
|
|
||||||
|
#include <obus_module.h>
|
||||||
|
#include <ezButton.h>
|
||||||
|
|
||||||
|
#define SPEAKER_PIN 10
|
||||||
|
|
||||||
|
ezButton green_button(6);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
// WARNING: do not use 255 for your module
|
||||||
|
obus_module::setup(OBUS_TYPE_NEEDY, 255);
|
||||||
|
green_button.setDebounceTime(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
obus_can::message message;
|
||||||
|
|
||||||
|
uint32_t next_activation_time = 0;
|
||||||
|
uint32_t trigger_time = 0;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
bool is_message_valid = obus_module::loopNeedy(&message);
|
||||||
|
green_button.loop();
|
||||||
|
|
||||||
|
// Every second, have a 1/20 chance to trigger the countdown
|
||||||
|
if (obus_module::is_active() && !trigger_time && (millis() > next_activation_time)) {
|
||||||
|
next_activation_time = millis() + 1000;
|
||||||
|
if (random(20) == 0) {
|
||||||
|
trigger_time = millis() + 30000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strike if time runs out
|
||||||
|
if (trigger_time && millis() > trigger_time) {
|
||||||
|
obus_module::strike();
|
||||||
|
trigger_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the button is pressed, reset countdown if countdown is running, else strike
|
||||||
|
if (green_button.getCount() > 0) {
|
||||||
|
green_button.resetCount();
|
||||||
|
if (trigger_time) {
|
||||||
|
trigger_time = 0;
|
||||||
|
} else {
|
||||||
|
obus_module::strike();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play the appropriate sound
|
||||||
|
if (trigger_time && millis() > trigger_time - 15000) {
|
||||||
|
tone(SPEAKER_PIN, 440);
|
||||||
|
}
|
||||||
|
else if (trigger_time) {
|
||||||
|
tone(SPEAKER_PIN, 449);
|
||||||
|
} else {
|
||||||
|
noTone(SPEAKER_PIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_game_start() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_game_stop() {
|
||||||
|
|
||||||
|
}
|
|
@ -4,16 +4,26 @@
|
||||||
#include <obus_module.h>
|
#include <obus_module.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(9600);
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Choose one
|
// Choose one
|
||||||
// Puzzle: a module that must be solved
|
// Puzzle: a module that must be solved
|
||||||
obus_module::setup(OBUS_TYPE_PUZZLE, /* Retrieve ID from MOANA */);
|
obus_module::setup(OBUS_TYPE_PUZZLE, /* Retrieve ID from MOANA */);
|
||||||
// Needy: a module that periodically requires an action not to get strikes
|
// Needy: a module that periodically requires an action not to get strikes
|
||||||
// obusmodule_init(OBUS_TYPE_NEEDY, /* Retrieve ID from MOANA */);
|
// obus_module::setup(OBUS_TYPE_NEEDY, /* Retrieve ID from MOANA */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obus_can::message message;
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
obus_module::loop();
|
bool is_message_valid = obus_module::loop_puzzle(&message);
|
||||||
|
// bool bool is_message_valid = obus_module::loop_needy(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_game_start() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_game_stop() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue