Deterministic modules
This commit is contained in:
parent
f98868d4f3
commit
463ebfa3e0
6 changed files with 47 additions and 7 deletions
|
@ -93,10 +93,19 @@ same effect as just resetting the microcontroller, so if your state is too hard
|
|||
|
||||
- The setup code, initializing your microcontroller and setting the type and id of the module with `obus_module::setup`
|
||||
- The main loop code. This should call the `loopPuzzle` function frequently so that all CAN packets can be handled.
|
||||
If you are using calls to `delay()`, try to replace them with a timer (a variable that keeps track of when something should happen). That way the loop can continue executing, without being stuck in the `delay()` function.
|
||||
- A call to the `obus_module::solve` function
|
||||
- A description for the expert of how to defuse the module in `doc/index.md` of your module folder
|
||||
- The `callback_game_start`, `callback_game_stop` and `callback_info` functions. These can be empty.
|
||||
- The `callback_game_start` and `callback_game_stop` functions. These can be empty.
|
||||
|
||||
Some tips:
|
||||
|
||||
- If you are using calls to `delay()`, try to replace them with a timer (a variable that keeps track of when something should happen).
|
||||
That way the function that handles CAN messages (`loopPuzzle`) can continue executing, without the microcontroller being stuck in the `delay()` function.
|
||||
The `loopPuzzle` function will automatically put itself into an error state if it has been too long since it has been called. This is meant to make
|
||||
writing correct code easier: that way you discover your code needs to be rewritten easily instead of having to figure out that and why messages are dropped.
|
||||
- Every time you play the game, it should be different (otherwise the defuser could just memorize what to do, this would be no fun for the experts).
|
||||
To accomplish this, you can use the `random()` function. You don't need to seed it (we recommend against it), because the OBUS framework already
|
||||
seeds this for you every game. That way, we can replay games for debugging if needed.
|
||||
|
||||
## More advanced puzzle modules
|
||||
|
||||
|
|
|
@ -68,8 +68,9 @@ Types for controller:
|
|||
|
||||
- 7 info start
|
||||
[ X B B B B B B B ]
|
||||
--------------
|
||||
reserved
|
||||
-------- -----
|
||||
↓ reserved
|
||||
random seed
|
||||
|
||||
- 8-255 reserved
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ uint8_t payload_type(uint8_t module_type, uint8_t module_id, uint8_t msg_type) {
|
|||
case OBUS_MSGTYPE_C_STRIKEOUT:
|
||||
return OBUS_PAYLDTYPE_GAMESTATUS;
|
||||
|
||||
case OBUS_MSGTYPE_C_INFOSTART:
|
||||
return OBUS_PAYLDTYPE_INFOSTART;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
|
@ -142,13 +145,22 @@ bool receive(struct message *msg) {
|
|||
case OBUS_PAYLDTYPE_MODULEADDR:
|
||||
{
|
||||
if (receive_frame.can_dlc < 3) {
|
||||
Serial.println(F("W Received illegal count msg: payload <3"));
|
||||
Serial.println(F("W Received illegal moduleaddr msg: payload <3"));
|
||||
return false;
|
||||
}
|
||||
msg->payload_address.type = receive_frame.data[1];
|
||||
msg->payload_address.id = receive_frame.data[2];
|
||||
}
|
||||
break;
|
||||
case OBUS_PAYLDTYPE_INFOSTART:
|
||||
{
|
||||
if (receive_frame.can_dlc < 5) {
|
||||
Serial.println(F("W Received illegal infostart msg: payload <5"));
|
||||
return false;
|
||||
}
|
||||
msg->infostart.seed = unpack_4b_into_u32(&(receive_frame.data[1]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Serial.println(F("W Couldn't determine payload type"));
|
||||
return false;
|
||||
|
@ -206,6 +218,11 @@ void send(struct message *msg) {
|
|||
send_frame.data[2] = msg->payload_address.id;
|
||||
break;
|
||||
|
||||
case OBUS_PAYLDTYPE_INFOSTART:
|
||||
pack_u32_into_4b(&(send_frame.data[1]), msg->gamestatus.time_left);
|
||||
length = 5;
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.print(F("E Unknown payload type "));
|
||||
Serial.println(pyld_type);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define OBUS_PAYLDTYPE_COUNT 2
|
||||
#define OBUS_PAYLDTYPE_INFO 3
|
||||
#define OBUS_PAYLDTYPE_MODULEADDR 4
|
||||
#define OBUS_PAYLDTYPE_INFOSTART 5
|
||||
|
||||
#define OBUS_PAYLD_INFO_MAXLEN (OBUS_MSG_LENGTH - 1)
|
||||
|
||||
|
@ -57,6 +58,9 @@ struct payld_infomessage {
|
|||
uint8_t len;
|
||||
uint8_t data[OBUS_PAYLD_INFO_MAXLEN];
|
||||
};
|
||||
struct payld_infostart {
|
||||
uint32_t seed;
|
||||
};
|
||||
|
||||
|
||||
struct message {
|
||||
|
@ -69,6 +73,7 @@ struct message {
|
|||
uint8_t count;
|
||||
struct payld_infomessage infomessage;
|
||||
struct module payload_address;
|
||||
struct payld_infostart infostart;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -208,9 +213,10 @@ inline void send_c_timeout(
|
|||
/**
|
||||
* Send a controller "info start" OBUS message
|
||||
*/
|
||||
inline void send_c_infostart(struct module from) {
|
||||
inline void send_c_infostart(struct module from, uint32_t seed) {
|
||||
assert(from.type == OBUS_TYPE_CONTROLLER);
|
||||
struct message msg = _msg(from, false, OBUS_MSGTYPE_C_INFOSTART);
|
||||
msg.infostart.seed = seed;
|
||||
send(&msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -165,6 +165,9 @@ bool loopPuzzle(obus_can::message* message, void (*callback_game_start)(uint8_t
|
|||
case OBUS_MSGTYPE_C_STATE:
|
||||
callback_state(message->gamestatus.time_left, message->gamestatus.strikes, message->gamestatus.max_strikes, message->gamestatus.puzzle_modules_left);
|
||||
break;
|
||||
case OBUS_MSGTYPE_C_INFOSTART:
|
||||
randomSeed(message->infostart.seed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -192,6 +195,7 @@ bool loopInfo(obus_can::message* message, int (*info_generator)(uint8_t*)) {
|
|||
switch (message->msg_type) {
|
||||
case OBUS_MSGTYPE_C_INFOSTART:
|
||||
{
|
||||
randomSeed(message->infostart.seed);
|
||||
uint8_t info_message[OBUS_PAYLD_INFO_MAXLEN];
|
||||
int len = info_generator(info_message);
|
||||
obus_can::send_i_infomessage(this_module, info_message, len);
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#define OBUS_GAME_DURATION_MS ((uint32_t) OBUS_GAME_DURATION*1000)
|
||||
#define OBUS_INFO_DURATION_MS ((uint32_t) OBUS_INFO_DURATION*1000)
|
||||
|
||||
// This should be changed every run, but for development it's useful to pin this
|
||||
#define OBUS_RANDOM_SEED 42
|
||||
|
||||
#define DIVIDE_CEIL(dividend, divisor) ((dividend + (divisor - 1)) / divisor)
|
||||
#define MAX_AMOUNT_PUZZLES (UINT8_MAX + 1) // The ID of a puzzle is a zero-based uint8
|
||||
|
||||
|
@ -104,7 +107,7 @@ void solve_puzzle_in_bit_vector(uint8_t module_id) {
|
|||
void start_info() {
|
||||
state = STATE_INFO;
|
||||
info_round_start = millis();
|
||||
obus_can::send_c_infostart(this_module);
|
||||
obus_can::send_c_infostart(this_module, OBUS_RANDOM_SEED);
|
||||
Serial.println(F(" Start of info round"));
|
||||
tm.displayText("InFO ");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue