obus/lib/obus_can.h

291 lines
7.1 KiB
C
Raw Permalink Normal View History

2020-08-20 17:47:32 +02:00
#ifndef OBUS_CAN_H
#define OBUS_CAN_H
2020-08-26 21:13:16 +02:00
#include "Arduino.h"
2020-08-20 21:13:19 +02:00
#include <assert.h>
2020-08-20 17:47:32 +02:00
#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
2020-08-26 21:13:16 +02:00
#define OBUS_TYPE_INFO 0
2020-08-20 17:47:32 +02:00
#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_C_INFOSTART 7
2020-08-20 17:47:32 +02:00
#define OBUS_MSGTYPE_M_HELLO 0
#define OBUS_MSGTYPE_M_STRIKE 1
#define OBUS_MSGTYPE_M_SOLVED 2
#define OBUS_MSGTYPE_I_INFOMESSAGE 0
#define OBUS_PAYLDTYPE_EMPTY 0
#define OBUS_PAYLDTYPE_GAMESTATUS 1
#define OBUS_PAYLDTYPE_COUNT 2
#define OBUS_PAYLDTYPE_INFO 3
#define OBUS_PAYLDTYPE_MODULEADDR 4
2021-02-03 01:25:03 +01:00
#define OBUS_PAYLDTYPE_INFOSTART 5
2020-08-20 17:47:32 +02:00
#define OBUS_PAYLD_INFO_MAXLEN (OBUS_MSG_LENGTH - 1)
2020-08-26 21:13:16 +02:00
namespace obus_can {
2020-08-20 17:47:32 +02:00
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;
uint8_t puzzle_modules_left;
2020-08-20 17:47:32 +02:00
};
struct payld_infomessage {
uint8_t len;
uint8_t data[OBUS_PAYLD_INFO_MAXLEN];
};
2021-02-03 01:25:03 +01:00
struct payld_infostart {
uint32_t seed;
};
2020-08-20 17:47:32 +02:00
2020-08-26 21:13:16 +02:00
struct message {
2020-08-20 17:47:32 +02:00
struct module from;
bool priority;
uint8_t msg_type;
union {
struct payld_empty empty;
struct payld_gamestatus gamestatus;
uint8_t count;
struct payld_infomessage infomessage;
struct module payload_address;
2021-02-03 01:25:03 +01:00
struct payld_infostart infostart;
2020-08-20 17:47:32 +02:00
};
};
2020-08-20 21:13:19 +02:00
/**
* Determine payload type for message
*
* @param module_type One of OBUS_TYPE_*
* @param module_type One of OBUS_MSGTYPE_*
*
* @return One of OBUS_PAYLDTYPE_*
*/
2020-08-26 21:13:16 +02:00
uint8_t payload_type(uint8_t module_type, uint8_t message_type);
2020-08-20 21:13:19 +02:00
/**
* Initialize the CAN controller for OBUS messaging
*
* @return true if initialization and self-test succeeded, false otherwise
2020-08-20 21:13:19 +02:00
*/
bool init();
2020-08-20 21:13:19 +02:00
/**
* Receive a message
*
* @param msg Pointer to memory where the received message will be written
2020-08-20 21:13:19 +02:00
* @return true if a message was received, false otherwise
*/
2020-08-26 21:13:16 +02:00
bool receive(struct message *msg);
2020-08-20 17:47:32 +02:00
2020-08-20 21:13:19 +02:00
/**
* Lowlevel interface to send a message, you may want to use one of the helpers, like
2020-08-26 21:13:16 +02:00
* send_m_strike
2020-08-20 21:13:19 +02:00
*
* @param msg Pointer to a message to send
*/
2020-08-26 21:13:16 +02:00
void send(struct message *msg);
2020-08-20 21:13:19 +02:00
bool is_error_condition();
2022-03-15 13:46:18 +01:00
uint8_t get_error_flags();
2020-08-20 21:13:19 +02:00
/**
* For internal use only
*
* Send an OBUS message
*/
2020-08-26 21:13:16 +02:00
inline struct message _msg(struct module from, bool priority, uint8_t msg_type) {
2020-08-20 21:13:19 +02:00
2020-08-26 21:13:16 +02:00
struct message msg;
2020-08-20 21:13:19 +02:00
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
*/
2020-08-26 21:13:16 +02:00
inline void _send_payld_gamestatus(
2020-08-20 17:47:32 +02:00
struct module from, bool priority, uint8_t msg_type,
uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_left) {
2020-08-20 21:13:19 +02:00
2020-08-26 21:13:16 +02:00
struct message msg = _msg(from, priority, msg_type);
2020-08-20 21:13:19 +02:00
msg.gamestatus.time_left = time_left;
msg.gamestatus.strikes = strikes;
msg.gamestatus.max_strikes = max_strikes;
msg.gamestatus.puzzle_modules_left = puzzle_modules_left;
2020-08-26 21:13:16 +02:00
send(&msg);
2020-08-20 21:13:19 +02:00
}
/**
* Send a controller "ACK" OBUS message
*/
2020-09-11 21:14:40 +02:00
inline void send_c_ack(struct module from, struct module payload_address) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
struct message msg = _msg(from, false, OBUS_MSGTYPE_C_ACK);
2020-09-11 21:14:40 +02:00
msg.payload_address = payload_address;
2020-08-26 21:13:16 +02:00
send(&msg);
2020-08-20 21:13:19 +02:00
}
/**
* Send a controller "hello" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_c_hello(struct module from) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
struct message msg = _msg(from, false, OBUS_MSGTYPE_C_HELLO);
send(&msg);
2020-08-20 21:13:19 +02:00
}
/**
* Send a controller "game start" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_c_gamestart(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_left) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_GAMESTART, time_left, strikes, max_strikes, puzzle_modules_left);
2020-08-20 21:13:19 +02:00
}
/**
* Send a controller "state" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_c_state(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_left) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STATE, time_left, strikes, max_strikes, puzzle_modules_left);
2020-08-20 21:13:19 +02:00
}
/**
* Send a controller "solved" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_c_solved(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_left) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_SOLVED, time_left, strikes, max_strikes, puzzle_modules_left);
2020-08-20 21:13:19 +02:00
}
/**
* Send a controller "timeout" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_c_timeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_left) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_TIMEOUT, time_left, strikes, max_strikes, puzzle_modules_left);
2020-08-20 21:13:19 +02:00
}
/**
2021-01-30 14:04:40 +01:00
* Send a controller "info start" OBUS message
2020-08-20 21:13:19 +02:00
*/
2021-02-03 01:25:03 +01:00
inline void send_c_infostart(struct module from, uint32_t seed) {
2020-09-11 21:55:43 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
struct message msg = _msg(from, false, OBUS_MSGTYPE_C_INFOSTART);
2021-02-03 01:25:03 +01:00
msg.infostart.seed = seed;
2020-09-11 21:55:43 +02:00
send(&msg);
}
2020-08-20 21:13:19 +02:00
/**
* Send a controller "strikeout" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_c_strikeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_left) {
2020-08-20 21:13:19 +02:00
assert(from.type == OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STRIKEOUT, time_left, strikes, max_strikes, puzzle_modules_left);
2020-08-20 21:13:19 +02:00
}
/**
* Send a module "hello" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_m_hello(struct module from) {
2020-08-20 21:13:19 +02:00
assert(from.type != OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
struct message msg = _msg(from, false, OBUS_MSGTYPE_M_HELLO);
send(&msg);
2020-08-20 21:13:19 +02:00
}
/**
* Send a module "strike" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_m_strike(struct module from, uint8_t count) {
2020-08-20 21:13:19 +02:00
assert(from.type != OBUS_TYPE_CONTROLLER);
2020-08-26 21:13:16 +02:00
struct message msg = _msg(from, false, OBUS_MSGTYPE_M_STRIKE);
msg.count = count;
2020-08-26 21:13:16 +02:00
send(&msg);
2020-08-20 21:13:19 +02:00
}
/**
* Send a module "solved" OBUS message
*/
2020-08-26 21:13:16 +02:00
inline void send_m_solved(struct module from) {
2020-08-20 21:13:19 +02:00
assert(from.type != OBUS_TYPE_CONTROLLER);
2020-09-09 15:32:47 +02:00
struct message msg = _msg(from, false, OBUS_MSGTYPE_M_SOLVED);
2020-08-26 21:13:16 +02:00
send(&msg);
}
/**
* Send an info module "information" OBUS message
*/
inline void send_i_infomessage(struct module from, uint8_t *data, uint8_t data_len) {
2020-09-09 20:41:48 +02:00
assert(from.type == OBUS_TYPE_INFO && from.id != OBUS_CONTROLLER_ID);
if (data_len > OBUS_PAYLD_INFO_MAXLEN) {
Serial.println(F("E Info payload too long"));
return;
}
struct message msg = _msg(from, false, OBUS_MSGTYPE_I_INFOMESSAGE);
msg.infomessage.len = data_len;
memset(msg.infomessage.data, 0, OBUS_PAYLD_INFO_MAXLEN);
memcpy(msg.infomessage.data, data, data_len);
send(&msg);
}
2020-10-22 21:16:12 +02:00
inline bool is_from_controller(struct module from) {
return from.type == OBUS_TYPE_CONTROLLER && from.id == OBUS_CONTROLLER_ID;
}
2020-08-20 21:13:19 +02:00
}
2020-08-20 17:47:32 +02:00
#endif /* end of include guard: OBUS_CAN_H */