Merge pull request #5 from ZeusWPI/module-code

Module
This commit is contained in:
redfast00 2020-09-06 14:19:35 +02:00 committed by GitHub
commit 26df06e55f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 232 additions and 9 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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;
} }
} }

View file

@ -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 */

View 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.

View 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
}

View file

@ -0,0 +1,6 @@
## Testmodule needy buttons
If the module starts making a sound, press the button.
### Credits
Module developed by redfast00.

View file

@ -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() {
}

View file

@ -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() {
} }