291 lines
9.2 KiB
C
291 lines
9.2 KiB
C
/***************************************************************************
|
|
* Copyright (C) 11/2014 by Olaf Rempel *
|
|
* razzor@kopf-tisch.de *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; version 2 of the License, *
|
|
* *
|
|
* This program 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 *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/wdt.h>
|
|
#include <avr/pgmspace.h>
|
|
|
|
#include <string.h> /* memcpy() */
|
|
|
|
#include "event.h"
|
|
#include "input.h"
|
|
#include "pwm.h"
|
|
#include "rfm12.h"
|
|
#include "timer.h"
|
|
#include "uart.h"
|
|
|
|
#include "funk_proto.h"
|
|
#include "target.h"
|
|
|
|
/* *********************************************************************** */
|
|
|
|
#define LED_RX 0
|
|
#define LED_TX 1
|
|
|
|
static uint8_t led[2];
|
|
volatile static uint8_t clock_tick;
|
|
|
|
ISR(TIMER0_OVF_vect)
|
|
{
|
|
/* 1ms interrupt */
|
|
TCNT0 = TIMER_RELOAD;
|
|
|
|
clock_tick = 1;
|
|
} /* TIMER0_OVF_vect */
|
|
|
|
|
|
void uart_event_handler(struct event_entry *event)
|
|
{
|
|
/* output all events on UART */
|
|
uart_putstr_p(PSTR("evt: "));
|
|
uart_put_hex(event->type);
|
|
uart_putc(' ');
|
|
uart_put_hex(event->num);
|
|
uart_putc(' ');
|
|
uart_put_hex(event->value >> 8);
|
|
uart_put_hex(event->value & 0xFF);
|
|
uart_putstr("\r\n");
|
|
} /* uart_event_handler */
|
|
|
|
|
|
/*
|
|
* For newer devices the watchdog timer remains active even after a
|
|
* system reset. So disable it as soon as possible.
|
|
* automagically called on startup
|
|
*/
|
|
void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
|
|
void disable_wdt_timer(void)
|
|
{
|
|
MCUSR = 0;
|
|
WDTCSR = (1<<WDCE) | (1<<WDE);
|
|
WDTCSR = (0<<WDE);
|
|
} /* disable_wdt_timer */
|
|
|
|
|
|
int main(void)
|
|
{
|
|
LED_INIT();
|
|
|
|
/* timer0, FCPU/64, overflow interrupt */
|
|
TCCR0B = (1<<CS01) | (1<<CS00);
|
|
TIMSK0 = (1<<TOIE0);
|
|
|
|
uart_init();
|
|
input_init();
|
|
pwm_init();
|
|
|
|
rfm12_init(RFM12_ADDRESS);
|
|
|
|
sei();
|
|
|
|
uart_putstr_p(PSTR("init\r\n"));
|
|
|
|
while (1)
|
|
{
|
|
if (clock_tick)
|
|
{
|
|
clock_tick = 0;
|
|
|
|
if (led[LED_RX] > 0)
|
|
{
|
|
led[LED_RX]--;
|
|
LED_GN_ON();
|
|
}
|
|
else
|
|
{
|
|
LED_GN_OFF();
|
|
}
|
|
|
|
if (led[LED_TX] > 0)
|
|
{
|
|
led[LED_TX]--;
|
|
LED_RT_ON();
|
|
}
|
|
else
|
|
{
|
|
LED_RT_OFF();
|
|
}
|
|
|
|
/* do periodic work (wait for 5 ticks silence before start TX) */
|
|
rfm12_tick(5);
|
|
|
|
input_tick();
|
|
timer_tick();
|
|
}
|
|
|
|
struct event_entry *event = event_get();
|
|
if (event->type != EVENT_TYPE_EMPTY)
|
|
{
|
|
uart_event_handler(event);
|
|
|
|
switch (event->type)
|
|
{
|
|
case EVENT_TYPE_PWM_COMMAND:
|
|
case EVENT_TYPE_PWM_VALUE:
|
|
pwm_event_handler(event);
|
|
break;
|
|
|
|
case EVENT_TYPE_INPUT:
|
|
if (event->num == EVENT_NUM_INPUT_QUAD)
|
|
{
|
|
if (event->value == EVENT_VALUE_INPUT_QUAD_DEC)
|
|
{
|
|
event_queue(EVENT_TYPE_PWM_COMMAND,
|
|
EVENT_NUM_PWM_CH1,
|
|
EVENT_VALUE_PWM_DEC
|
|
);
|
|
}
|
|
else if (event->value == EVENT_VALUE_INPUT_QUAD_INC)
|
|
{
|
|
event_queue(EVENT_TYPE_PWM_COMMAND,
|
|
EVENT_NUM_PWM_CH1,
|
|
EVENT_VALUE_PWM_INC
|
|
);
|
|
}
|
|
}
|
|
else if (event->num == EVENT_NUM_INPUT_BUTTON)
|
|
{
|
|
if (event->value == EVENT_VALUE_INPUT_BUTTON_PRESSED)
|
|
{
|
|
event_queue(EVENT_TYPE_PWM_COMMAND,
|
|
EVENT_NUM_PWM_CH1,
|
|
PWM_MODE_TOGGLE
|
|
);
|
|
}
|
|
}
|
|
else if (event->num == EVENT_NUM_INPUT_DOOR)
|
|
{
|
|
if (event->value == EVENT_VALUE_INPUT_DOOR_CLOSED)
|
|
{
|
|
event_queue(EVENT_TYPE_PWM_COMMAND,
|
|
EVENT_NUM_PWM_CH0,
|
|
EVENT_VALUE_PWM_KEEP
|
|
);
|
|
|
|
event_queue(EVENT_TYPE_TIMER_SET,
|
|
TIMER_DOOR_CLOSE_DELAY,
|
|
2000
|
|
);
|
|
}
|
|
else if (event->value == EVENT_VALUE_INPUT_DOOR_OPEN)
|
|
{
|
|
event_queue(EVENT_TYPE_PWM_COMMAND,
|
|
EVENT_NUM_PWM_CH0,
|
|
EVENT_VALUE_PWM_FADE_MAX
|
|
);
|
|
|
|
event_queue(EVENT_TYPE_TIMER_SET,
|
|
TIMER_DOOR_CLOSE_DELAY,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVENT_TYPE_TIMER_SET:
|
|
timer_event_handler(event);
|
|
break;
|
|
|
|
case EVENT_TYPE_TIMER_ELAPSED:
|
|
if (event->num == TIMER_DOOR_CLOSE_DELAY)
|
|
{
|
|
event_queue(EVENT_TYPE_PWM_COMMAND,
|
|
EVENT_NUM_PWM_CH0,
|
|
EVENT_VALUE_PWM_FADE_MIN
|
|
);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
event_clear();
|
|
}
|
|
|
|
/* get RX data */
|
|
struct rfm12_packet *req_pkt = rfm12_get_rxpkt();
|
|
struct rfm12_packet *rsp_pkt = rfm12_get_txpkt();
|
|
if (req_pkt != NULL)
|
|
{
|
|
led[LED_RX] = 5;
|
|
if (rsp_pkt == NULL)
|
|
{
|
|
rfm12_clear_rx();
|
|
continue;
|
|
}
|
|
|
|
struct rfm12_msg *req_msg = (struct rfm12_msg *)req_pkt->data;
|
|
struct rfm12_msg *rsp_msg = (struct rfm12_msg *)rsp_pkt->data;
|
|
|
|
/* retransmitted request -> retransmit response */
|
|
if ((req_pkt->source_address == rsp_pkt->dest_address) &&
|
|
((req_msg->command & MSG_CMD_MASK) == (rsp_msg->command & MSG_CMD_MASK)) &&
|
|
(req_msg->seqnum == rsp_msg->seqnum)
|
|
)
|
|
{
|
|
/* RX packet no longer needed */
|
|
rfm12_clear_rx();
|
|
|
|
/* transmit response */
|
|
if (rfm12_start_tx())
|
|
{
|
|
led[LED_TX] = 5;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
rsp_pkt->dest_address = req_pkt->source_address;
|
|
rsp_pkt->data_length = 3;
|
|
rsp_msg->command = req_msg->command | MSG_TYPE_RESPONSE;
|
|
rsp_msg->seqnum = req_msg->seqnum;
|
|
rsp_msg->cause = CAUSE_SUCCESS;
|
|
|
|
switch (req_msg->command)
|
|
{
|
|
case MSG_CMD_SWITCHAPP_REQUEST:
|
|
if (req_msg->p.switchapp.app == BOOTMODE_BOOTLOADER)
|
|
{
|
|
wdt_enable(WDTO_15MS);
|
|
}
|
|
else if (req_msg->p.switchapp.app != BOOTMODE_APPLICATION)
|
|
{
|
|
rsp_msg->cause = CAUSE_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rsp_msg->cause = CAUSE_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
/* RX packet no longer needed */
|
|
rfm12_clear_rx();
|
|
|
|
/* transmit response */
|
|
if (rfm12_start_tx())
|
|
{
|
|
led[LED_TX] = 5;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
} /* main */
|