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_ */
|