Finish an obuscan abstraction
This commit is contained in:
parent
71df9f71b9
commit
341ff1bb1e
5 changed files with 432 additions and 167 deletions
|
@ -1,42 +1,40 @@
|
|||
#include <mcp2515.h>
|
||||
#include <assert.h>
|
||||
#include "shared.hpp"
|
||||
#include "obus_can.hpp"
|
||||
|
||||
#include "../shared/shared.hpp"
|
||||
|
||||
#define STATE_INACTIVE 0
|
||||
#define STATE_HELLO 1
|
||||
#define STATE_GAME 2
|
||||
|
||||
#define OBUS_GAME_DURATION 60 // Duration of the game in seconds
|
||||
#define OBUS_MAX_STRIKEOUTS 3 // Number of strikeouts 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
|
||||
|
||||
|
||||
MCP2515 mcp2515(10);
|
||||
#define OBUS_GAME_DURATION_MS ((uint32_t) OBUS_GAME_DURATION*1000)
|
||||
|
||||
|
||||
uint8_t state = STATE_INACTIVE;
|
||||
struct module connected_modules_ids[OBUS_MAX_MODULES];
|
||||
uint8_t nr_connected_modules;
|
||||
uint8_t strikeouts;
|
||||
uint8_t strikes;
|
||||
|
||||
// Bit vectors for checking if game is solved or not
|
||||
uint8_t unsolved_puzzles[32]; // 256 bits
|
||||
|
||||
// TIMERS
|
||||
uint16_t hello_round_start;
|
||||
uint16_t game_start;
|
||||
uint16_t last_update;
|
||||
uint32_t hello_round_start;
|
||||
uint32_t game_start;
|
||||
uint32_t last_update;
|
||||
|
||||
struct module this_module = (struct module) {
|
||||
.type = OBUS_TYPE_CONTROLLER;
|
||||
.id = OBUS_CONTROLLER_ID;
|
||||
struct module this_module = {
|
||||
.type = OBUS_TYPE_CONTROLLER,
|
||||
.id = OBUS_CONTROLLER_ID
|
||||
};
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
mcp2515.reset();
|
||||
mcp2515.setBitrate(CAN_50KBPS);
|
||||
mcp2515.setNormalMode();
|
||||
obuscan_init();
|
||||
|
||||
state = STATE_INACTIVE;
|
||||
}
|
||||
|
@ -44,7 +42,7 @@ void setup() {
|
|||
|
||||
uint8_t check_solved() {
|
||||
uint8_t solved = 1;
|
||||
for (int i; i<32; i++) {
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
if (unsolved_puzzles != 0) {
|
||||
solved = 0;
|
||||
break;
|
||||
|
@ -68,68 +66,48 @@ void solve_module_in_bit_vector(uint8_t module_id) {
|
|||
}
|
||||
|
||||
|
||||
void send_message(uint8_t* message, uint8_t length) {
|
||||
send_message(message, length, false);
|
||||
}
|
||||
void send_message(uint8_t* message, uint8_t length, bool priority) {
|
||||
struct can_frame send_frame;
|
||||
|
||||
send_frame.can_id = encode_can_id(this_module, priority);
|
||||
send_frame.can_dlc = length;
|
||||
|
||||
memcpy(send_frame.data, message, OBUS_MSG_LENGTH);
|
||||
|
||||
mcp2515.sendMessage(&send_frame);
|
||||
}
|
||||
|
||||
|
||||
void start_hello() {
|
||||
state = STATE_HELLO;
|
||||
hello_round_start = millis();
|
||||
nr_connected_modules = 0;
|
||||
|
||||
// Zero bit vectors
|
||||
for (int i; i<32; i++) {
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
unsolved_puzzles[i] = 0;
|
||||
}
|
||||
|
||||
uint8_t message[OBUS_MSG_LENGTH];
|
||||
message[0] = OBUS_MSGTYPE_C_HELLO;
|
||||
struct obus_message msg = obuscan_msg_c_hello(this_module);
|
||||
obuscan_send(&msg);
|
||||
|
||||
send_message(message, 1);
|
||||
|
||||
Serial.println("Start of discovery round");
|
||||
Serial.println(F("Start of discovery round"));
|
||||
}
|
||||
|
||||
|
||||
void send_ack() {
|
||||
uint8_t message[OBUS_MSG_LENGTH];
|
||||
message[0] = OBUS_MSGTYPE_C_ACK;
|
||||
|
||||
send_message(message, 1);
|
||||
struct obus_message msg = obuscan_msg_c_ack(this_module);
|
||||
obuscan_send(&msg);
|
||||
}
|
||||
|
||||
|
||||
void receive_hello() {
|
||||
struct can_frame receive_frame;
|
||||
uint16_t current_time = millis();
|
||||
struct obus_message msg;
|
||||
uint32_t current_time = millis();
|
||||
|
||||
if (mcp2515.readMessage(&receive_frame) == MCP2515::ERROR_OK) {
|
||||
if (receive_frame.data[0] == OBUS_MSGTYPE_M_HELLO) {
|
||||
struct module new_module = decode_can_id(receive_frame.can_id);
|
||||
if (obuscan_receive(&msg)) {
|
||||
if (msg.msg_type == OBUS_MSGTYPE_M_HELLO) {
|
||||
Serial.print("Registered module ");
|
||||
Serial.println(full_module_id(new_module));
|
||||
connected_modules_ids[nr_connected_modules] = new_module;
|
||||
Serial.println(full_module_id(msg.from));
|
||||
connected_modules_ids[nr_connected_modules] = msg.from;
|
||||
nr_connected_modules++;
|
||||
|
||||
if (new_module.type == OBUS_TYPE_PUZZLE) {
|
||||
add_module_to_bit_vector(full_module_id(new_module));
|
||||
if (msg.from.type == OBUS_TYPE_PUZZLE) {
|
||||
add_module_to_bit_vector(full_module_id(msg.from));
|
||||
}
|
||||
|
||||
send_ack();
|
||||
Serial.println("ACK");
|
||||
}
|
||||
} else if (current_time - hello_round_start > OBUS_DISC_DURATION * 1000) {
|
||||
} else if (current_time - hello_round_start > OBUS_DISC_DURATION_MS) {
|
||||
Serial.println("End of discovery round");
|
||||
initialize_game();
|
||||
}
|
||||
|
@ -137,86 +115,87 @@ void receive_hello() {
|
|||
|
||||
|
||||
void initialize_game() {
|
||||
strikeouts = 0;
|
||||
|
||||
uint16_t game_duration_millis = (uint16_t) OBUS_GAME_DURATION * 1000;
|
||||
|
||||
uint8_t message[OBUS_MSG_LENGTH];
|
||||
message[0] = OBUS_MSGTYPE_C_GAMESTART;
|
||||
message[1] = (uint8_t) ((game_duration_millis & 0xFF000000) >> 0x18);
|
||||
message[2] = (uint8_t) ((game_duration_millis & 0x00FF0000) >> 0x10);
|
||||
message[3] = (uint8_t) ((game_duration_millis & 0x0000FF00) >> 0x08);
|
||||
message[4] = (uint8_t) (game_duration_millis & 0x000000FF);
|
||||
message[5] = strikeouts;
|
||||
message[6] = OBUS_MAX_STRIKEOUTS;
|
||||
|
||||
send_message(message, 7);
|
||||
|
||||
strikes = 0;
|
||||
game_start = millis();
|
||||
last_update = game_start;
|
||||
|
||||
last_update = game_start;
|
||||
state = STATE_GAME;
|
||||
|
||||
Serial.println("Game started");
|
||||
|
||||
send_game_update(OBUS_MSGTYPE_C_GAMESTART, OBUS_GAME_DURATION_MS);
|
||||
}
|
||||
|
||||
|
||||
void receive_module_update() {
|
||||
struct can_frame receive_frame;
|
||||
struct obus_message msg;
|
||||
|
||||
if (mcp2515.readMessage(&receive_frame) == MCP2515::ERROR_OK) {
|
||||
if (receive_frame.data[0] == OBUS_MSGTYPE_M_STRIKE) {
|
||||
strikeouts++;
|
||||
} else if (receive_frame.data[0] == OBUS_MSGTYPE_M_SOLVED) {
|
||||
uint16_t module_id = full_module_id(decode_can_id(receive_frame.can_id));
|
||||
solve_module_in_bit_vector(module_id);
|
||||
if (obuscan_receive(&msg)) {
|
||||
|
||||
switch (msg.msg_type) {
|
||||
case OBUS_MSGTYPE_M_STRIKE:
|
||||
// TODO check idempotency ID
|
||||
strikes++;
|
||||
break;
|
||||
|
||||
case OBUS_MSGTYPE_M_SOLVED:
|
||||
solve_module_in_bit_vector(full_module_id(msg.from));
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.print(F("W Ignoring msg "));
|
||||
Serial.println(msg.msg_type);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_game_update(uint8_t status, uint16_t timestamp) {
|
||||
uint8_t message[OBUS_MSG_LENGTH];
|
||||
message[0] = status;
|
||||
message[1] = (uint8_t) ((timestamp & 0xFF000000) >> 0x18);
|
||||
message[2] = (uint8_t) ((timestamp & 0x00FF0000) >> 0x10);
|
||||
message[3] = (uint8_t) ((timestamp & 0x0000FF00) >> 0x08);
|
||||
message[4] = (uint8_t) (timestamp & 0x000000FF);
|
||||
message[5] = strikeouts;
|
||||
message[6] = OBUS_MAX_STRIKEOUTS;
|
||||
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);
|
||||
|
||||
send_message(message, 7);
|
||||
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() {
|
||||
uint16_t current_time = millis();
|
||||
uint16_t game_duration = current_time - game_start;
|
||||
uint32_t current_time = millis();
|
||||
uint32_t time_elapsed = current_time - game_start;
|
||||
uint32_t time_left =
|
||||
OBUS_GAME_DURATION_MS < time_elapsed ? 0 : OBUS_GAME_DURATION_MS - time_elapsed;
|
||||
// We cannot check for '<= 0' in an uint type so we check the terms prior to subtraction
|
||||
|
||||
receive_module_update();
|
||||
|
||||
if (check_solved()) {
|
||||
Serial.println("Game solved");
|
||||
send_game_update(OBUS_MSGTYPE_C_SOLVED, game_duration);
|
||||
send_game_update(OBUS_MSGTYPE_C_SOLVED, time_left);
|
||||
state = STATE_INACTIVE;
|
||||
return;
|
||||
} else if (game_duration >= (uint16_t) OBUS_GAME_DURATION * 1000) {
|
||||
} else if (time_left == 0) {
|
||||
Serial.println("Time's up");
|
||||
send_game_update(OBUS_MSGTYPE_C_TIMEOUT, game_duration);
|
||||
send_game_update(OBUS_MSGTYPE_C_TIMEOUT, time_left);
|
||||
state = STATE_INACTIVE;
|
||||
return;
|
||||
} else if (strikeouts >= OBUS_MAX_STRIKEOUTS) {
|
||||
} else if (strikes >= OBUS_MAX_STRIKES) {
|
||||
Serial.println("Strikeout");
|
||||
send_game_update(OBUS_MSGTYPE_C_STRIKEOUT, game_duration);
|
||||
send_game_update(OBUS_MSGTYPE_C_STRIKEOUT, time_left);
|
||||
state = STATE_INACTIVE;
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t elapsed_time = current_time - last_update;
|
||||
if (elapsed_time > OBUS_UPDATE_INTERVAL) {
|
||||
Serial.print("Sending game update: ");
|
||||
Serial.println(game_duration);
|
||||
send_game_update(OBUS_MSGTYPE_C_STATE, (uint16_t) OBUS_GAME_DURATION * 1000 - game_duration);
|
||||
if (last_update + OBUS_UPDATE_INTERVAL <= current_time) {
|
||||
send_game_update(OBUS_MSGTYPE_C_STATE, time_left);
|
||||
last_update = current_time;
|
||||
}
|
||||
}
|
||||
|
|
259
src/controller/obus_can.cpp
Normal file
259
src/controller/obus_can.cpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
#include <mcp2515.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "obus_can.hpp"
|
||||
|
||||
|
||||
MCP2515 mcp2515(10);
|
||||
bool obuscan_is_init = false;
|
||||
|
||||
|
||||
uint16_t _encode_can_id(struct module mod, bool priority) {
|
||||
assert(mod.type <= 0b11);
|
||||
|
||||
/* b bb bbbbbbbb
|
||||
* ↓ type module ID
|
||||
* priority bit
|
||||
*/
|
||||
return \
|
||||
((uint16_t) (priority ? CAN_DOMINANT : CAN_RECESSIVE) << 10) | \
|
||||
((uint16_t) mod.type << 8) | \
|
||||
(uint16_t) mod.id;
|
||||
}
|
||||
|
||||
void _decode_can_id(uint16_t can_id, struct module *mod, bool *priority) {
|
||||
*priority = ((can_id >> 10) & 1) == CAN_DOMINANT;
|
||||
mod->type = (can_id >> 8) & 0b11;
|
||||
mod->id = can_id & 0b11111111;
|
||||
|
||||
assert(mod->type <= 0b11);
|
||||
}
|
||||
|
||||
|
||||
void obuscan_init() {
|
||||
obuscan_is_init = true;
|
||||
mcp2515.reset();
|
||||
mcp2515.setBitrate(CAN_50KBPS);
|
||||
mcp2515.setNormalMode();
|
||||
}
|
||||
|
||||
|
||||
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"));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct can_frame receive_frame;
|
||||
|
||||
memset(&receive_frame.data, 0, CAN_MAX_DLEN);
|
||||
|
||||
MCP2515::ERROR status = mcp2515.readMessage(&receive_frame);
|
||||
if (status != MCP2515::ERROR_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always at least OBUS message type required
|
||||
if (receive_frame.can_dlc < 1) {
|
||||
Serial.println(F("W Received illegal msg: payload <1"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t msg_type = receive_frame.data[0];
|
||||
uint8_t payload_type = -1;
|
||||
|
||||
_decode_can_id(receive_frame.can_id, &msg->from, &msg->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) {
|
||||
case OBUS_PAYLDTYPE_EMPTY:
|
||||
break;
|
||||
|
||||
case OBUS_PAYLDTYPE_GAMESTATUS:
|
||||
if (receive_frame.can_dlc < 7) {
|
||||
Serial.println(F("W Received illegal gamestatus msg: payload <7"));
|
||||
return false;
|
||||
}
|
||||
msg->gamestatus.time_left =
|
||||
((uint32_t) receive_frame.data[1] << 0x18) |
|
||||
((uint32_t) receive_frame.data[2] << 0x10) |
|
||||
((uint32_t) receive_frame.data[3] << 0x08) |
|
||||
((uint32_t) receive_frame.data[4]);
|
||||
msg->gamestatus.strikes = receive_frame.data[5];
|
||||
msg->gamestatus.max_strikes = receive_frame.data[6];
|
||||
break;
|
||||
|
||||
case OBUS_PAYLDTYPE_IDEMPOTENCY_ID:
|
||||
msg->idempotency.id = receive_frame.data[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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);
|
||||
}
|
79
src/controller/obus_can.hpp
Normal file
79
src/controller/obus_can.hpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef OBUS_CAN_H
|
||||
#define OBUS_CAN_H
|
||||
|
||||
#define CAN_DOMINANT 0
|
||||
#define CAN_RECESSIVE 1
|
||||
|
||||
#define OBUS_CONTROLLER_ID 0x000
|
||||
|
||||
#define OBUS_MSG_LENGTH 8 // Max 8 to fit in a CAN message
|
||||
|
||||
#define OBUS_TYPE_CONTROLLER 0
|
||||
#define OBUS_TYPE_PUZZLE 1
|
||||
#define OBUS_TYPE_NEEDY 2
|
||||
|
||||
#define OBUS_MSGTYPE_C_ACK 0
|
||||
#define OBUS_MSGTYPE_C_HELLO 1
|
||||
#define OBUS_MSGTYPE_C_GAMESTART 2
|
||||
#define OBUS_MSGTYPE_C_STATE 3
|
||||
#define OBUS_MSGTYPE_C_SOLVED 4
|
||||
#define OBUS_MSGTYPE_C_TIMEOUT 5
|
||||
#define OBUS_MSGTYPE_C_STRIKEOUT 6
|
||||
|
||||
#define OBUS_MSGTYPE_M_HELLO 0
|
||||
#define OBUS_MSGTYPE_M_STRIKE 1
|
||||
#define OBUS_MSGTYPE_M_SOLVED 2
|
||||
|
||||
#define OBUS_PAYLDTYPE_EMPTY 0
|
||||
#define OBUS_PAYLDTYPE_GAMESTATUS 1
|
||||
#define OBUS_PAYLDTYPE_IDEMPOTENCY_ID 2
|
||||
|
||||
struct module {
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
};
|
||||
|
||||
struct payld_empty {};
|
||||
struct payld_gamestatus {
|
||||
uint32_t time_left;
|
||||
uint8_t strikes;
|
||||
uint8_t max_strikes;
|
||||
};
|
||||
struct payld_idempotency {
|
||||
uint8_t id;
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
struct payld_idempotency idempotency;
|
||||
};
|
||||
};
|
||||
|
||||
void obuscan_init();
|
||||
void obuscan_send(struct obus_message *msg);
|
||||
bool obuscan_receive(struct obus_message *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);
|
||||
|
||||
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 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);
|
||||
|
||||
#endif /* end of include guard: OBUS_CAN_H */
|
18
src/controller/shared.hpp
Normal file
18
src/controller/shared.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef OBUS_SHARED_H
|
||||
#define OBUS_SHARED_H
|
||||
|
||||
#include "obus_can.hpp"
|
||||
|
||||
#define OBUS_MAX_MODULES 16
|
||||
#define OBUS_DISC_DURATION 5 // Duration of discovery round in seconds
|
||||
#define OBUS_UPDATE_INTERVAL 500 // Number of milliseconds between game updates
|
||||
|
||||
#define OBUS_DISC_DURATION_MS ((uint32_t) OBUS_DISC_DURATION*1000)
|
||||
|
||||
uint16_t full_module_id(struct module mod) {
|
||||
return \
|
||||
((uint16_t) mod.type << 8) | \
|
||||
(uint16_t) mod.id;
|
||||
}
|
||||
|
||||
#endif /* end of include guard: OBUS_DEFS_H */
|
|
@ -1,70 +0,0 @@
|
|||
#ifndef OBUS_SHARED_H
|
||||
#define OBUS_SHARED_H
|
||||
|
||||
#define OBUS_CONTROLLER_ID 0x000
|
||||
|
||||
#define OBUS_TYPE_CONTROLLER 0
|
||||
#define OBUS_TYPE_PUZZLE 1
|
||||
#define OBUS_TYPE_NEEDY 2
|
||||
|
||||
#define OBUS_MSG_LENGTH 8 // Max 8 to fit in a CAN message
|
||||
|
||||
#define OBUS_MAX_MODULES 16
|
||||
#define OBUS_DISC_DURATION 5 // Duration of discovery round in seconds
|
||||
#define OBUS_UPDATE_INTERVAL 500 // Number of milliseconds between game updates
|
||||
|
||||
#define OBUS_MSGTYPE_C_ACK 0
|
||||
#define OBUS_MSGTYPE_C_HELLO 1
|
||||
#define OBUS_MSGTYPE_C_GAMESTART 2
|
||||
#define OBUS_MSGTYPE_C_STATE 3
|
||||
#define OBUS_MSGTYPE_C_SOLVED 4
|
||||
#define OBUS_MSGTYPE_C_TIMEOUT 5
|
||||
#define OBUS_MSGTYPE_C_STRIKEOUT 6
|
||||
|
||||
#define OBUS_MSGTYPE_M_HELLO 0
|
||||
#define OBUS_MSGTYPE_M_STRIKE 1
|
||||
#define OBUS_MSGTYPE_M_SOLVED 2
|
||||
|
||||
#define CAN_DOMINANT 0
|
||||
#define CAN_RECESSIVE 1
|
||||
|
||||
#define OBUS_MASK_PRIORITY = 0b10000000000
|
||||
#define OBUS_MASK_TYPE = 0b01100000000
|
||||
#define OBUS_MASK_ID = 0b00011111111
|
||||
|
||||
struct module {
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
};
|
||||
|
||||
|
||||
uint16_t encode_can_id(struct module mod, bool priority) {
|
||||
assert(mod.type <= 0b11);
|
||||
|
||||
/* b bb bbbbbbbb
|
||||
* ↓ type module ID
|
||||
* priority bit
|
||||
*/
|
||||
return \
|
||||
((uint16_t) (priority ? CAN_DOMINANT : CAN_RECESSIVE) << 10) | \
|
||||
((uint16_t) mod.type << 8) | \
|
||||
(uint16_t) mod.id;
|
||||
}
|
||||
|
||||
uint16_t full_module_id(struct module mod) {
|
||||
return \
|
||||
((uint16_t) mod.type << 8) | \
|
||||
(uint16_t) mod.id;
|
||||
}
|
||||
|
||||
struct module decode_can_id(uint16_t can_id) {
|
||||
struct module mod;
|
||||
mod.type = (can_id & OBUS_MASK_TYPE) >> 8;
|
||||
mod.id = can_id & OBUS_MASK_ID;
|
||||
|
||||
assert(mod.type <= 0x11);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
#endif /* end of include guard: OBUS_DEFS_H */
|
Loading…
Reference in a new issue