142424c4a6d56db1c34c2e74bbb46fd2bb668968
2 * Microcontroller message bus
3 * uc-side slave implementation for Atmel AVR8
5 * The gcc compiler always treats multi-byte variables as litte-endian.
6 * So no explicit endianness conversions are done on the message header,
7 * footer and status data structures.
9 * Copyright (C) 2009 Michael Buesch <mb@bu3sch.de>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
26 #include <avr/interrupt.h>
27 #include <util/crc16.h>
30 struct ucmb_message_hdr
{
31 uint16_t magic
; /* UCMB_MAGIC */
32 uint16_t len
; /* Payload length (excluding header) */
33 } __attribute__((packed
));
35 struct ucmb_message_footer
{
36 uint16_t crc
; /* CRC of the header + payload. */
37 } __attribute__((packed
));
40 uint16_t magic
; /* UCMB_MAGIC */
41 uint16_t code
; /* enum ucmb_status_code */
42 } __attribute__((packed
));
44 #define UCMB_MAGIC 0x1337
46 enum ucmb_status_code
{
48 UCMB_STAT_EPROTO
, /* Protocol format error */
49 UCMB_STAT_ENOMEM
, /* Out of memory */
50 UCMB_STAT_E2BIG
, /* Message too big */
51 UCMB_STAT_ECRC
, /* CRC error */
55 static uint8_t ucmb_buf
[sizeof(struct ucmb_message_hdr
) +
57 sizeof(struct ucmb_message_footer
)];
58 static uint16_t ucmb_buf_ptr
;
59 static struct ucmb_status status_buf
;
60 static uint16_t ucmb_send_message_len
;
63 static uint8_t ucmb_state
;
73 static void ucmb_send_next_byte(void)
76 case UCMB_ST_SENDSTATUS
: {
77 const uint8_t *st
= (const uint8_t *)&status_buf
;
79 if (ucmb_buf_ptr
< sizeof(struct ucmb_status
))
80 SPDR
= st
[ucmb_buf_ptr
];
82 if (ucmb_buf_ptr
== sizeof(struct ucmb_status
) + TRAILING
) {
84 if (ucmb_send_message_len
) {
85 ucmb_state
= UCMB_ST_SENDMESSAGE
;
88 ucmb_state
= UCMB_ST_LISTEN
;
92 case UCMB_ST_SENDMESSAGE
: {
94 uint16_t full_length
= sizeof(struct ucmb_message_hdr
) +
95 ucmb_send_message_len
+
96 sizeof(struct ucmb_message_footer
);
97 if (ucmb_buf_ptr
< full_length
)
98 SPDR
= ucmb_buf
[ucmb_buf_ptr
];
100 if (ucmb_buf_ptr
== full_length
+ TRAILING
) {
101 ucmb_send_message_len
= 0;
103 ucmb_state
= UCMB_ST_LISTEN
;//FIXME retr status
109 static uint16_t crc16_block_update(uint16_t crc
, const void *_data
, uint16_t size
)
111 const uint8_t *data
= _data
;
114 crc
= _crc16_update(crc
, *data
);
122 static uint16_t ucmb_calc_msg_buffer_crc(void)
124 const struct ucmb_message_hdr
*hdr
;
125 uint16_t crc
= 0xFFFF;
127 hdr
= (const struct ucmb_message_hdr
*)ucmb_buf
;
128 crc
= crc16_block_update(crc
, ucmb_buf
,
129 sizeof(struct ucmb_message_hdr
) + hdr
->len
);
135 /* SPI data transfer interrupt. */
142 switch (ucmb_state
) {
143 case UCMB_ST_LISTEN
: {
144 struct ucmb_message_hdr
*hdr
;
145 struct ucmb_message_footer
*footer
;
147 ucmb_buf
[ucmb_buf_ptr
++] = data
;
148 if (ucmb_buf_ptr
< sizeof(struct ucmb_message_hdr
))
149 return; /* Header RX not complete. */
150 hdr
= (struct ucmb_message_hdr
*)ucmb_buf
;
151 if (ucmb_buf_ptr
== sizeof(struct ucmb_message_hdr
)) {
152 if (hdr
->magic
!= UCMB_MAGIC
) {
153 /* Invalid magic! Reset. */
157 if (hdr
->len
> UCMB_MAX_MSG_LEN
) {
158 /* Invalid length. */
159 //FIXME don't interrupt, but poll len bytes and
160 // send an immediate failure report
167 if (ucmb_buf_ptr
== sizeof(struct ucmb_message_hdr
) +
168 sizeof(struct ucmb_message_footer
) +
170 footer
= (struct ucmb_message_footer
*)(
171 ucmb_buf
+ sizeof(struct ucmb_message_hdr
) +
173 status_buf
.magic
= UCMB_MAGIC
;
174 status_buf
.code
= UCMB_STAT_OK
;
175 if (ucmb_calc_msg_buffer_crc() != footer
->crc
)
176 status_buf
.code
= UCMB_STAT_ECRC
;
177 ucmb_state
= UCMB_ST_SENDSTATUS
;
179 ucmb_send_next_byte();
181 ucmb_send_message_len
= ucmb_rx_message(
182 ucmb_buf
+ sizeof(struct ucmb_message_hdr
),
184 if (ucmb_send_message_len
) {
185 footer
= (struct ucmb_message_footer
*)(
186 ucmb_buf
+ sizeof(struct ucmb_message_hdr
) +
187 ucmb_send_message_len
);
189 hdr
->magic
= UCMB_MAGIC
;
190 hdr
->len
= ucmb_send_message_len
;
191 footer
->crc
= ucmb_calc_msg_buffer_crc();
196 case UCMB_ST_SENDSTATUS
:
197 case UCMB_ST_SENDMESSAGE
:
198 ucmb_send_next_byte();
205 ucmb_state
= UCMB_ST_LISTEN
;
207 /* SPI slave mode 0 with IRQ enabled. */
208 DDRB
|= (1 << 4/*MISO*/);
209 DDRB
&= ~((1 << 5/*SCK*/) | (1 << 3/*MOSI*/) | (1 << 2/*SS*/));
210 SPCR
= (1 << SPE
) | (1 << SPIE
) /*| (1 << CPOL) | (1 << CPHA)*/;
211 (void)SPSR
; /* clear state */
212 (void)SPDR
; /* clear state */