Project

General

Profile

Revision 202

Added by Kevin Woo about 14 years ago

  • Moved the reset code to toolbox since it is the only code that uses it
  • Optimized the toolbox statemachine to use parse_packet and the bootloader
    function
  • Small byte optimizations.
  • Down from 1024 bytes to 768 bytes

View differences:

trunk/toolbox/reset.c
1
#include <avr/wdt.h>
2

  
3
/**
4
 * This function resets the board, resetting the hardware back to almost the
5
 * same state as a power on reset. Note that you must do the following in
6
 * this order upon reset or the process will fail:
7
 *
8
 * 1. Reset WDRF in MCUSR to 0
9
 * 2. call wdt_diable() to disable the watchdog in the right order
10
 * 3. Set WDTCSR to clear out all traces of the watchdog timer
11
 **/
12
void reset(void) {
13
    wdt_enable(WDTO_15MS);
14
    while(1);
15
}
trunk/toolbox/main.c
26 26
//Includes
27 27
#include <avr/io.h>
28 28
#include <avr/interrupt.h>
29
#include <avr/eeprom.h>
29 30
#include <stdint.h>
30 31
#include <util/delay.h>
31 32
#include <tooltron.h>
32 33
#include "jumptable.h"
34
#include "reset.h"
33 35
#include <toolbox_pindefs.h>
34
#define TOOLBOX
35
#define RELAY       _BV(PORTD4)
36
#define VAC_SENSE   _BV(PIND3)
37
#define BUT_RED     _BV(PINB4)
38
#define BUT_BLACK   _BV(PINB3)
39
#define LED_GREEN   _BV(PORTB2)
40
#define LED_YELLOW  _BV(PORTB1)
41
#define LED_RED     _BV(PORTB0)
42
#define ON      0x01
43
#define OFF     0x00
44 36

  
45
/***** change ADDR ****/
46
#define ADDR 18
47
#define DELIM '^'
48
#define SERVER 1
49
#define TURNON 'O' 'O''0'
50

  
51 37
/***
52 38
 * TWAIT - minutes to wait before green button is pressed to kill power
53 39
 * TWARN - minutes until warning (blink yellow, allow more time with green button)
......
61 47
uint8_t min;
62 48

  
63 49
typedef enum {
64
    sd,     // start delimitor
65
    src,    // src
66
    dest,   // destination
67
    data,   // data
68
    cs,     // checksum
69
    ack,    // send ack
50
    wait,   // wait for a turn on packet
70 51
    pwron,  // poweron
71 52
    idiot,  // user tried to hit green with the machine switch on
72 53
    toolon, // tool on
......
74 55
    off     // tool off
75 56
} state_t;
76 57

  
77
void init_pins(void) {
78
    DDRB = 0x00;
79
    DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB5);
80
    DDRD = _BV(DDB4);
81
    PORTB = 0x00;
82
}
83

  
58
/**
59
 * @brief Sets the LED to the specified state
60
 *
61
 * This sets LED which to the specified state. You can use this to set
62
 * multiple LEDs if you OR the LEDs desired into the which argument.
63
 *
64
 * @param which The LEDs to set
65
 * @parma state The state ON or OFF to set to the LEDs to
66
 * @return void
67
 */
84 68
void toggle_led(uint8_t which, uint8_t state) {
85 69
    if (state == ON) {
86
        PORTB &= ~which;
70
        LED_PORT &= ~(which);
87 71
    } else {
88
        PORTB |= which;
72
        LED_PORT |= (which);
89 73
    }
90 74
}
91 75

  
76
/**
77
 * @brief Sets the relay to a particular state
78
 *
79
 * @param state Sets the relay to either ON or OFF
80
 * @return void
81
 */
92 82
void toggle_relay(uint8_t state) {
93 83
    if (state == ON) {
94
        PORTD |= RELAY;
84
        RELAY_PORT |= RELAY;
95 85
    } else {
96
        PORTD &= ~RELAY;
86
        RELAY_PORT &= ~RELAY;
97 87
    }
98 88
}
99 89

  
90
/**
91
 * @brief Returns the current value of the AC voltage sense
92
 *
93
 * @return ON if AC voltage is detected, OFF otherwise
94
 */
100 95
inline uint8_t read_vac(void) {
101
    return (!(PIND & VAC_SENSE));
96
    return (!(VAC_PORT & VAC_SENSE));
102 97
}
103 98

  
99
/**
100
 * @brief Returns the current value of the buttons
101
 *
102
 * You can read multiple buttons at once but it will only return TRUE
103
 * if all of the buttons are pressed. You should OR the buttons together
104
 * while passing them into which.
105
 *
106
 * @param which The buttons to read
107
 * @return TRUE if the buttons are pressed, FALSE otherwise
108
 */
