From 920723afed3eaebd0754444c1de6136ff9f68edd Mon Sep 17 00:00:00 2001 From: redfast00 Date: Wed, 26 Aug 2020 23:33:01 +0200 Subject: [PATCH 1/8] Add more setup steps to the README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 796af29..c98c293 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ OBUS is a real-life version of the multiplayer game "Keep Talking And Nobody Exp 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. 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 ## Game From 54a87bb7118c5176ee77f0b1562bbd7eb5c8ef81 Mon Sep 17 00:00:00 2001 From: redfast00 Date: Wed, 26 Aug 2020 23:35:13 +0200 Subject: [PATCH 2/8] Change library to use callback functions, add basic hardware --- lib/obus_can.cpp | 5 ++++- lib/obus_module.cpp | 39 +++++++++++++++++++++++++++++++++++- lib/obus_module.h | 6 +++++- src/template_module/main.ino | 13 ++++++++++-- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/lib/obus_can.cpp b/lib/obus_can.cpp index 6068597..daacb36 100644 --- a/lib/obus_can.cpp +++ b/lib/obus_can.cpp @@ -2,9 +2,12 @@ #include "obus_can.h" +// Chip select for the CAN module +#define MCP_CS 8 + namespace obus_can { -MCP2515 mcp2515(10); +MCP2515 mcp2515(MCP_CS); bool is_init = false; diff --git a/lib/obus_module.cpp b/lib/obus_module.cpp index b3b6a21..8903f5b 100644 --- a/lib/obus_module.cpp +++ b/lib/obus_module.cpp @@ -1,11 +1,23 @@ #include "obus_can.h" #include "obus_module.h" +#define RED_LED A4 +#define GREEN_LED A5 + +#define MCP_INT 2 + namespace obus_module { + struct obus_can::module this_module; uint8_t strike_count; +bool running; +bool error; +uint32_t time_stop_strike_led; +void interrupt_can_error() { + error = true; +} void setup(uint8_t type, uint8_t id) { this_module.type = type; @@ -14,19 +26,44 @@ void setup(uint8_t type, uint8_t id) { obus_can::init(); strike_count = 0; + running = false; + error = false; + pinMode(RED_LED, OUTPUT); + pinMode(GREEN_LED, OUTPUT); + digitalWrite(RED_LED, LOW); + digitalWrite(GREEN_LED, LOW); } -void loop() { +bool loop(obus_can::message* message) { + // Check if the message buffer overflowed + if (error) { + // Loop forever while blinking status led orange + bool blink = false; + while (true) { + digitalWrite(RED_LED, blink); + digitalWrite(GREEN_LED, blink); + blink = !blink; + delay(500); + } + } + if (time_stop_strike_led && time_stop_strike_led > millis()) { + digitalWrite(RED_LED, LOW); + } + // TODO receive CAN frame and call callback functions } void strike() { strike_count++; + digitalWrite(RED_LED, HIGH); + time_stop_strike_led = millis() + 1000; obus_can::send_m_strike(this_module, strike_count); } void solve() { obus_can::send_m_solved(this_module); + digitalWrite(GREEN_LED, HIGH); + running = false; } } diff --git a/lib/obus_module.h b/lib/obus_module.h index 163c5e0..10dca7b 100644 --- a/lib/obus_module.h +++ b/lib/obus_module.h @@ -4,11 +4,15 @@ #include "Arduino.h" #include +void callback_game_start(); + +void callback_game_stop(); + namespace obus_module { void setup(uint8_t type, uint8_t id); -void loop(); +bool loop(obus_can::message* message); void strike(); diff --git a/src/template_module/main.ino b/src/template_module/main.ino index 0d704b4..d98c8d7 100644 --- a/src/template_module/main.ino +++ b/src/template_module/main.ino @@ -4,7 +4,7 @@ #include void setup() { - Serial.begin(9600); + Serial.begin(115200); // Choose one // Puzzle: a module that must be solved @@ -13,7 +13,16 @@ void setup() { // obusmodule_init(OBUS_TYPE_NEEDY, /* Retrieve ID from MOANA */); } +obus_can::message message; void loop() { - obus_module::loop(); + bool is_message_valid = obus_module::loop(&message); +} + +void callback_game_start() { + +} + +void callback_game_stop() { + } From 36af43b1445588210b29a17c90e292029a884095 Mon Sep 17 00:00:00 2001 From: redfast00 Date: Wed, 26 Aug 2020 23:36:35 +0200 Subject: [PATCH 3/8] Add basic module with two buttons --- src/modules/testmodule_buttons/doc/index.md | 6 +++ .../testmodule_buttons/testmodule_buttons.ino | 44 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/modules/testmodule_buttons/doc/index.md create mode 100644 src/modules/testmodule_buttons/testmodule_buttons.ino diff --git a/src/modules/testmodule_buttons/doc/index.md b/src/modules/testmodule_buttons/doc/index.md new file mode 100644 index 0000000..f751538 --- /dev/null +++ b/src/modules/testmodule_buttons/doc/index.md @@ -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. diff --git a/src/modules/testmodule_buttons/testmodule_buttons.ino b/src/modules/testmodule_buttons/testmodule_buttons.ino new file mode 100644 index 0000000..9ac77e7 --- /dev/null +++ b/src/modules/testmodule_buttons/testmodule_buttons.ino @@ -0,0 +1,44 @@ +// (c) 2020, redfast00 +// See the LICENSE file for conditions for copying + +#include +#include + +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::loop(&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 +} From a62562b716d3c3407f96a1f6264365ac39cf52ef Mon Sep 17 00:00:00 2001 From: redfast00 Date: Wed, 26 Aug 2020 23:41:00 +0200 Subject: [PATCH 4/8] Enable error interrupt --- lib/obus_can.cpp | 1 + lib/obus_module.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/obus_can.cpp b/lib/obus_can.cpp index daacb36..c923b93 100644 --- a/lib/obus_can.cpp +++ b/lib/obus_can.cpp @@ -74,6 +74,7 @@ void init() { mcp2515.reset(); mcp2515.setBitrate(CAN_50KBPS); mcp2515.setNormalMode(); + mcp2515.setRegister(MCP_CANINTE, CANINTF_ERRIF); } diff --git a/lib/obus_module.cpp b/lib/obus_module.cpp index 8903f5b..acb13f1 100644 --- a/lib/obus_module.cpp +++ b/lib/obus_module.cpp @@ -32,6 +32,7 @@ void setup(uint8_t type, uint8_t id) { pinMode(GREEN_LED, OUTPUT); digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, LOW); + attachInterrupt(digitalPinToInterrupt(MCP_INT), interrupt_can_error, RISING); } bool loop(obus_can::message* message) { From e5bf82352f030ca87ca0e44947aa4469b5dbba2d Mon Sep 17 00:00:00 2001 From: redfast00 Date: Thu, 27 Aug 2020 03:29:16 +0200 Subject: [PATCH 5/8] Different, less efficient way of checking if buffer overflowed --- lib/obus_can.cpp | 4 +++- lib/obus_can.h | 4 +++- lib/obus_module.cpp | 28 ++++++++++++++++------------ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/obus_can.cpp b/lib/obus_can.cpp index c923b93..d242019 100644 --- a/lib/obus_can.cpp +++ b/lib/obus_can.cpp @@ -74,7 +74,6 @@ void init() { mcp2515.reset(); mcp2515.setBitrate(CAN_50KBPS); mcp2515.setNormalMode(); - mcp2515.setRegister(MCP_CANINTE, CANINTF_ERRIF); } @@ -140,6 +139,9 @@ bool receive(struct message *msg) { return true; } +bool is_error_condition() { + return mcp2515.getInterrupts() & MCP2515::CANINTF_ERRIF; +} void send(struct message *msg) { if (!is_init) { diff --git a/lib/obus_can.h b/lib/obus_can.h index dee7d9e..2994a9c 100644 --- a/lib/obus_can.h +++ b/lib/obus_can.h @@ -77,7 +77,7 @@ void init(); /** * 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 */ bool receive(struct message *msg); @@ -90,6 +90,8 @@ bool receive(struct message *msg); */ void send(struct message *msg); +bool is_error_condition(); + /** * For internal use only diff --git a/lib/obus_module.cpp b/lib/obus_module.cpp index acb13f1..34efbc7 100644 --- a/lib/obus_module.cpp +++ b/lib/obus_module.cpp @@ -12,13 +12,8 @@ namespace obus_module { struct obus_can::module this_module; uint8_t strike_count; bool running; -bool error; uint32_t time_stop_strike_led; -void interrupt_can_error() { - error = true; -} - void setup(uint8_t type, uint8_t id) { this_module.type = type; this_module.id = id; @@ -27,18 +22,22 @@ void setup(uint8_t type, uint8_t id) { strike_count = 0; running = false; - error = false; pinMode(RED_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, LOW); - attachInterrupt(digitalPinToInterrupt(MCP_INT), interrupt_can_error, RISING); } bool loop(obus_can::message* message) { // Check if the message buffer overflowed - if (error) { - // Loop forever while blinking status led orange + if (time_stop_strike_led && time_stop_strike_led > millis()) { + digitalWrite(RED_LED, LOW); + } + // 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); @@ -47,10 +46,15 @@ bool loop(obus_can::message* message) { delay(500); } } - if (time_stop_strike_led && time_stop_strike_led > millis()) { - digitalWrite(RED_LED, LOW); + bool received = receive(message); + if (received) { + if (message->msg_type == OBUS_MSGTYPE_C_GAMESTART) { + callback_game_start(); + } /* TODO extend this for all messages */ else { + return true; + } + return false; } - // TODO receive CAN frame and call callback functions } From 908095d57211b180f2ac87015631b9a2659396bb Mon Sep 17 00:00:00 2001 From: redfast00 Date: Thu, 27 Aug 2020 04:02:10 +0200 Subject: [PATCH 6/8] Cleanup --- lib/obus_module.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/obus_module.cpp b/lib/obus_module.cpp index 34efbc7..c0e1ff7 100644 --- a/lib/obus_module.cpp +++ b/lib/obus_module.cpp @@ -29,9 +29,11 @@ void setup(uint8_t type, uint8_t id) { } bool loop(obus_can::message* message) { - // Check if the message buffer overflowed + // 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 @@ -46,12 +48,25 @@ bool loop(obus_can::message* message) { delay(500); } } - bool received = receive(message); - if (received) { - if (message->msg_type == OBUS_MSGTYPE_C_GAMESTART) { - callback_game_start(); - } /* TODO extend this for all messages */ else { - return true; + if (obus_can::receive(message)) { + switch(message->msg_type) { + case OBUS_MSGTYPE_C_GAMESTART: + running = 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: + running = false; + callback_game_stop(); + break; + case OBUS_MSGTYPE_C_ACK: + break; + case OBUS_MSGTYPE_C_STATE: + return true; } return false; } From ac2c8129a91cd89f2f94caeb1ba2ac2514aaa942 Mon Sep 17 00:00:00 2001 From: redfast00 Date: Thu, 27 Aug 2020 05:30:22 +0200 Subject: [PATCH 7/8] Add needy module, clean up code --- lib/obus_module.cpp | 28 ++++++-- lib/obus_module.h | 6 +- .../testmodule_buttons/testmodule_buttons.ino | 2 +- .../testmodule_needy_buttons/doc/index.md | 6 ++ .../testmodule_needy_buttons.ino | 68 +++++++++++++++++++ src/template_module/main.ino | 2 +- 6 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 src/modules/testmodule_needy_buttons/doc/index.md create mode 100644 src/modules/testmodule_needy_buttons/testmodule_needy_buttons.ino diff --git a/lib/obus_module.cpp b/lib/obus_module.cpp index c0e1ff7..81ce44f 100644 --- a/lib/obus_module.cpp +++ b/lib/obus_module.cpp @@ -11,7 +11,7 @@ namespace obus_module { struct obus_can::module this_module; uint8_t strike_count; -bool running; +bool active; uint32_t time_stop_strike_led; void setup(uint8_t type, uint8_t id) { @@ -21,14 +21,14 @@ void setup(uint8_t type, uint8_t id) { obus_can::init(); strike_count = 0; - running = false; + active = false; pinMode(RED_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, LOW); } -bool loop(obus_can::message* message) { +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()) { @@ -37,7 +37,7 @@ bool loop(obus_can::message* message) { } // 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 + // 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; @@ -51,7 +51,7 @@ bool loop(obus_can::message* message) { if (obus_can::receive(message)) { switch(message->msg_type) { case OBUS_MSGTYPE_C_GAMESTART: - running = true; + active = true; callback_game_start(); break; case OBUS_MSGTYPE_C_HELLO: @@ -60,7 +60,7 @@ bool loop(obus_can::message* message) { case OBUS_MSGTYPE_C_SOLVED: case OBUS_MSGTYPE_C_TIMEOUT: case OBUS_MSGTYPE_C_STRIKEOUT: - running = false; + active = false; callback_game_stop(); break; case OBUS_MSGTYPE_C_ACK: @@ -70,10 +70,17 @@ bool loop(obus_can::message* message) { } return false; } +} +bool loopNeedy(obus_can::message* message) { + // For now this is the same function + return loopPuzzle(message); } void strike() { + if (!active) { + return; + } strike_count++; digitalWrite(RED_LED, HIGH); time_stop_strike_led = millis() + 1000; @@ -81,9 +88,16 @@ void strike() { } void solve() { + if (!active) { + return; + } obus_can::send_m_solved(this_module); digitalWrite(GREEN_LED, HIGH); - running = false; + active = false; +} + +bool is_active() { + return active; } } diff --git a/lib/obus_module.h b/lib/obus_module.h index 10dca7b..e5ad254 100644 --- a/lib/obus_module.h +++ b/lib/obus_module.h @@ -12,12 +12,16 @@ namespace obus_module { void setup(uint8_t type, uint8_t id); -bool loop(obus_can::message* message); +bool loopPuzzle(obus_can::message* message); + +bool loopNeedy(obus_can::message* message); void strike(); void solve(); +bool is_active(); + } #endif /* end of include guard: OBUS_MODULE_H */ diff --git a/src/modules/testmodule_buttons/testmodule_buttons.ino b/src/modules/testmodule_buttons/testmodule_buttons.ino index 9ac77e7..501e17c 100644 --- a/src/modules/testmodule_buttons/testmodule_buttons.ino +++ b/src/modules/testmodule_buttons/testmodule_buttons.ino @@ -18,7 +18,7 @@ void setup() { obus_can::message message; void loop() { - bool received = obus_module::loop(&message); + 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(); diff --git a/src/modules/testmodule_needy_buttons/doc/index.md b/src/modules/testmodule_needy_buttons/doc/index.md new file mode 100644 index 0000000..56142da --- /dev/null +++ b/src/modules/testmodule_needy_buttons/doc/index.md @@ -0,0 +1,6 @@ +## Testmodule needy buttons + +If the module starts making a sound, press the button. + +### Credits +Module developed by redfast00. diff --git a/src/modules/testmodule_needy_buttons/testmodule_needy_buttons.ino b/src/modules/testmodule_needy_buttons/testmodule_needy_buttons.ino new file mode 100644 index 0000000..ab6b8df --- /dev/null +++ b/src/modules/testmodule_needy_buttons/testmodule_needy_buttons.ino @@ -0,0 +1,68 @@ +// (c) 2020, redfast00 +// See the LICENSE file for conditions for copying + +#include +#include + +#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() { + +} diff --git a/src/template_module/main.ino b/src/template_module/main.ino index d98c8d7..a558084 100644 --- a/src/template_module/main.ino +++ b/src/template_module/main.ino @@ -10,7 +10,7 @@ void setup() { // Puzzle: a module that must be solved obus_module::setup(OBUS_TYPE_PUZZLE, /* Retrieve ID from MOANA */); // 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; From bcc4a484516ed587c9acc83bcbdcc7cd5a32a1bb Mon Sep 17 00:00:00 2001 From: redfast00 Date: Mon, 31 Aug 2020 19:52:31 +0200 Subject: [PATCH 8/8] Change loop functions in template --- src/template_module/main.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/template_module/main.ino b/src/template_module/main.ino index a558084..5e7fa0d 100644 --- a/src/template_module/main.ino +++ b/src/template_module/main.ino @@ -16,7 +16,8 @@ void setup() { obus_can::message message; void loop() { - bool is_message_valid = obus_module::loop(&message); + bool is_message_valid = obus_module::loop_puzzle(&message); + // bool bool is_message_valid = obus_module::loop_needy(&message); } void callback_game_start() {