Revision 211
| trunk/cardbox/rs485_int.c (revision 211) | ||
|---|---|---|
| 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 (revision 211) | ||
|---|---|---|
| 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 (revision 211) | ||
|---|---|---|
| 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 (revision 211) | ||
|---|---|---|
| 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 (revision 211) | ||
|---|---|---|
| 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 (revision 211) | ||
|---|---|---|
| 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