Program the control the fischertechnik robo interface or intelligent interface via tcp socket or via a java gui.

Dependencies:   mbed ConfigFile

rs485.c

Committer:
networker
Date:
2010-12-31
Revision:
0:7f26f0680202

File content as of revision 0:7f26f0680202:

//#define DEBUG //switches PB2 in interrupts and timeouts
#if 0 //for reference only
#define ALLOW_NESTING

#include "data.h"
#include "rs485.h"


#define BAUD 921600
#define DIRPORT    PORTD
#define DIRBIT    PD4
#define DIRDIR    DDRD
#define TRANSMIT  asm("sbi    %0, %1"::"I" (_SFR_IO_ADDR(DIRPORT)),"I" (DIRBIT));
#define RECEIVE      asm("cbi    %0, %1"::"I" (_SFR_IO_ADDR(DIRPORT)),"I" (DIRBIT));


uint8_t /*wpos = 0,*/ rpos = 0;
volatile uint8_t rs485_timeout = 0;
volatile uint8_t rs485_delay = 0;
static char* wposp = (char*)&msg.hdr.snd;
static char state = 0;

void init_rs485()
{
/*Set baud rate */
//Enable receiver and transmitter (also interrupts)
//  UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0) /*| _BV(UDRIE0)*/;
/* Set frame format: 8data, 1stop bit */
//  UCSR0C = (3<<UCSZ00);
//set tranceiver
//  RECEIVE;
//  DIRDIR  |= _BV(DIRBIT); //set enable as output
}

void enable_rx_rs485()
{
  UCSR0B |= _BV(RXEN0)  | _BV(RXCIE0); //enable uart rx
  RECEIVE;
}

void send_rs485()
{ rpos = 0;
//set RS485 tranceiver in send mode
  TRANSMIT;
//disable rx interrupt
  UCSR0B &= ~(_BV(RXCIE0) | _BV(RXEN0));
//enable tx interrupt, will immediately generate int
  UCSR0B |= _BV(UDRIE0);
//kick off transmission
//  UDR0 = ((char*)&msg)[rpos++];//not necessary, will start by itself
  rs485_timeout = sizeof(msg)/8; //just a precaution, transmit should not timeout, timeout is approx. 110% of expected time
}

ISR(USART_RX_vect)
{ 
  SETPIN12;
#ifdef ALLOW_NESTING
  MASK_TIMER_INT();
  MASK_EXTENSION_INT();
  MASK_DISTANCE_INT();
  MASK_IR_INT();
  //MASK_EEPROM_INT();
  sei(); 
#endif
  register char *wp asm("r30") = wposp;
  register char data asm("r1");
  do
  { data = UDR0;
    rs485_timeout = 2;//set a timeout of 100-200us equiv. to 10-20 bytes
    switch (state)
    { case 0: //idle
             if (data == 0x02) 
               state = 1;
             else if (data == 0xA0)//this is really a hack, it avoids timeouts in case of a bad start
               state = 5;
             break;
      case 1: //stx
             if (data == 0x55) 
               state = 2;
             else
               state = 0;
             break;
      case 2://length H, high byte comes first
             msg.hdr.bytesL = data;
             state = 3;
             break;
      case 3://length L, low byte
             msg.hdr.bytesH = data;
             if (msg.hdr.bytes > sizeof(msg)-7)
               state = 0; //message structure cannot accomodate message this size
             else
               state = 4;
             break;
      case 4://store
             *wp++ = data;
             if (wp >= ((char*)&msg.hdr.snd + sizeof(trailer)) + msg.hdr.bytes
                 && wp <= (char*)&msg + sizeof(message) + 1
                )
             { //message complete
               wp = (char*)&msg.hdr.snd;
               rs485_timeout = 0;
               //tx_message = find_ad(msg.hdr.rec) > 0;
               tx_message = msg.hdr.rec - 3;
               if (tx_message >= 0)
               { UCSR0B &= ~(_BV(RXCIE0) | _BV(RXEN0)); //disable rec to avoid corruption by new messages
               }
               state = 0;
             }
             break;
      case 5://wrong start
             if (data == 0x15)//after a wrong start A0 i.o. 02, the 55 gets read as 15
             { msg.hdr.bytesL = 0;
               state = 3;
             }
             else
               state = 0;
      default:
             break;
    }
  } while (UCSR0A & _BV(RXC0)); //see if another char is available, now it is fast enough so this is normally not the case
  wposp = wp;
#ifdef ALLOW_NESTING
  cli();
  UNMASK_TIMER_INT();
  UNMASK_EXTENSION_INT();
  UNMASK_DISTANCE_INT();
  UNMASK_IR_INT();
  //UNMASK_EEPROM_INT();
#endif
  CLRPIN12;
}


ISR(USART_UDRE_vect)
{ SETPIN12;
  if (rpos > BYTES()+7)
  { //last byte was sent
    RECEIVE;
    UCSR0B &= ~_BV(UDRIE0); //disable tx int
    UCSR0B |= _BV(RXCIE0) | _BV(RXEN0); //re-enable rx int
    rs485_timeout = 0;
  }
  else//send 1 byte too many in order to detect that the etx char was sent
    UDR0 = ((char*)&msg)[rpos++];
  CLRPIN12;
}

void timeout_rs485()
{ SETPIN12;
  //reset receiver
  wposp = (char*)&msg.hdr.snd;
  state = 0;
  //reset transmitter
  rpos = 0;
  RECEIVE;
  UCSR0B &= ~_BV(UDRIE0); //disable tx int
  UCSR0B |= _BV(RXCIE0) | _BV(RXEN0); //re-enable rx int
  CLRPIN12;
}
#endif