summaryrefslogtreecommitdiffstats
path: root/firmware/comm.h
blob: 86cb706b2afd46cf7ac1148031ceeb861a31584a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#ifndef COMM_H_
#define COMM_H_

#include "util.h"

#include <stdint.h>

#include <avr/pgmspace.h>


#ifndef COMM_PAYLOAD_LEN
# define COMM_PAYLOAD_LEN		8
#endif

#ifndef COMM_LOCAL_ADDRESS
# define COMM_LOCAL_ADDRESS		0
#endif

#ifndef COMM_BAUDRATE
# define COMM_BAUDRATE			9600
#endif

#ifndef COMM_TX_QUEUE_SIZE
# define COMM_TX_QUEUE_SIZE		4	/* Must be power of two */
#endif
#define COMM_TX_QUEUE_MASK	(COMM_TX_QUEUE_SIZE - 1)

#ifndef COMM_RX_QUEUE_SIZE
# define COMM_RX_QUEUE_SIZE		4	/* Must be power of two */
#endif
#define COMM_RX_QUEUE_MASK	(COMM_RX_QUEUE_SIZE - 1)


enum comm_frame_control {
	COMM_FC_RESET		= 0x01,
	COMM_FC_REQ_ACK		= 0x02,
	COMM_FC_ACK		= 0x04,

	COMM_FC_ERRCODE		= 0xC0,
	COMM_FC_ERRCODE_SHIFT	= 6,
};

enum comm_errcode {
	COMM_ERR_OK,		/* Ok. */
	COMM_ERR_FAIL,		/* Failure. */
	COMM_ERR_FCS,		/* Checksum error. */
	COMM_ERR_Q,		/* Queue overflow. */
};

typedef uint16_t comm_crc_t;			/* little endian checksum*/

#define COMM_HDR_LEN			4
#define COMM_FCS_LEN			sizeof(comm_crc_t)

struct comm_message {
	uint8_t fc;				/* Frame control. */
	uint8_t seq;				/* Sequence number. */
	uint8_t addr;				/* Source and destination address. */
	uint8_t reserved;
	uint8_t payload[COMM_PAYLOAD_LEN];	/* Payload. */
	comm_crc_t fcs;				/* Frame check sequence. */
} _packed;

#define COMM_MSG_INIT()	{				\
	.fc		= 0,				\
	.seq		= 0,				\
	.addr		= COMM_LOCAL_ADDRESS & 0x0F,	\
}

#define COMM_MSG(_name)				\
	struct comm_message _name = COMM_MSG_INIT()

static inline uint8_t comm_msg_err(const struct comm_message *msg)
{
	return (msg->fc & COMM_FC_ERRCODE) >> COMM_FC_ERRCODE_SHIFT;
}

static inline void comm_msg_set_err(struct comm_message *msg, uint8_t err)
{
	msg->fc = (msg->fc & ~COMM_FC_ERRCODE) | (err << COMM_FC_ERRCODE_SHIFT);
}

static inline uint8_t comm_msg_sa(const struct comm_message *msg)
{
	return msg->addr & 0x0F;
}

static inline void comm_msg_set_sa(struct comm_message *msg, uint8_t sa)
{
	msg->addr = (msg->addr & 0xF0) | (sa & 0x0F);
}

static inline uint8_t comm_msg_da(const struct comm_message *msg)
{
	return msg->addr >> 4;
}

static inline void comm_msg_set_da(struct comm_message *msg, uint8_t da)
{
	msg->addr = (msg->addr & 0x0F) | (da << 4);
}

#define comm_payload(payload_ptr_type, msg)	((payload_ptr_type)((msg)->payload))

void comm_init(void);

void comm_work(void);
void comm_centisecond_tick(void);

void comm_message_send(struct comm_message *msg, uint8_t dest_addr);
void comm_drain_tx_queue(void);

extern bool comm_handle_rx_message(const struct comm_message *msg,
				   void *reply_payload);

#endif /* COMM_H_ */
bues.ch cgit interface