104 109
inline uint8_t read_button(uint8_t which) {
105
    return (!(PINB & which));
110
    return (!(BUT_PORT & (which)));
106 111
}
107 112

  
113
/**
114
 * @brief Initialize the hardware timer to be a realtime clock
115
 *
116
 * This will set timer 1 to cause an interrupt every 1 second assuming
117
 * you are using a 8MHz clock. The global sec and min counters are 
118
 * reset as well.
119
 *
120
 * @return void
121
 */
108 122
void init_timer(void) {
109 123
    // Clear timmer on OCRA1 Compare match
110 124
    // No prescale
111 125
    TCCR1B |= _BV(WGM12) | _BV(CS12);
112 126
    
113 127
    // 1 second @ 8MHz clock
114
    OCR1AH =0x7A;
115
    OCR1AL =0x12;
128
    OCR1A = 0x7A12;
116 129

  
117 130
    TIMSK = _BV(OCIE1A);
118 131

  
......
120 133
    min = 0;
121 134
}
122 135

  
136
/**
137
 * @brief Resets the timer
138
 * @return void
139
 */
123 140
void reset_timer(void) {
124 141
    sec = 0;
125 142
    min = 0;
126 143
}
127 144

  
145
/**
146
 * @brief Timer1 interrupt vector
147
 *
148
 * This counts the seconds and minute since the last reset. Automatically
149
 * resets the seconds once it rolls over to 60s and increments minutes.
150
 *
151
 * @note minutes may overflow if you let it run long enough. There are no
152
 * checks against this
153
 */
