/********
* This file is part of Tooltron.
*
* Tooltron is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tooltron is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
* You should have received a copy of the Lesser GNU General Public License
* along with Tooltron. If not, see .
*
* Copyright 2009 Kevin Woo
*
********/
/** @file main.c
* @brief Contains the main function for the toolbox code.
*
* @author Suresh Nidhiry (snidhiry@andrew.cmu.edu)
* @author Kevin Woo (kwoo@2ndt.com)
*/
//Includes
#include
#include
#include
#include
#include
#include "jumptable.h"
#include
#define TOOLBOX
#define RELAY _BV(PORTD4)
#define VAC_SENSE _BV(PIND3)
#define BUT_RED _BV(PINB4)
#define BUT_BLACK _BV(PINB3)
#define LED_GREEN _BV(PORTB2)
#define LED_YELLOW _BV(PORTB1)
#define LED_RED _BV(PORTB0)
#define ON 0x01
#define OFF 0x00
/***** change ADDR ****/
#define ADDR 18
#define DELIM '^'
#define SERVER 1
#define TURNON 'O' 'O''0'
/***
* TWAIT - minutes to wait before green button is pressed to kill power
* TWARN - minutes until warning (blink yellow, allow more time with green button)
* TMAX - minutes until power is killed (unless tool is on)
*/
#define TWAIT 1
#define TWARN 1
#define TMAX 2
uint8_t sec;
uint8_t min;
typedef enum {
sd, // start delimitor
src, // src
dest, // destination
data, // data
cs, // checksum
ack, // send ack
pwron, // poweron
idiot, // user tried to hit green with the machine switch on
toolon, // tool on
warn, // time warning
off // tool off
} state_t;
void init_pins(void) {
DDRB = 0x00;
DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB5);
DDRD = _BV(DDB4);
PORTB = 0x00;
}
void toggle_led(uint8_t which, uint8_t state) {
if (state == ON) {
PORTB &= ~which;
} else {
PORTB |= which;
}
}
void toggle_relay(uint8_t state) {
if (state == ON) {
PORTD |= RELAY;
} else {
PORTD &= ~RELAY;
}
}
inline uint8_t read_vac(void) {
return (!(PIND & VAC_SENSE));
}
inline uint8_t read_button(uint8_t which) {
return (!(PINB & which));
}
void init_timer(void) {
// Clear timmer on OCRA1 Compare match
// No prescale
TCCR1B |= _BV(WGM12) | _BV(CS12);
// 1 second @ 8MHz clock
OCR1AH =0x7A;
OCR1AL =0x12;
TIMSK = _BV(OCIE1A);
sec = 0;
min = 0;
}
void reset_timer(void) {
sec = 0;
min = 0;
}
ISR(TIMER1_COMPA_vect) {
if (sec == 59) {
sec = 0;
min++;
} else {
sec++;
}
}
int main(int argc, char **argv) {
state_t state = sd;
uint8_t packet[3];
uint8_t ms_timer=0;
/***** Start Start-up Sequence *****/
sei(); //Enable interrupts
init_timer(); //Set registers for timer
init_pins(); //Set pin directions
rs485_init(51);
/***** End Start-up Sequence *****/
uint8_t r;
packet[0] = 0x00;
packet[1] = 0x00;
packet[2] = 0x00;
while(1) {
switch (state) {
case sd:
toggle_led(LED_RED, ON);
toggle_led(LED_YELLOW, OFF);
toggle_led(LED_GREEN, OFF);
toggle_relay(OFF);
while ((rs485_get_byte(&r)) < 0);
if (r == DELIM) {
state = src;
}
break;
case src:
while ((rs485_get_byte(&r)) < 0);
if (r == DELIM) {
state = src;
} else {
packet[0] = r;
state = dest;
}
break;
case dest:
while ((rs485_get_byte(&r)) < 0);
if (r == DELIM) {
packet[0] = 0x00;
state = src;
} else if (r == ADDR) {
packet[1] = r;
state = data;
} else {
packet[0] = 0x00;
state = sd;
}
break;
case data:
while ((rs485_get_byte(&r)) < 0);
if (r == DELIM) {
packet[0] = 0x00;
packet[1] = 0x00;
state = src;
} else {
packet[2] = r;
state = cs;
}
break;
case cs:
while ((rs485_get_byte(&r)) < 0);
if (r == (packet[0] ^ packet[1] ^ packet[2])) {
if (packet[2] == TT_TON) {
state = ack;
break;
}
}
packet[0] = 0x00;
packet[1] = 0x00;
packet[2] = 0x00;
state = sd;
break;
case ack:
rs485_send_byte(DELIM);
rs485_send_byte(ADDR);
rs485_send_byte(SERVER);
rs485_send_byte('A');
rs485_send_byte(ADDR ^ SERVER ^ 'A');
toggle_led(LED_RED, OFF);
toggle_led(LED_YELLOW, ON);
state = pwron;
reset_timer();
break;
case pwron:
if (read_vac() == ON) {
ms_timer = 0;
state = idiot;
break;
}
if (read_button(BUT_BLACK)) {
toggle_led(LED_YELLOW, OFF);
toggle_led(LED_GREEN, ON);
toggle_relay(ON);
reset_timer();
state = toolon;
} else if ((read_button(BUT_RED)) || (min >= TWAIT)) {
state = off;
}
break;
case idiot:
if (read_vac() == OFF) {
state = pwron;
toggle_led(LED_RED, OFF);
toggle_led(LED_YELLOW, ON);
break;
}
if (read_button(BUT_RED)) {
state = off;
break;
}
if(ms_timer >= 100) {
toggle_led(LED_YELLOW, ON);
toggle_led(LED_RED, OFF);
if(ms_timer >= 200) {
ms_timer = 0;
}
}
else {
toggle_led(LED_YELLOW, OFF);
toggle_led(LED_RED, ON);
}
_delay_ms(2);
ms_timer++;
break;
case toolon:
if ((read_button(BUT_RED)) && (read_vac() == OFF)) {
state = off;
toggle_relay(OFF);
} else if (min >= TWARN) {
toggle_led(LED_GREEN, OFF);
state = warn;
}
break;
case warn:
if(ms_timer >= 100) {
toggle_led(LED_YELLOW, ON);
if(ms_timer >= 200) {
ms_timer = 0;
}
}
else {
toggle_led(LED_YELLOW, OFF);
}
if (read_button(BUT_RED) && read_vac() == OFF) {
toggle_relay(OFF);
state = off;
} else if (read_button(BUT_BLACK)) {
toggle_led(LED_GREEN, ON);
toggle_led(LED_YELLOW, OFF);
reset_timer();
state = toolon;
} else if ((min >= TMAX) && (read_vac() == OFF)) {
toggle_relay(OFF);
state = off;
}
_delay_ms(2);
ms_timer++;
break;
case off:
toggle_led(LED_GREEN, OFF);
toggle_led(LED_YELLOW, OFF);
toggle_led(LED_RED, ON);
state = sd;
break;
default: state = sd;
}
}
return 0;
}