You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
9.0 KiB
C

7 years ago
#include "hw.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <stdlib.h>
#include <string.h>
#include "hbw.h"
uint8_t my_address[4];
uint8_t rind;
uint16_t rcrc;
uint8_t raddress[4];
uint8_t rdest[4];
uint8_t resc;
uint8_t rctl;
volatile uint8_t rready;
uint8_t rmessage[62];
uint8_t rlen;
uint8_t sind;
uint8_t sdisc;
uint8_t sctl;
uint16_t scrc;
uint8_t sesc;
uint8_t saddress[4];
uint8_t slen;
uint8_t smessage[62];
uint16_t sdelay;
uint8_t asent;
uint8_t waitack;
uint8_t gotack;
static uint16_t crc16shift(uint16_t crc, uint8_t data)
{
int stat, i;
for (i=0; i<8; i++) {
stat = crc & 0x8000;
crc = crc << 1;
if (data & 0x80)
crc = crc | 1;
if (stat)
crc = crc ^ 0x1002;
data = data << 1;
}
return crc;
}
static void readaddr(void)
{
my_address[0]=eeprom_read_byte((const uint8_t *)EESIZE-4);
my_address[1]=eeprom_read_byte((const uint8_t *)EESIZE-3);
my_address[2]=eeprom_read_byte((const uint8_t *)EESIZE-2);
my_address[3]=eeprom_read_byte((const uint8_t *)EESIZE-1);
if ((my_address[0] == 0xFF) &&
(my_address[1] == 0xFF) &&
(my_address[2] == 0xFF) &&
(my_address[3] == 0xFF))
my_address[0] = 0x42;
}
static void send(uint8_t i,uint8_t crc)
{
if (bit_is_set(UCSR0A, UDRE0)) {
if (sesc) {
UDR0 = i & 0x7F;
sind++;
sesc = 0;
return;
}
if (crc == 1) {
scrc = crc16shift(scrc, i);
}
if (crc == 2) {
scrc = crc16shift(scrc, 0);
scrc = crc16shift(scrc, 0);
i = (scrc >> 8) & 0xFF;
}
if ((i == 0xFD) || (i == 0xFC) || (i == 0xFE)) {
UDR0 = 0xFC;
sesc = 1;
return;
}
UDR0 = i;
sind++;
}
}
void rloop(void)
{
if (!sind)
return;
if (sdisc) {
if (sind == 1) {
send(0x04,1);
return;
}
if (sind == 2) {
send(0x01,1);
return;
}
if (sind == 3) {
send((scrc >> 8) & 0xFF,2);
return;
}
if (sind == 4) {
send(scrc & 0xFF,0);
return;
}
if (bit_is_set(UCSR0A, TXC0)) {
PORTD &= ~(1<<SenderEnable);
PORTD &= ~(1<<ReceiverDisable);
sind = 0;
sdisc = 0;
}
return;
}
if (sind < 5) {
send(saddress[sind-1],1);
return;
}
if (sind == 5) {
send(sctl,1);
return;
}
if (sind < 10) {
send(my_address[sind-6],1);
return;
}
if (sind == 10) {
send(slen+2,1);
return;
}
if (sind < slen+10) {
send(smessage[sind-11],1);
return;
}
if (sind == slen+10) {
send(smessage[sind-11],1);
return;
}
if (sind == slen+11) {
send((scrc >> 8) & 0xFF,2);
return;
}
if (sind == slen+12) {
send(scrc & 0xFF,0);
return;
}
if (bit_is_set(UCSR0A, TXC0)) {
PORTD &= ~(1<<SenderEnable);
PORTD &= ~(1<<ReceiverDisable);
sind = 0;
}
}
static uint8_t sendmsg(void)
{
if (sind)
return 0;
PORTD |= (1<<SenderEnable);
PORTD |= (1<<ReceiverDisable);
UCSR0A = (1<<TXC0);
scrc = crc16shift(0xFFFF, 0xFD);
UDR0 = 0xFD;
sind = 1;
sesc = 0;
sdisc = 0;
return ~0;
}
static uint8_t senddsc(void)
{
if (sind)
return 0;
PORTD |= (1<<SenderEnable);
PORTD |= (1<<ReceiverDisable);
UCSR0A = (1<<TXC0);
scrc = crc16shift(0xFFFF, 0xFE);
UDR0 = 0xFE;
sind = 1;
sesc = 0;
sdisc = 1;
return ~0;
}
static uint8_t is_bus_free(void)
{
if(sdelay - hbw_timer > 0x7FFF)
return 1;
return 0;
}
static void announce(void)
{
sctl = 0xF8;
saddress[0] = 0xFF;
saddress[1] = 0xFF;
saddress[2] = 0xFF;
saddress[3] = 0xFF;
slen = 16;
smessage[0] = 0x41;
smessage[1] = 0;
smessage[2] = HBWTYPE;
smessage[3] = 0;
smessage[4] = HBWMAJOR;
smessage[5] = HBWMINOR;
smessage[6] = HBWSERIAL0;
smessage[7] = HBWSERIAL1;
smessage[8] = HBWSERIAL2;
smessage[9] = HBWSERIAL3;
smessage[10] = HBWSERIAL4;
smessage[11] = HBWSERIAL5;
smessage[12] = HBWSERIAL6;
smessage[13] = HBWSERIAL7;
smessage[14] = HBWSERIAL8;
smessage[15] = HBWSERIAL9;
sendmsg();
asent = 1;
}
void hbw_init(void)
{
DDRD |= (1<<SenderEnable);
DDRD |= (1<<ReceiverDisable);
PORTD &= ~(1<<SenderEnable);
PORTD &= ~(1<<ReceiverDisable);
UBRR0L = ((F_CPU/(BAUDRATE*16))-1) & 0xFF;
UBRR0H = 0;
UCSR0B = (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0);
UCSR0C = (1 << UPM01) | (1 << UCSZ01) | (1 << UCSZ00);
OCR2A = 0xF9;
TIMSK2 |= (1 << OCIE2A);
TCCR2A |= (1 << WGM21);
TCCR2B = TCCR2B | (1 << CS21) | (1 << CS20);
rind = 0;
sind = 0;
sdisc = 0;
rready = 0;
asent = 0;
hbw_timer = 0;
readaddr();
srand(my_address[3]);
sdelay = 1000 + (rand() & 0x1F);
sei();
}
static void process(void)
{
uint8_t seq,i;
uint16_t addr;
if ((rdest[0] == my_address[0]) &&
(rdest[1] == my_address[1]) &&
(rdest[2] == my_address[2]) &&
(rdest[3] == my_address[3]) &&
((rctl & 0x13) == 0x11)) {
if (waitack) {
waitack = 0;
gotack = 1;
}
return;
}
if ((rdest[0] == my_address[0]) &&
(rdest[1] == my_address[1]) &&
(rdest[2] == my_address[2]) &&
(rdest[3] == my_address[3]) &&
((rctl & 0x11) == 0x10)) {
saddress[0] = raddress[0];
saddress[1] = raddress[1];
saddress[2] = raddress[2];
saddress[3] = raddress[3];
seq = (rctl >> 1) & 3;
switch (rmessage[0]) {
case '@':
if (rmessage[1] == 'a') {
eeprom_write_byte((uint8_t *)EESIZE-4, rmessage[2]);
eeprom_write_byte((uint8_t *)EESIZE-3, rmessage[3]);
eeprom_write_byte((uint8_t *)EESIZE-2, rmessage[4]);
eeprom_write_byte((uint8_t *)EESIZE-1, rmessage[5]);
readaddr();
}
slen = 0;
sctl = 0x19 | (seq << 5);
sendmsg();
break;
case 'h':
smessage[0] = HBWTYPE;
smessage[1] = 0;
slen = 2;
sctl = 0x18 | (seq << 5);
sendmsg();
break;
case 'n':
smessage[0] = HBWSERIAL0;
smessage[1] = HBWSERIAL1;
smessage[2] = HBWSERIAL2;
smessage[3] = HBWSERIAL3;
smessage[4] = HBWSERIAL4;
smessage[5] = HBWSERIAL5;
smessage[6] = HBWSERIAL6;
smessage[7] = HBWSERIAL7;
smessage[8] = HBWSERIAL8;
smessage[9] = HBWSERIAL9;
slen = 10;
seq = (rctl >> 1) & 3;
sctl = 0x18 | (seq << 5);
sendmsg();
break;
case 'v':
smessage[0] = HBWMAJOR;
smessage[1] = HBWMINOR;
slen = 2;
seq = (rctl >> 1) & 3;
sctl = 0x18 | (seq << 5);
sendmsg();
break;
case 'R':
addr = (rmessage[1] >> 8) | rmessage[2];
for (i = 0; i < rmessage[3]; i++)
smessage[i] = eeprom_read_byte((const uint8_t *)addr+i);
slen = rmessage[3];
seq = (rctl >> 1) & 3;
sctl = 0x18 | (seq << 5);
sendmsg();
break;
case 'W':
addr = (rmessage[1] >> 8) | rmessage[2];
for (i = 0; i < rmessage[3]; i++)
eeprom_write_byte((uint8_t *)addr+i, rmessage[4+i]);
slen = 0;
sctl = 0x19 | (seq << 5);
sendmsg();
break;
case 'x':
case 's':
hbw_set_channel(rmessage[1], rlen - 2, &(rmessage[2]));
case 'S':
smessage[0] = 'i';
smessage[1] = rmessage[1];
slen = hbw_get_channel(rmessage[1], &(smessage[2])) + 2;
seq = (rctl >> 1) & 3;
sctl = 0x18 | (seq << 5);
sendmsg();
break;
case 'C':
slen = 0;
sctl = 0x19 | (seq << 5);
sendmsg();
break;
}
}
}
void hbw_loop(void)
{
rloop();
if (rready) {
process();
rready = 0;
}
if (!asent) {
if (is_bus_free()) {
announce();
}
}
}
uint8_t hbw_send_channel(uint8_t channel, uint8_t length, uint8_t const * const data, uint32_t target_address)
{
if (gotack) {
gotack = 0;
return 1;
}
if (!is_bus_free())
return 0;
if (waitack)
return 0;
slen = length + 2;
sctl = 0xF8;
saddress[0] = eeprom_read_byte((const uint8_t *)2);
saddress[1] = eeprom_read_byte((const uint8_t *)3);
saddress[2] = eeprom_read_byte((const uint8_t *)4);
saddress[3] = eeprom_read_byte((const uint8_t *)5);
smessage[0] = 'i';
smessage[1] = channel;
memcpy(&(smessage[2]), data, length);
sendmsg();
waitack = 1;
gotack = 0;
return 0;
}
ISR(USART_RX_vect)
{
uint8_t c;
sdelay = hbw_timer + 100 + (rand() & 0x1F);
c = UDR0;
if (c == 0xFE) {
rind = 255;
resc = 0;
}
if (c == 0xFD) {
rind = 0;
resc = 0;
rready = 0;
rcrc =0xFFFF;
}
if (rind < 255) {
if (c == 0xFC) {
resc = 1;
return;
}
if (resc)
c = c | 0x80;
rcrc = crc16shift(rcrc, c);
resc = 0;
rind++;
}
if ((rind == 1) || (rind == 255))
return;
if (rind < 6) {
rdest[rind-2] = c;
return;
}
if (rind == 6) {
rctl = c;
return;
}
if (rind < 11) {
raddress[rind-7] = c;
return;
}
if (rind == 11) {
rlen = c;
return;
}
if ((rlen < 2) || (rlen > 64)) {
rind = 255;
return;
}
if ((rind < rlen + 10)) {
rmessage[rind-12] = c;
return;
}
if (rind == rlen + 10)
return;
if (rind == rlen + 11) {
rind = 255;
if (rcrc)
return;
rready = 1;
return;
}
}
ISR(TIMER2_COMPA_vect)
{
cli();
hbw_timer++;
sei();
}