Program the control the fischertechnik robo interface or intelligent interface via tcp socket or via a java gui.
Diff: rs485.cpp
- Revision:
- 0:7f26f0680202
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rs485.cpp Fri Dec 31 14:01:14 2010 +0000 @@ -0,0 +1,187 @@ +#include "mbed.h" +#include "data.h" + +#define TXMODE true /* level of eg. MAX485 input to switch to transmit mode */ +#define RXMODE (!TXMODE) + +class rs485: public Serial, DigitalOut { //since communication is half duplex we use only one buffer for both reading and writing + char *buffer; + int index, length; //index is the buffer pointer, length is the length of the buffer + //bool receiving; + bool _done; + virtual void rx() { //ISR that stashes bytes until the buffer is full and then disables itself + //if (!receiving)return; + if (index<length) + buffer[index++] = getc(); + else { + //receiving = false; + attach(0); + _done = true; + } + } + virtual void tx() { //ISR that sends out the entire buffer and then switches to receive mode + if (index<length) + putc(buffer[index++]); + else { + DigitalOut::write(RXMODE); + attach(this,&rs485::rx, RxIrq); + _done = true; + } + } +public: + enum mode_t { rec, trans}; + rs485(PinName out, PinName in, PinName dir): Serial(out, in), DigitalOut(dir) { + //attach(this, rx, RxIrq); + attach(this, &rs485::tx, TxIrq); + DigitalOut::write(RXMODE); + buffer = 0; + length = 0; + //receiving = false; + } + //void init(int br) {} + void send(char *buf, int len) { + DigitalOut::write(TXMODE); + buffer = buf; + length = len; + putc(*buffer); + index = 1; + } + void receive(char *buf, int len) { + buffer = buf; + length = len; + //receiving = true; + attach(this,&rs485::rx, RxIrq); + } + bool done() { + bool tmp = _done; + _done=false; + return tmp; + } + void setmode(enum mode_t m) { + if (m==rec) + DigitalOut::write(RXMODE); + else + DigitalOut::write(TXMODE); + } +}; + + +//class specialized for use with the fischertechnik TXC +class TXC_rs485: public rs485 { + message *msg; //pointer to a TXC message buffer + char *wp; //pointer where the receiver will write the data + int rpos; //index where the transmitter will read the data + virtual void rx(); //ISR + virtual void tx(); //ISR + char state; //receiver state + int rs485_timeout; // a timeout period, intended to reset the receiver when interrupts stop before the end of a message + int tx_message; //the destination of a received message, i.e. the slave address +public: + TXC_rs485(PinName out, PinName in, PinName dir): rs485(out, in, dir) { + baud(921600); + } + void receive(message *m) { + state = 0; + msg = m; + wp = (char*)&msg->hdr.snd; + } + void send(message *m) { +#if 1 + rs485::send((char*)m, BYTES(msg)+7);//use base class for transmission +#else + rpos = 0; + msg = m; +//set RS485 tranceiver in send mode + setmode(trans); +//disable rx interrupt + attach(0); +//enable tx interrupt, will immediately generate int + attach(this, &TXC_rs485::tx, TxIrq); +//kick off transmission +// putc((char*)msg)[rpos++];//not necessary, will start by itself + rs485_timeout = sizeof(message)/8; //just a precaution, transmit should not timeout, timeout is approx. 110% of expected time +#endif + } + + int Slave(bool clear=false) {//return the destination of the received packet, functions also as reception complete flag, is <0 when not yet available + int tmp = tx_message; + if (clear) + tx_message = -3; + return tmp; + } + void timeout(); +}; + +void TXC_rs485::rx() { +// SETPIN12; + char data; + do { + data = getc(); + rs485_timeout = 2;//set a timeout of 100-200us equiv. to 10-20 bytes + switch (state) { + case 0: //idle + if (data == 0x02)//stx + state = 1; + 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; + //length = (unsigned)data<<8; + state = 3; + break; + case 3://length L, low byte + msg->hdr.bytesH = data; + //length += 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;//ready for next message to receive + rs485_timeout = 0; + tx_message = msg->hdr.rec - 3;//slave address tx_message==0 means Ext.1 etc + if (tx_message >= 0) { + attach(0); //disable rec to avoid corruption by new messages + } + state = 0; + } + break; + default: + break; + } + } while (readable()); //see if another char is available, now it is fast enough so this is normally not the case +// CLRPIN12; +} + +void TXC_rs485::tx() {// SETPIN12; + if (rpos > BYTES(msg)+7) { //last byte was sent + attach(0, TxIrq); //disable tx int + attach(this,&TXC_rs485::rx, RxIrq); //re-enable rx int + rs485_timeout = 0; + } else//send 1 byte too many in order to detect that the etx char was sent + putc(((char*)msg)[rpos++]); +// CLRPIN12; +} + +void TXC_rs485::timeout() { + //SETPIN12; + //reset receiver + wp = (char*)&msg->hdr.snd; + state = 0; + //reset transmitter + rpos = 0; + setmode(rec); + attach(0, TxIrq); //disable tx int + attach(this,&TXC_rs485::rx, RxIrq); //re-enable rx int + //CLRPIN12; +}