Update library and stuff

This commit is contained in:
Midgard 2020-08-20 21:13:19 +02:00
parent 341ff1bb1e
commit 9dc7c399f2
Signed by: midgard
GPG key ID: 511C112F1331BBB4
3 changed files with 279 additions and 232 deletions

View file

@ -6,22 +6,27 @@
#define STATE_HELLO 1
#define STATE_GAME 2
#define OBUS_MAX_STRIKES 3 // Number of strikes allowed until game over
#define OBUS_MAX_STRIKES 3 // Number of strikes allowed until game over
#define OBUS_GAME_DURATION 10 // Duration of the game in seconds
#define OBUS_GAME_DURATION_MS ((uint32_t) OBUS_GAME_DURATION*1000)
#define DIVIDE_CEIL(dividend, divisor) ((dividend + (divisor - 1)) / divisor)
#define MAX_AMOUNT_PUZZLES 256 // The ID of a puzzle is uint8
uint8_t state = STATE_INACTIVE;
struct module connected_modules_ids[OBUS_MAX_MODULES];
uint8_t nr_connected_modules;
uint8_t strikes;
// Bit vectors for checking if game is solved or not
uint8_t unsolved_puzzles[32]; // 256 bits
// Bitvector for checking if game is solved or not
// 32 bits per uint32 bitvector field
#define N_UNSOLVED_PUZZLES DIVIDE_CEIL(MAX_AMOUNT_PUZZLES, 32)
uint32_t unsolved_puzzles[N_UNSOLVED_PUZZLES];
// TIMERS
// Timers
uint32_t hello_round_start;
uint32_t game_start;
uint32_t last_update;
@ -40,15 +45,13 @@ void setup() {
}
uint8_t check_solved() {
uint8_t solved = 1;
for (uint8_t i = 0; i < 32; i++) {
if (unsolved_puzzles != 0) {
solved = 0;
break;
bool check_solved() {
for (uint8_t i = 0; i < N_UNSOLVED_PUZZLES; i++) {
if (unsolved_puzzles[i] != 0) {
return false;
}
}
return solved;
return true;
}
@ -72,20 +75,13 @@ void start_hello() {
nr_connected_modules = 0;
// Zero bit vectors
for (uint8_t i = 0; i < 32; i++) {
for (uint8_t i = 0; i < N_UNSOLVED_PUZZLES; i++) {
unsolved_puzzles[i] = 0;
}
struct obus_message msg = obuscan_msg_c_hello(this_module);
obuscan_send(&msg);
obuscan_send_c_hello(this_module);
Serial.println(F("Start of discovery round"));
}
void send_ack() {
struct obus_message msg = obuscan_msg_c_ack(this_module);
obuscan_send(&msg);
Serial.println(F(" Start of discovery round"));
}
@ -94,8 +90,8 @@ void receive_hello() {
uint32_t current_time = millis();
if (obuscan_receive(&msg)) {
if (msg.msg_type == OBUS_MSGTYPE_M_HELLO) {
Serial.print("Registered module ");
if (msg.msg_type == OBUS_MSGTYPE_M_HELLO) {
Serial.print(" Registered module ");
Serial.println(full_module_id(msg.from));
connected_modules_ids[nr_connected_modules] = msg.from;
nr_connected_modules++;
@ -104,11 +100,11 @@ void receive_hello() {
add_module_to_bit_vector(full_module_id(msg.from));
}
send_ack();
Serial.println("ACK");
obuscan_send_c_ack(this_module);
Serial.println(" ACK");
}
} else if (current_time - hello_round_start > OBUS_DISC_DURATION_MS) {
Serial.println("End of discovery round");
Serial.println(" End of discovery round");
initialize_game();
}
}
@ -121,9 +117,9 @@ void initialize_game() {
last_update = game_start;
state = STATE_GAME;
Serial.println("Game started");
Serial.println(" Game started");
send_game_update(OBUS_MSGTYPE_C_GAMESTART, OBUS_GAME_DURATION_MS);
obuscan_send_c_gamestart(this_module, OBUS_GAME_DURATION_MS, strikes, OBUS_MAX_STRIKES);
}
@ -152,22 +148,6 @@ void receive_module_update() {
}
void send_game_update(uint8_t msg_type, uint32_t time_left) {
Serial.print(F("Send "));
Serial.print(msg_type);
Serial.print(F(": "));
Serial.print(time_left);
Serial.print(F(", "));
Serial.print(strikes);
Serial.print(F("/"));
Serial.println(OBUS_MAX_STRIKES);
struct obus_message msg = obuscan_msg_c_payld_gamestatus(
this_module, false, msg_type, time_left, strikes, OBUS_MAX_STRIKES);
obuscan_send(&msg);
}
void game_loop() {
uint32_t current_time = millis();
uint32_t time_elapsed = current_time - game_start;
@ -178,24 +158,26 @@ void game_loop() {
receive_module_update();
if (check_solved()) {
Serial.println("Game solved");
send_game_update(OBUS_MSGTYPE_C_SOLVED, time_left);
Serial.println(" Game solved");
obuscan_send_c_solved(this_module, time_left, strikes, OBUS_MAX_STRIKES);
state = STATE_INACTIVE;
return;
} else if (time_left == 0) {
Serial.println("Time's up");
send_game_update(OBUS_MSGTYPE_C_TIMEOUT, time_left);
}
if (time_left == 0) {
Serial.println(" Time's up");
obuscan_send_c_timeout(this_module, time_left, strikes, OBUS_MAX_STRIKES);
state = STATE_INACTIVE;
return;
} else if (strikes >= OBUS_MAX_STRIKES) {
Serial.println("Strikeout");
send_game_update(OBUS_MSGTYPE_C_STRIKEOUT, time_left);
}
if (strikes >= OBUS_MAX_STRIKES) {
Serial.println(" Strikeout");
obuscan_send_c_strikeout(this_module, time_left, strikes, OBUS_MAX_STRIKES);
state = STATE_INACTIVE;
return;
}
if (last_update + OBUS_UPDATE_INTERVAL <= current_time) {
send_game_update(OBUS_MSGTYPE_C_STATE, time_left);
obuscan_send_c_state(this_module, time_left, strikes, OBUS_MAX_STRIKES);
last_update = current_time;
}
}

View file

@ -1,5 +1,4 @@
#include <mcp2515.h>
#include <assert.h>
#include "obus_can.hpp"
@ -29,6 +28,42 @@ void _decode_can_id(uint16_t can_id, struct module *mod, bool *priority) {
assert(mod->type <= 0b11);
}
uint8_t obuscan_payload_type(uint8_t module_type, uint8_t msg_type) {
if (module_type == OBUS_TYPE_CONTROLLER) {
switch (msg_type) {
case OBUS_MSGTYPE_C_ACK:
case OBUS_MSGTYPE_C_HELLO:
return OBUS_PAYLDTYPE_EMPTY;
case OBUS_MSGTYPE_C_GAMESTART:
case OBUS_MSGTYPE_C_STATE:
case OBUS_MSGTYPE_C_SOLVED:
case OBUS_MSGTYPE_C_TIMEOUT:
case OBUS_MSGTYPE_C_STRIKEOUT:
return OBUS_PAYLDTYPE_GAMESTATUS;
default:
return false;
break;
}
// Module messages
} else {
switch (msg_type) {
case OBUS_MSGTYPE_M_STRIKE:
return OBUS_PAYLDTYPE_IDEMPOTENCY_ID;
case OBUS_MSGTYPE_M_HELLO:
case OBUS_MSGTYPE_M_SOLVED:
return OBUS_PAYLDTYPE_EMPTY;
default:
return -1;
break;
}
}
}
void obuscan_init() {
obuscan_is_init = true;
@ -38,41 +73,9 @@ void obuscan_init() {
}
void obuscan_send(struct obus_message *msg) {
if (!obuscan_is_init) {
Serial.println(F("Call obuscan_init first"));
return;
}
struct can_frame send_frame;
memset(&send_frame.data, 0, CAN_MAX_DLEN);
uint8_t length = 1;
send_frame.data[0] = msg->msg_type;
switch (msg->payload_type) {
case OBUS_PAYLDTYPE_EMPTY: break;
case OBUS_PAYLDTYPE_GAMESTATUS:
send_frame.data[1] = (uint8_t) ((msg->gamestatus.time_left & 0xFF000000) >> 0x18);
send_frame.data[2] = (uint8_t) ((msg->gamestatus.time_left & 0x00FF0000) >> 0x10);
send_frame.data[3] = (uint8_t) ((msg->gamestatus.time_left & 0x0000FF00) >> 0x08);
send_frame.data[4] = (uint8_t) (msg->gamestatus.time_left & 0x000000FF);
send_frame.data[5] = msg->gamestatus.strikes;
send_frame.data[6] = msg->gamestatus.max_strikes;
length = 7;
}
send_frame.can_id = _encode_can_id(msg->from, msg->priority);
send_frame.can_dlc = length;
mcp2515.sendMessage(&send_frame);
}
bool obuscan_receive(struct obus_message *msg) {
if (!obuscan_is_init) {
Serial.println(F("Call obuscan_init first"));
Serial.println(F("E Call obuscan_init first"));
return false;
}
@ -92,50 +95,13 @@ bool obuscan_receive(struct obus_message *msg) {
}
uint8_t msg_type = receive_frame.data[0];
uint8_t payload_type = -1;
_decode_can_id(receive_frame.can_id, &msg->from, &msg->priority);
struct module from;
bool priority;
_decode_can_id(receive_frame.can_id, &from, &priority);
// Controller messages
// TODO ifdef, ignore not for us and assume for us
if (msg->from.type == OBUS_TYPE_CONTROLLER) {
switch (msg_type) {
case OBUS_MSGTYPE_C_ACK: // fall-through
case OBUS_MSGTYPE_C_HELLO:
payload_type = OBUS_PAYLDTYPE_EMPTY;
break;
case OBUS_MSGTYPE_C_GAMESTART: // fall-through
case OBUS_MSGTYPE_C_STATE:
case OBUS_MSGTYPE_C_SOLVED:
case OBUS_MSGTYPE_C_TIMEOUT:
case OBUS_MSGTYPE_C_STRIKEOUT:
payload_type = OBUS_PAYLDTYPE_GAMESTATUS;
break;
default:
return false;
break;
}
// Module messages
} else {
switch (msg_type) {
case OBUS_MSGTYPE_M_STRIKE:
payload_type = OBUS_PAYLDTYPE_IDEMPOTENCY_ID;
break;
case OBUS_MSGTYPE_M_HELLO:
case OBUS_MSGTYPE_M_SOLVED:
payload_type = OBUS_PAYLDTYPE_EMPTY;
break;
default:
return false;
break;
}
}
switch (payload_type) {
switch (obuscan_payload_type(from.type, msg_type)) {
case OBUS_PAYLDTYPE_EMPTY:
break;
@ -158,102 +124,52 @@ bool obuscan_receive(struct obus_message *msg) {
break;
default:
assert(false);
break;
Serial.println(F("W Couldn't determine payload type"));
return false;
}
msg->from = from;
msg->priority = priority;
msg->msg_type = msg_type;
msg->payload_type = payload_type;
return true;
}
inline struct obus_message _obuscan_msg(
struct module from, bool priority, uint8_t msg_type, uint8_t payload_type) {
void obuscan_send(struct obus_message *msg) {
if (!obuscan_is_init) {
Serial.println(F("E Call obuscan_init first"));
return;
}
struct obus_message msg;
msg.from = from;
msg.priority = priority;
msg.msg_type = msg_type;
msg.payload_type = payload_type;
return msg;
}
struct obus_message obuscan_msg_c_payld_gamestatus(
struct module from, bool priority, uint8_t msg_type,
uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
assert(from.type == OBUS_TYPE_CONTROLLER);
struct obus_message msg = _obuscan_msg(
from, priority, msg_type, OBUS_PAYLDTYPE_GAMESTATUS);
msg.gamestatus.time_left = time_left;
msg.gamestatus.strikes = strikes;
msg.gamestatus.max_strikes = max_strikes;
return msg;
}
struct obus_message obuscan_msg_c_ack(struct module from) {
assert(from.type == OBUS_TYPE_CONTROLLER);
return _obuscan_msg(from, false, OBUS_MSGTYPE_C_ACK, OBUS_PAYLDTYPE_EMPTY);
}
struct obus_message obuscan_msg_c_hello(struct module from) {
assert(from.type == OBUS_TYPE_CONTROLLER);
return _obuscan_msg(from, false, OBUS_MSGTYPE_C_HELLO, OBUS_PAYLDTYPE_EMPTY);
}
struct obus_message obuscan_msg_c_gamestart(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
return obuscan_msg_c_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_GAMESTART, time_left, strikes, max_strikes);
}
struct obus_message obuscan_msg_c_state(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
return obuscan_msg_c_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STATE, time_left, strikes, max_strikes);
}
struct obus_message obuscan_msg_c_solved(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
return obuscan_msg_c_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_SOLVED, time_left, strikes, max_strikes);
}
struct obus_message obuscan_msg_c_timeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
return obuscan_msg_c_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_TIMEOUT, time_left, strikes, max_strikes);
}
struct obus_message obuscan_msg_c_strikeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
return obuscan_msg_c_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STRIKEOUT, time_left, strikes, max_strikes);
}
struct obus_message obuscan_msg_m_hello(struct module from) {
assert(from.type != OBUS_TYPE_CONTROLLER);
return _obuscan_msg(from, false, OBUS_MSGTYPE_M_HELLO, OBUS_PAYLDTYPE_EMPTY);
}
struct obus_message obuscan_msg_m_strike(struct module from) {
assert(from.type != OBUS_TYPE_CONTROLLER);
return _obuscan_msg(from, false, OBUS_MSGTYPE_M_STRIKE, OBUS_PAYLDTYPE_EMPTY);
}
struct obus_message obuscan_msg_m_solved(struct module from) {
assert(from.type != OBUS_TYPE_CONTROLLER);
return _obuscan_msg(from, false, OBUS_MSGTYPE_M_STRIKE, OBUS_PAYLDTYPE_EMPTY);
struct can_frame send_frame;
memset(&send_frame.data, 0, CAN_MAX_DLEN);
uint8_t length = 1;
send_frame.data[0] = msg->msg_type;
switch (obuscan_payload_type(msg->from.type, msg->msg_type)) {
case OBUS_PAYLDTYPE_EMPTY:
break;
case OBUS_PAYLDTYPE_GAMESTATUS:
send_frame.data[1] = (uint8_t) ((msg->gamestatus.time_left & 0xFF000000) >> 0x18);
send_frame.data[2] = (uint8_t) ((msg->gamestatus.time_left & 0x00FF0000) >> 0x10);
send_frame.data[3] = (uint8_t) ((msg->gamestatus.time_left & 0x0000FF00) >> 0x08);
send_frame.data[4] = (uint8_t) (msg->gamestatus.time_left & 0x000000FF);
send_frame.data[5] = msg->gamestatus.strikes;
send_frame.data[6] = msg->gamestatus.max_strikes;
length = 7;
break;
default:
Serial.println(F("Unknown payload type"));
return;
}
send_frame.can_id = _encode_can_id(msg->from, msg->priority);
send_frame.can_dlc = length;
mcp2515.sendMessage(&send_frame);
}

View file

@ -1,6 +1,8 @@
#ifndef OBUS_CAN_H
#define OBUS_CAN_H
#include <assert.h>
#define CAN_DOMINANT 0
#define CAN_RECESSIVE 1
@ -48,7 +50,6 @@ struct obus_message {
struct module from;
bool priority;
uint8_t msg_type;
uint8_t payload_type;
union {
struct payld_empty empty;
struct payld_gamestatus gamestatus;
@ -56,24 +57,172 @@ struct obus_message {
};
};
/**
* Determine payload type for message
*
* @param module_type One of OBUS_TYPE_*
* @param module_type One of OBUS_MSGTYPE_*
*
* @return One of OBUS_PAYLDTYPE_*
*/
uint8_t obuscan_payload_type(uint8_t module_type, uint8_t message_type);
/**
* Initialize the CAN controller for OBUS messaging
*/
void obuscan_init();
void obuscan_send(struct obus_message *msg);
/**
* Receive a message
*
* @param msg Pointer to memory where the received message will be wriitten
* @return true if a message was received, false otherwise
*/
bool obuscan_receive(struct obus_message *msg);
struct obus_message obuscan_msg_c_payld_gamestatus(
/**
* Lowlevel interface to send a message, you may want to use one of the helpers, like
* obuscan_send_m_strike
*
* @param msg Pointer to a message to send
*/
void obuscan_send(struct obus_message *msg);
/**
* For internal use only
*
* Send an OBUS message
*/
inline struct obus_message _obuscan_msg(struct module from, bool priority, uint8_t msg_type) {
struct obus_message msg;
msg.from = from;
msg.priority = priority;
msg.msg_type = msg_type;
return msg;
}
/**
* For internal use only
*
* Send a controller OBUS message with a gamestatus payload
*/
inline void _obuscan_send_payld_gamestatus(
struct module from, bool priority, uint8_t msg_type,
uint32_t time_left, uint8_t strikes, uint8_t max_strikes);
uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
struct obus_message obuscan_msg_c_ack(struct module from);
struct obus_message obuscan_msg_c_hello(struct module from);
struct obus_message obuscan_msg_c_gamestart(struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes);
struct obus_message obuscan_msg_c_state(struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes);
struct obus_message obuscan_msg_c_solved(struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes);
struct obus_message obuscan_msg_c_timeout(struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes);
struct obus_message obuscan_msg_c_strikeout(struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes);
struct obus_message msg = _obuscan_msg(from, priority, msg_type);
msg.gamestatus.time_left = time_left;
msg.gamestatus.strikes = strikes;
msg.gamestatus.max_strikes = max_strikes;
obuscan_send(&msg);
}
struct obus_message obuscan_msg_m_hello(struct module from);
struct obus_message obuscan_msg_m_strike(struct module from);
struct obus_message obuscan_msg_m_solved(struct module from);
/**
* Send a controller "ACK" OBUS message
*/
inline void obuscan_send_c_ack(struct module from) {
assert(from.type == OBUS_TYPE_CONTROLLER);
struct obus_message msg = _obuscan_msg(from, false, OBUS_MSGTYPE_C_ACK);
obuscan_send(&msg);
}
/**
* Send a controller "hello" OBUS message
*/
inline void obuscan_send_c_hello(struct module from) {
assert(from.type == OBUS_TYPE_CONTROLLER);
struct obus_message msg = _obuscan_msg(from, false, OBUS_MSGTYPE_C_HELLO);
obuscan_send(&msg);
}
/**
* Send a controller "game start" OBUS message
*/
inline void obuscan_send_c_gamestart(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_obuscan_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_GAMESTART, time_left, strikes, max_strikes);
}
/**
* Send a controller "state" OBUS message
*/
inline void obuscan_send_c_state(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_obuscan_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STATE, time_left, strikes, max_strikes);
}
/**
* Send a controller "solved" OBUS message
*/
inline void obuscan_send_c_solved(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_obuscan_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_SOLVED, time_left, strikes, max_strikes);
}
/**
* Send a controller "timeout" OBUS message
*/
inline void obuscan_send_c_timeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_obuscan_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_TIMEOUT, time_left, strikes, max_strikes);
}
/**
* Send a controller "strikeout" OBUS message
*/
inline void obuscan_send_c_strikeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_obuscan_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STRIKEOUT, time_left, strikes, max_strikes);
}
/**
* Send a module "hello" OBUS message
*/
inline void obuscan_send_m_hello(struct module from) {
assert(from.type != OBUS_TYPE_CONTROLLER);
struct obus_message msg = _obuscan_msg(from, false, OBUS_MSGTYPE_M_HELLO);
obuscan_send(&msg);
}
/**
* Send a module "strike" OBUS message
*/
inline void obuscan_send_m_strike(struct module from) {
assert(from.type != OBUS_TYPE_CONTROLLER);
struct obus_message msg = _obuscan_msg(from, false, OBUS_MSGTYPE_M_STRIKE);
obuscan_send(&msg);
}
/**
* Send a module "solved" OBUS message
*/
inline void obuscan_send_m_solved(struct module from) {
assert(from.type != OBUS_TYPE_CONTROLLER);
struct obus_message msg = _obuscan_msg(from, false, OBUS_MSGTYPE_M_STRIKE);
obuscan_send(&msg);
}
#endif /* end of include guard: OBUS_CAN_H */