Revision 211
broken cardbox, needs to fix the statemachine
trunk/cardbox/rs485_int.c | ||
---|---|---|
16 | 16 |
* Copyright 2009 Kevin Woo <kwoo@2ndt.com> |
17 | 17 |
* |
18 | 18 |
********/ |
19 |
/** @file uart.c
|
|
19 |
/** @file rs485_int.c
|
|
20 | 20 |
* |
21 | 21 |
* @brief Implements UART functionality in hardware |
22 | 22 |
* |
23 | 23 |
* @author Kevin Woo (kwoo) |
24 | 24 |
*/ |
25 | 25 |
|
26 |
#include "uart.h"
|
|
26 |
#include "rs485_int.h"
|
|
27 | 27 |
#include <util/delay.h> |
28 | 28 |
#include <stdint.h> |
29 | 29 |
|
30 | 30 |
uint8_t received_byte; //Byte received |
31 | 31 |
uint8_t byte_ready; //New byte has been received |
32 | 32 |
|
33 |
void init_uart(uint16_t baud) {
|
|
33 |
void rs485_init(uint16_t baud) {
|
|
34 | 34 |
// Set baud rate |
35 | 35 |
UBRRH = (uint8_t)(baud>>8); |
36 | 36 |
UBRRL = (uint8_t)baud; |
... | ... | |
44 | 44 |
// Initialize receive variables |
45 | 45 |
byte_ready = 0; |
46 | 46 |
received_byte = 0x0; |
47 |
|
|
48 |
// Set to receive mode |
|
49 |
rs485_toggle_transmit(TX_OFF); |
|
47 | 50 |
} |
48 | 51 |
|
49 |
int8_t uart_get_byte(uint8_t *output_byte) {
|
|
52 |
int8_t rs485_get_byte(uint8_t *output_byte) {
|
|
50 | 53 |
if (byte_ready) { |
51 | 54 |
byte_ready = 0; |
52 | 55 |
*output_byte = received_byte; |
... | ... | |
56 | 59 |
} |
57 | 60 |
} |
58 | 61 |
|
59 |
void uart_send_byte(uint8_t data) {
|
|
62 |
void rs485_send_byte(uint8_t data) {
|
|
60 | 63 |
//Waits until current transmit is done |
61 | 64 |
while (!(UCSRA & _BV(UDRE))); |
62 | 65 |
|
63 | 66 |
// Enable writes and send |
64 |
uart_toggle_transmit(UART_TX_ON);
|
|
67 |
rs485_toggle_transmit(UART_TX_ON);
|
|
65 | 68 |
UDR = data; |
66 | 69 |
return; |
67 | 70 |
} |
68 | 71 |
|
69 |
void uart_toggle_transmit(uint8_t state) {
|
|
72 |
void rs485_toggle_transmit(uint8_t state) {
|
|
70 | 73 |
if (state == UART_TX_ON) { |
71 | 74 |
PORTD |= TX_EN; |
72 | 75 |
} else { |
... | ... | |
81 | 84 |
|
82 | 85 |
ISR(USART_TX_vect) { |
83 | 86 |
// Re-enable reads |
84 |
uart_toggle_transmit(UART_TX_OFF);
|
|
87 |
rs485_toggle_transmit(UART_TX_OFF);
|
|
85 | 88 |
} |
trunk/cardbox/main.c | ||
---|---|---|
17 | 17 |
* |
18 | 18 |
********/ |
19 | 19 |
#include <util/delay.h> |
20 |
#include "uart.h"
|
|
20 |
#include "rs485_int.h"
|
|
21 | 21 |
#include <avr/interrupt.h> |
22 | 22 |
#include <avr/io.h> |
23 | 23 |
|
24 |
#include "tooltron.h"
|
|
24 |
#include <tooltron.h>
|
|
25 | 25 |
#include "timer.h" |
26 | 26 |
|
27 | 27 |
/***** Keypad definitions ******/ |
... | ... | |
48 | 48 |
#define LED_YELLOW (_BV(PC4)) |
49 | 49 |
#define LED_GREEN (_BV(PC3)) |
50 | 50 |
|
51 |
#define ADDR 2 |
|
51 | 52 |
|
52 | 53 |
/***** Global variables *****/ |
53 | 54 |
|
... | ... | |
62 | 63 |
return; |
63 | 64 |
} |
64 | 65 |
|
66 |
/** |
|
67 |
* @brief Sets the LED to the specified state |
|
68 |
* |
|
69 |
* This sets LED which to the specified state. You can use this to set |
|
70 |
* multiple LEDs if you OR the LEDs desired into the which argument. |
|
71 |
* |
|
72 |
* @param which The LEDs to set |
|
73 |
* @parma state The state ON or OFF to set to the LEDs to |
|
74 |
* @return void |
|
75 |
*/ |
|
76 |
void toggle_led(uint8_t which, uint8_t state) { |
|
77 |
if (state == ON) { |
|
78 |
LED_PORT &= ~(which); |
|
79 |
} else { |
|
80 |
LED_PORT |= (which); |
|
81 |
} |
|
82 |
} |
|
65 | 83 |
|
84 |
|
|
66 | 85 |
char get_button(void) { |
67 | 86 |
|
68 | 87 |
char ret = ' '; |
... | ... | |
134 | 153 |
return ret; |
135 | 154 |
} |
136 | 155 |
|
137 |
int main(void) |
|
138 |
{ |
|
156 |
typedef enum { |
|
157 |
req, |
|
158 |
press, |
|
159 |
send, |
|
160 |
rsp |
|
161 |
} state_t; |
|
139 | 162 |
|
140 |
char c; |
|
141 |
serial_init(BAUD9600); |
|
163 |
|
|
164 |
int main(void) { |
|
165 |
uint8_t mbuf[PROGD_PACKET_SIZE]; |
|
166 |
uint8_t resp; |
|
167 |
uint8_t c; |
|
168 |
state_t state = req; |
|
169 |
|
|
170 |
rs485_init(BAUD9600); |
|
142 | 171 |
init_pins(); |
143 | 172 |
init_timer(); |
144 | 173 |
sei(); |
145 | 174 |
|
146 |
while(1) |
|
147 |
{ |
|
175 |
while(1) { |
|
148 | 176 |
|
149 |
PORTC |= LED_RED | LED_GREEN | LED_YELLOW; |
|
150 |
|
|
151 |
//wait for key request from server |
|
152 |
while(serial_getchar()!=TT_GET_KEY); |
|
177 |
switch(state) { |
|
178 |
case req: |
|
179 |
toggle_led(LED_RED|LED_GREEN|LED_YELLOW, OFF); |
|
180 |
|
|
181 |
// Wait for a packet |
|
182 |
resp = parse_packet(mbuf, ADDR); |
|
153 | 183 |
|
154 |
PORTC &=~LED_YELLOW; |
|
155 |
reset_timer(); |
|
156 |
reset_timeout_flag(); |
|
157 |
start_timer(); |
|
184 |
if (resp == TT_GET_KEY) { |
|
185 |
toggle_led(LED_YELLOW, ON); |
|
186 |
reset_timer(); |
|
187 |
reset_timeout_flag(); |
|
188 |
start_timer(); |
|
189 |
c = ' '; |
|
190 |
state = press; |
|
191 |
} |
|
192 |
break; |
|
193 |
case press: |
|
194 |
c = get_button(); |
|
158 | 195 |
|
159 |
c = ' '; |
|
160 |
serial_disable_rx(); |
|
161 |
while(c ==' ') { |
|
162 |
if (seconds > TIMEOUT_SECONDS) { |
|
163 |
set_timeout_flag(); |
|
164 |
serial_putchar(TT_TIMEOUT); |
|
165 |
serial_enable_rx(); |
|
166 |
break; |
|
167 |
} |
|
196 |
if (seconds > TIMEOUT_SECONDS) { |
|
197 |
set_timeout_flag(); |
|
198 |
state = send; |
|
199 |
} else if (c != ' ') { |
|
200 |
state = send; |
|
201 |
} |
|
168 | 202 |
|
169 |
c = get_button(); |
|
170 |
_delay_ms(100); |
|
171 |
} |
|
172 |
serial_enable_rx(); |
|
203 |
break; |
|
204 |
case send: |
|
205 |
if (timeoutflag == 1) { |
|
206 |
send_packet(TT_TIMEOUT, ADDR); |
|
207 |
state = req; |
|
208 |
} else { |
|
209 |
send_packet_data(TT_SEND_KEY, ADDR, &c, 1); |
|
210 |
} |
|
173 | 211 |
|
212 |
state = rsp; |
|
213 |
break; |
|
214 |
case rsp: |
|
215 |
resp = parse_packet(mbuf, ADDR); |
|
174 | 216 |
|
217 |
if (resp == TT_ACK |
|
218 |
|
|
219 |
|
|
220 |
|
|
221 |
|
|
222 |
|
|
175 | 223 |
if (timeout_flag == 0) { |
176 | 224 |
//respond with key pressed |
177 |
serial_putchar(c);
|
|
225 |
uart_send_byte(c);
|
|
178 | 226 |
|
179 | 227 |
//wait for response |
180 | 228 |
c=0; |
181 | 229 |
reset_timeout_flag(); |
182 | 230 |
reset_timer(); |
183 |
while(!c && seconds < TIMEOUT_SECONDS) |
|
184 |
c = serial_getchar_nb(); |
|
231 |
while((uart_get_byte(&c) < 0) && (seconds < TIMEOUT_SECONDS)); |
|
185 | 232 |
|
186 | 233 |
PORTC |= LED_YELLOW; |
187 | 234 |
|
trunk/cardbox/rs485_int.h | ||
---|---|---|
16 | 16 |
* Copyright 2009 Kevin Woo <kwoo@2ndt.com> |
17 | 17 |
* |
18 | 18 |
********/ |
19 |
/** @file uart.h
|
|
19 |
/** @file rs485_int.h
|
|
20 | 20 |
* |
21 | 21 |
* @brief Initializes UART functions using the UART hardware module |
22 | 22 |
* |
... | ... | |
53 | 53 |
* which msut be the value that is defined in the datasheet |
54 | 54 |
* for any particular speed (ie: 51 -> 9600bps) |
55 | 55 |
**/ |
56 |
void init_uart(uint16_t baud);
|
|
56 |
void rs485_init(uint16_t baud);
|
|
57 | 57 |
/** @brief Gets latest byte and returns it in output_byte. If the byte |
58 | 58 |
* was already read, returns -1 otherwise it returns 0 |
59 | 59 |
**/ |
60 |
int8_t uart_get_byte(uint8_t *output_byte);
|
|
60 |
int8_t rs485_get_byte(uint8_t *output_byte);
|
|
61 | 61 |
/** @brief Sends a character array of size size. If we are currently |
62 | 62 |
* transmitting it will block until the the current transmit |
63 | 63 |
* is done. |
64 | 64 |
**/ |
65 |
void uart_send_byte(uint8_t data);
|
|
66 |
void uart_toggle_transmit(uint8_t state);
|
|
65 |
void rs485_send_byte(uint8_t data);
|
|
66 |
void rs485_toggle_transmit(uint8_t state);
|
|
67 | 67 |
#endif |
trunk/cardbox/packet.c | ||
---|---|---|
1 |
#include <packet.h> |
|
2 |
|
|
3 |
|
|
4 |
/** |
|
5 |
* @brief Packet handler states |
|
6 |
* @param sd Looking for a start delimiter |
|
7 |
* @param src Looking for a source |
|
8 |
* @param dest Looking for a destination |
|
9 |
* @param comd Looking for a command |
|
10 |
* @param read Reading data payload |
|
11 |
* @param cs Calcualting the checksum and returning |
|
12 |
*/ |
|
13 |
typedef enum { |
|
14 |
sd, |
|
15 |
src, |
|
16 |
dest, |
|
17 |
comd, |
|
18 |
read, |
|
19 |
cs |
|
20 |
} state_t; |
|
21 |
|
|
22 |
/** |
|
23 |
* @brief Parses a tooltron packet |
|
24 |
* |
|
25 |
* This is a state machine that parses the packet. It uses a software |
|
26 |
* counter to track timeout status. The timeout is not reset unless |
|
27 |
* a fully valid packet is found. It will fail if there is a timeout, |
|
28 |
* crc error, or any error in the packet. All data will be placed in |
|
29 |
* mbuf. Note that mbuf must be able to handle PROGD_PACKET_SIZE |
|
30 |
* bytes. |
|
31 |
* |
|
32 |
* @pre mbuf is PROGD_PACKET_SIZE bytes large |
|
33 |
* @param mbuf Buffer to write the packet data payload to if there is one |
|
34 |
* @param addr The address of the sending node |
|
35 |
* @return the command received or TT_BAD on any error |
|
36 |
*/ |
|
37 |
char parse_packet(uint8_t *mbuf, uint8_t addr) { |
|
38 |
uint8_t r; // Byte from the network |
|
39 |
uint8_t crc; // Running checksum of the packet |
|
40 |
uint8_t cmd; // The command received |
|
41 |
uint8_t pos; // Position in the message buffer |
|
42 |
uint8_t lim; // Max number of bytes to read into the message buf |
|
43 |
state_t state; // State machine |
|
44 |
uint16_t count; |
|
45 |
|
|
46 |
r = 0; |
|
47 |
crc = 0; |
|
48 |
cmd = 0; |
|
49 |
pos = 0; |
|
50 |
lim = 0; |
|
51 |
state = sd; |
|
52 |
count = 0; |
|
53 |
|
|
54 |
while (1) { |
|
55 |
// Wait for the next byte |
|
56 |
while ((rs485_get_byte(&r)) < 0) { |
|
57 |
if (count >= MAX_TIMEOUT) { |
|
58 |
return TT_BAD; |
|
59 |
} else { |
|
60 |
count++; |
|
61 |
} |
|
62 |
} |
|
63 |
|
|
64 |
switch (state) { |
|
65 |
case sd: |
|
66 |
if (r == DELIM) { |
|
67 |
state = src; |
|
68 |
} |
|
69 |
break; |
|
70 |
|
|
71 |
case src: |
|
72 |
if (r == DELIM) { |
|
73 |
state = src; |
|
74 |
} else { |
|
75 |
crc = r; |
|
76 |
state = dest; |
|
77 |
} |
|
78 |
break; |
|
79 |
|
|
80 |
case dest: |
|
81 |
if (r == DELIM) { |
|
82 |
state = src; |
|
83 |
} else if (r == addr) { |
|
84 |
crc ^= r; |
|
85 |
state = comd; |
|
86 |
} else { |
|
87 |
state = sd; |
|
88 |
} |
|
89 |
break; |
|
90 |
|
|
91 |
case comd: |
|
92 |
cmd = r; |
|
93 |
crc ^= r; |
|
94 |
|
|
95 |
if (r == DELIM) { |
|
96 |
state = src; |
|
97 |
} else if (r == TT_PROGM) { |
|
98 |
lim = PROGM_PACKET_SIZE; |
|
99 |
state = read; |
|
100 |
} else if (r == TT_PROGD) { |
|
101 |
lim = PROGD_PACKET_SIZE; |
|
102 |
state = read; |
|
103 |
} else if (r == TT_SEND_KEY) { |
|
104 |
lim = SEND_KEY_PACKET_SIZE; |
|
105 |
state = read; |
|
106 |
} else { |
|
107 |
state = cs; |
|
108 |
} |
|
109 |
break; |
|
110 |
|
|
111 |
case read: |
|
112 |
mbuf[pos] = r; |
|
113 |
crc ^= r; |
|
114 |
pos++; |
|
115 |
|
|
116 |
if (pos == lim) { |
|
117 |
state = cs; |
|
118 |
} |
|
119 |
|
|
120 |
break; |
|
121 |
|
|
122 |
case cs: |
|
123 |
if (r == crc) { |
|
124 |
if (cmd == TT_RESET) { |
|
125 |
reset(); |
|
126 |
} |
|
127 |
return cmd; |
|
128 |
} else { |
|
129 |
return TT_BAD; |
|
130 |
} |
|
131 |
|
|
132 |
break; |
|
133 |
|
|
134 |
default: |
|
135 |
return TT_BAD; |
|
136 |
} |
|
137 |
} |
|
138 |
} |
|
139 |
|
|
140 |
/** |
|
141 |
* @brief Sends a packet of type cmd onto the network |
|
142 |
* @param cmd The command to send |
|
143 |
* @param addr The address of the sending node |
|
144 |
*/ |
|
145 |
void send_packet(uint8_t cmd, uint8_t addr) { |
|
146 |
rs485_send_byte(DELIM); |
|
147 |
rs485_send_byte(addr); |
|
148 |
rs485_send_byte(SERVER); |
|
149 |
rs485_send_byte(cmd); |
|
150 |
rs485_send_byte(addr ^ SERVER ^ cmd); |
|
151 |
} |
|
152 |
|
|
153 |
/** |
|
154 |
* @brief Sends a packet of type cmd onto the network |
|
155 |
* @param cmd The command to send |
|
156 |
* @param addr The address of the sending node |
|
157 |
* @param data Pointer to data |
|
158 |
* @param len Number of bytes to send |
|
159 |
*/ |
|
160 |
void send_packet_data(uint8_t cmd, uint8_t addr, uint8_t* data, uint8_t len) { |
|
161 |
uint8_t i; |
|
162 |
uint8_t crc = 0; |
|
163 |
|
|
164 |
rs485_send_byte(DELIM); |
|
165 |
rs485_send_byte(addr); |
|
166 |
rs485_send_byte(SERVER); |
|
167 |
rs485_send_byte(cmd); |
|
168 |
for (i = 0; i < len; i++) { |
|
169 |
crc ^= data[i]; |
|
170 |
rs485_send_byte(data[i]); |
|
171 |
} |
|
172 |
rs485_send_byte(addr ^ SERVER ^ cmd ^ crc); |
|
173 |
} |
|
174 |
|
trunk/cardbox/Makefile | ||
---|---|---|
91 | 91 |
# Each directory must be seperated by a space. |
92 | 92 |
# Use forward slashes for directory separators. |
93 | 93 |
# For a directory that has spaces, enclose it in quotes. |
94 |
EXTRAINCDIRS = Y:/code/firefly_plus_lib |
|
95 |
#C:\WinAVR\include\fwr |
|
94 |
EXTRAINCDIRS = ../common |
|
96 | 95 |
|
97 | 96 |
|
98 | 97 |
# Compiler flag to set the C Standard level. |
trunk/cardbox/packet.h | ||
---|---|---|
1 |
#ifndef _PACKET_H_ |
|
2 |
#define _PACKET_H_ |
|
3 |
|
|
4 |
#include <tooltron.h> |
|
5 |
#include <avr/eeprom.h> |
|
6 |
#include "rs485_poll.h" |
|
7 |
#include "bootloader.h" |
|
8 |
|
|
9 |
/** @brief Max time to wait until we exit the packet handler */ |
|
10 |
#define MAX_TIMEOUT 60000 |
|
11 |
|
|
12 |
char parse_packet(uint8_t *mbuf, uint8_t addr); |
|
13 |
void send_packet(uint8_t cmd, uint8_t addr); |
|
14 |
void send_packet_data(uint8_t cmd, uint8_t addr, uint8_t* data, uint8_t len); |
|
15 |
|
|
16 |
|
|
17 |
#endif |
Also available in: Unified diff