funkbridge/funkbridge.c

244 lines
7.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/boot.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "target.h"
#include "rfm12.h"
#include "uart.h"
/* *********************************************************************** */
#define BRIDGE_CMD_IDLE 0x00
#define BRIDGE_CMD_TRANSMIT 'T'
#define BRIDGE_CMD_RECEIVE 'R'
#define BRIDGE_CMD_VERSION 'V'
#define BRIDGE_CAUSE_SUCCESS 0x00
#define BRIDGE_CAUSE_TIMEOUT 0x01
#define BRIDGE_CAUSE_NOT_SUPPORTED 0xF0
#define BRIDGE_CAUSE_INVALID_PARAMETER 0xF1
#define BRIDGE_CAUSE_UNSPECIFIED_ERROR 0xFF
/* *********************************************************************** */
static uint8_t led_timer;
volatile static uint8_t clock_tick;
ISR(TIMER0_OVF_vect)
{
TCNT0 = TIMER_RELOAD;
clock_tick = 1;
} /* TIMER0_OVF_vect */
/*
* 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) __attribute__ ((noreturn));
int main(void)
{
/* init LEDs */
LED_INIT();
/* timer0, FCPU/64, overflow interrupt */
TCCR0B = (1<<CS01) | (1<<CS00);
TIMSK0 = (1<<TOIE0);
uart_init();
rfm12_init(RFM12_ADDRESS);
sei();
uint8_t command = BRIDGE_CMD_IDLE;
uint8_t timeout = 0;
uint8_t datalen = 0;
uint8_t bcnt = 0;
while (1)
{
if (clock_tick)
{
clock_tick = 0;
if (led_timer > 0)
{
LED_ON();
led_timer--;
}
else
{
LED_OFF();
}
/* do periodic work (wait for 5 ticks silence before start TX) */
rfm12_tick(5);
if (timeout != 0)
{
timeout--;
}
}
uint8_t rx_count = uart_rx_count();
if ((command == BRIDGE_CMD_IDLE) && (rx_count != 0))
{
command = uart_getc();
datalen = 0;
timeout = 0;
bcnt = 1;
switch (command)
{
case 'R':
timeout = 200;
case 'T':
case 'V':
break;
default:
uart_putc(command);
uart_putc(BRIDGE_CAUSE_NOT_SUPPORTED);
uart_putc(0x00);
command = BRIDGE_CMD_IDLE;
break;
}
}
else if ((bcnt == 1) && (rx_count != 0))
{
datalen = uart_getc();
bcnt++;
}
else
{
if ((command == BRIDGE_CMD_TRANSMIT) & (bcnt == 2) && (rx_count == datalen))
{
struct rfm12_packet * pkt = rfm12_get_txpkt();
if (pkt == (void *)0)
{
uart_putc(command);
uart_putc(BRIDGE_CAUSE_UNSPECIFIED_ERROR);
uart_putc(0x00);
}
else
{
pkt->dest_address = uart_getc();
pkt->source_address = uart_getc();
pkt->data_length = uart_getc();
pkt->header_checksum = uart_getc();
datalen -= 4;
uint8_t i = 0;
while (datalen--)
{
pkt->data[i++] = uart_getc();
}
rfm12_start_tx();
led_timer = 5;
uart_putc(command);
uart_putc(BRIDGE_CAUSE_SUCCESS);
uart_putc(0x00);
}
command = BRIDGE_CMD_IDLE;
}
else if ((command == BRIDGE_CMD_RECEIVE) && (bcnt == 2))
{
if ((datalen != 0) && (rx_count != 0))
{
datalen--;
uart_getc();
}
else if (timeout == 0)
{
uart_putc(command);
uart_putc(BRIDGE_CAUSE_TIMEOUT);
uart_putc(0);
command = BRIDGE_CMD_IDLE;
}
else
{
struct rfm12_packet *pkt = rfm12_get_rxpkt();
if (pkt)
{
uint8_t i;
led_timer = 5;
uart_putc(command);
uart_putc(BRIDGE_CAUSE_SUCCESS);
uart_putc(pkt->data_length + 4);
uart_putc(pkt->dest_address);
uart_putc(pkt->source_address);
uart_putc(pkt->data_length);
uart_putc(pkt->header_checksum);
for (i = 0; i < pkt->data_length; i++)
{
uart_putc(pkt->data[i]);
}
command = BRIDGE_CMD_IDLE;
}
}
}
else if ((command == BRIDGE_CMD_VERSION) && (bcnt == 2))
{
if ((datalen != 0) && (rx_count != 0))
{
datalen--;
uart_getc();
}
else
{
uart_putc(command);
uart_putc(BRIDGE_CAUSE_SUCCESS);
uart_putc(16);
uart_putstr("funkbridge v0.99");
command = BRIDGE_CMD_IDLE;
}
}
}
}
} /* main */