128 154
ISR(TIMER1_COMPA_vect) {
129 155
    if (sec == 59) {
130 156
        sec = 0;
131
        min++;
157
        ++min;
132 158
    } else {
133
        sec++;
159
        ++sec;
134 160
    }
135 161
}
136 162

  
137 163

  
138
int main(int argc, char **argv) {
139
    state_t state = sd;
140
    uint8_t packet[3];
164
int main(void) {
165
    state_t state = wait;
166
    // This reads the node addr
167
    uint8_t addr = eeprom_read_byte((void*)EEPROM_ADDR);    
141 168
    uint8_t ms_timer=0;
169
    uint8_t mbuf[PROGD_PACKET_SIZE];    // For reading messages
142 170

  
143 171
	/***** Start Start-up Sequence *****/
172
    // We are initializing the pins and the RS485 in the bootloader
144 173
	sei();				//Enable interrupts
145 174
	init_timer();		//Set registers for timer
146
	init_pins();		//Set pin directions
147
    rs485_init(51);
148 175
	/***** End Start-up Sequence *****/
149 176

  
150
    uint8_t r;
177
    uint8_t resp;
151 178
    
152
    packet[0] = 0x00;
153
    packet[1] = 0x00;
154
    packet[2] = 0x00;
155
   
156 179
	while(1) {
157 180
        switch (state) {
158
            case sd:
181
            case wait:
182
                // Reset the lights and relay
159 183
                toggle_led(LED_RED, ON);
160
                toggle_led(LED_YELLOW, OFF);
161
                toggle_led(LED_GREEN, OFF);
184
                toggle_led(LED_YELLOW | LED_GREEN, OFF);
162 185
                toggle_relay(OFF);
163
                while ((rs485_get_byte(&r)) < 0);
164
                if (r == DELIM) {
165
                    state = src;
166
                }
167
                break;
168
            case src:
169
                while ((rs485_get_byte(&r)) < 0);
170 186

  
171
                if (r == DELIM) {
172
                    state = src;
173
                } else {
174
                    packet[0] = r;
175
                    state = dest;
176
                }
177
                break;
178
            case dest:
179
                while ((rs485_get_byte(&r)) < 0);
187
                // Wait for a packet
188
                resp = parse_packet(mbuf, addr);
180 189

  
181
                if (r == DELIM) {
182
                    packet[0] = 0x00;
183
                    state = src;
184
                } else if (r == ADDR) {
185
                    packet[1] = r;
186
                    state = data;
187
                } else {
188
                    packet[0] = 0x00;
189
                    state = sd;
190
                }
191
                break;
192
            case data:
193
                while ((rs485_get_byte(&r)) < 0);
194
                
195
                if (r == DELIM) {
196
                    packet[0] = 0x00;
197
                    packet[1] = 0x00;
198
                    state = src;
199
                } else {
200
                    packet[2] = r;
201
                    state = cs;
202
                }
203
                break;
204
            case cs:
205
                while ((rs485_get_byte(&r)) < 0);
190
                // Turn on the tool
191
                if (resp == TT_ON) {
192
                    send_packet(TT_ACK, addr);
206 193

  
207
                if (r == (packet[0] ^ packet[1] ^ packet[2])) {
208

  
209
                    if (packet[2] == TT_TON) {
210
                        state = ack;
211
                        break;
212
                    }
194
                    toggle_led(LED_RED, OFF);
195
                    toggle_led(LED_YELLOW, ON);
196
                    state = pwron;
197
                    reset_timer();
198
                // Reset the board
199
                } else if (resp == TT_RESET) {
200
                    send_packet(TT_ACK, addr);
201
                    reset();
213 202
                }
214

  
215
                packet[0] = 0x00;
216
                packet[1] = 0x00;
217
                packet[2] = 0x00;
218
                state = sd;
219 203
                break;
220
            case ack:
221
                rs485_send_byte(DELIM);
222
                rs485_send_byte(ADDR);
223
                rs485_send_byte(SERVER);
224
                rs485_send_byte('A');
225
                rs485_send_byte(ADDR ^ SERVER ^ 'A');
226

  
227
                toggle_led(LED_RED, OFF);
228
                toggle_led(LED_YELLOW, ON);
229

  
230
                state = pwron;
231
                reset_timer();
232
                break;
233 204
            case pwron:
234
	      if (read_vac() == ON) {
235
		ms_timer = 0;
236
		state = idiot;
237
		break;
238
	      }
205
                // Make sure the tool isn't on before we apply power
206
	            if (read_vac() == ON) {
207
		            ms_timer = 0;
208
		            state = idiot;
209
		            break;
210
	            }
239 211

  
212
                // Wait for a black button press
240 213
                if (read_button(BUT_BLACK)) {
241 214
                    toggle_led(LED_YELLOW, OFF);
242 215
                    toggle_led(LED_GREEN, ON);
......
244 217

  
245 218
                    reset_timer();
246 219
                    state = toolon;
220
                // Timeout waiting for the user
247 221
                } else if ((read_button(BUT_RED)) || (min >= TWAIT)) {
248 222
                    state = off;
249 223
                }
250 224
                break;
251
	    case idiot:
252
	      if (read_vac() == OFF) {
253
		state = pwron;
254
		toggle_led(LED_RED, OFF);
255
		toggle_led(LED_YELLOW, ON);
256
		break;
257
	      }
225
            case idiot:
226
                // We can safely exit this state if the tool is switched off
227
                if (read_vac() == OFF) {
228
                    state = pwron;
229
                    toggle_led(LED_RED, OFF);
230
                    toggle_led(LED_YELLOW, ON);
231
                    break;
232
                }
258 233

  
259
	      if (read_button(BUT_RED)) {
260
		state = off;
261
		break;
262
	      }
234
                // The user has cancelled the tooltron request
235
                if (read_button(BUT_RED)) {
236
                    state = off;
237
                    break;
238
                }
263 239

  
264
	      if(ms_timer >= 100) {
265
		toggle_led(LED_YELLOW, ON);
266
		toggle_led(LED_RED, OFF);
267
		
268
		if(ms_timer >= 200) {
269
		  ms_timer = 0;
270
		}
271
	      }
272
	      else {
273
		toggle_led(LED_YELLOW, OFF);
274
		toggle_led(LED_RED, ON);
275
	      }
240
                // Blink code
241
                if(ms_timer >= 100) {
242
                    toggle_led(LED_YELLOW, ON);
243
                    toggle_led(LED_RED, OFF);
244
            
245
                    if(ms_timer >= 200) {
246
                        ms_timer = 0;
247
                    }
248
                } else {
249
                    toggle_led(LED_YELLOW, OFF);
250
                    toggle_led(LED_RED, ON);
251
                }
276 252

  
277
	      _delay_ms(2);
278
	      ms_timer++;
279
	      break;
253
                _delay_ms(2);
254
                ms_timer++;
255
                break;
280 256

  
281 257
            case toolon:
282
                
258
                // Give the tool power until the red button is pressed
283 259
                if ((read_button(BUT_RED)) && (read_vac() == OFF)) {
284 260
                        state = off;
285 261
                        toggle_relay(OFF);
262
                // Time is about to expire
286 263
                } else if (min >= TWARN) {
287 264
                    toggle_led(LED_GREEN, OFF);
288 265
                    state = warn;
......
290 267
                break;
291 268

  
292 269
            case warn:
293
		if(ms_timer >= 100) {
294
		  toggle_led(LED_YELLOW, ON);
270
                // Blink the LED
271
		        if(ms_timer >= 100) {
272
		            toggle_led(LED_YELLOW, ON);
295 273
		
296
		  if(ms_timer >= 200) {
297
		    ms_timer = 0;
298
		  }
299
		}
300
		else {
301
		  toggle_led(LED_YELLOW, OFF);
302
		}
274
		            if(ms_timer >= 200) {
275
		                ms_timer = 0;
276
		            }
277
		        } else {
278
		            toggle_led(LED_YELLOW, OFF);
279
		        }
303 280

  
281
                // User turns off the tool if it's safe
304 282
                if (read_button(BUT_RED) && read_vac() == OFF) {
305 283
                    toggle_relay(OFF);
306 284
                    state = off;
285
                // Time extension
307 286
                } else if (read_button(BUT_BLACK)) {
308 287
                    toggle_led(LED_GREEN, ON);
309 288
                    toggle_led(LED_YELLOW, OFF);
310 289
                    reset_timer();
311 290
                    state = toolon;
291
                // Time expired and it's safe to turn off
312 292
                } else if ((min >= TMAX) && (read_vac() == OFF)) {
313 293
                    toggle_relay(OFF);
314 294
                    state = off;
315 295
                }
316 296

  
317
		_delay_ms(2);
318
		ms_timer++;
297
		        _delay_ms(2);
298
		        ms_timer++;
319 299

  
320 300
                break;
321 301
            case off:
322
                toggle_led(LED_GREEN, OFF);
323
                toggle_led(LED_YELLOW, OFF);
302
                toggle_led(LED_GREEN | LED_YELLOW, OFF);
324 303
                toggle_led(LED_RED, ON);
325
                state = sd;
304
                state = wait;
326 305
                break;
327
            default: state = sd;
306
            default: state = wait;
328 307
        }     
329
        
330 308
	}
331 309
	
332 310
	return 0;
trunk/toolbox/reset.h
1
#ifndef __RESET_H__
2
#define __RESET_H__
3

  
4
void reset(void) __attribute__((noreturn));
5

  
6
#endif
trunk/toolbox/jumptable.h
16 16
void (*rs485_init)(uint16_t) = JT_RS485_INIT;
17 17
int8_t (*rs485_get_byte)(uint8_t*) = JT_RS485_GET_BYTE;
18 18
void (*rs485_send_byte)(uint8_t) = JT_RS485_SEND_BYTE;
19
char (*parse_packet)(uint8_t*) = JT_PARSE_PACKET;
20
void (*send_packet)(uint8_t) = JT_SEND_PACKET;
19
char (*parse_packet)(uint8_t*, uint8_t) = JT_PARSE_PACKET;
20
void (*send_packet)(uint8_t, uint8_t) = JT_SEND_PACKET;
21 21

  
22 22
#endif
trunk/common/reset.c
1
#include <avr/wdt.h>
2

  
3
/**
4
 * This function resets the board, resetting the hardware back to almost the
5
 * same state as a power on reset. Note that you must do the following in
6
 * this order upon reset or the process will fail:
7
 *
8
 * 1. Reset WDRF in MCUSR to 0
9
 * 2. call wdt_diable() to disable the watchdog in the right order
10
 * 3. Set WDTCSR to clear out all traces of the watchdog timer
11
 **/
12
void reset(void) {
13
    wdt_enabled(WDTO_15MS);
14
}
trunk/common/reset.h
1
#ifndef __RESET_H__
2
#define __RESET_H__
3

  
4
void reset(void);
5

  
6
#endif
trunk/common/toolbox_pindefs.h
8 8
#define RELAY       _BV(PORTD4)
9 9

  
10 10
// AC Voltage Sense
11
#define VAC_PORT    PORTD
11
#define VAC_PORT    PIND
12 12
#define VAC_SENSE   _BV(PIND3)
13 13

  
14 14
// Buttons
trunk/common/tooltron.h
30 30
#define TT_GET_KEY  'k'     // Get a key from the keyboard
31 31
#define TT_ACK      'a'     // Ack
32 32
#define TT_NACK     'n'     // Nack
33
#define TT_TON      'o'     // Turn the tool on
33
#define TT_ON       'o'     // Turn the tool on
34 34
#define TT_TO       'f'     // State timeout
35 35
#define TT_TIMEOUT  't'     // Packet timeout
36 36
#define TT_RESET    'r'     // Tool reset request

Also available in: Unified diff