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

Dependencies:   mbed ConfigFile

rs485.cpp

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

File content as of revision 0:7f26f0680202:

#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;
}