/*************************************************************************** * 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 #include #include #include #include /* 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< 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 */