diff --git a/README.md b/README.md index 00614a8..1ade192 100644 --- a/README.md +++ b/README.md @@ -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. 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 diff --git a/lib/obus_can.cpp b/lib/obus_can.cpp index 6068597..d242019 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; @@ -136,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 b3b6a21..81ce44f 100644 --- a/lib/obus_module.cpp +++ b/lib/obus_module.cpp @@ -1,11 +1,18 @@ #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 active; +uint32_t time_stop_strike_led; void setup(uint8_t type, uint8_t id) { this_module.type = type; @@ -14,19 +21,83 @@ void setup(uint8_t type, uint8_t id) { obus_can::init(); 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() { + if (!active) { + return; + } strike_count++; + digitalWrite(RED_LED, HIGH); + time_stop_strike_led = millis() + 1000; obus_can::send_m_strike(this_module, strike_count); } void solve() { + if (!active) { + return; + } obus_can::send_m_solved(this_module); + digitalWrite(GREEN_LED, HIGH); + active = false; +} + +bool is_active() { + return active; } } diff --git a/lib/obus_module.h b/lib/obus_module.h index f3ed0a3..8c585e1 100644 --- a/lib/obus_module.h +++ b/lib/obus_module.h @@ -8,16 +8,24 @@ #define OBUS_NEEDY_ID_DEVELOPMENT 255 #define OBUS_INFO_ID_DEVELOPMENT 255 +void callback_game_start(); + +void callback_game_stop(); + namespace obus_module { 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 solve(); +bool is_active(); + } #endif /* end of include guard: OBUS_MODULE_H */ 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..501e17c --- /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::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 +} 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 5d9baef..3b05aa5 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,17 @@ void setup() { // obus_module::setup(OBUS_TYPE_NEEDY, OBUS_NEEDY_ID_DEVELOPMENT); } +obus_can::message message; 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() { + }