RealtimeCompLab2

Dependencies:   mbed

Fork of PPP-Blinky by Nicolas Nackel

main.cpp

Committer:
nixnax
Date:
2016-12-30
Revision:
9:0992486d4a30
Parent:
8:48e40f1ff316
Child:
10:74f8233f72c0

File content as of revision 9:0992486d4a30:

#include "mbed.h"

// Proof-of-concept for TCP/IP using Windows 7/8/10 Dial Up Networking over MBED USB Virtual COM Port

// Toggles LED1 every time the PC sends an IP packet over the PPP link

// Note - turn off all authentication, passwords, compression etc. Simplest link possible.

// Handy links
// http://atari.kensclassics.org/wcomlog.htm
// https://technet.microsoft.com/en-us/library/cc957992.aspx
// http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
// https://en.wikibooks.org/wiki/Serial_Programming/IP_Over_Serial_Connections

Serial pc(USBTX, USBRX); // The USB com port - Set this up as a Dial-Up Modem on your pc
Serial xx(PC_10, PC_11); // debug port - use a second USB serial port to monitor

#define debug(x) xx.printf( x )

DigitalOut led1(LED1);

#define FRAME_7E (0x7e)
#define BUFLEN (1<<12)
char rxbuf[BUFLEN];
char frbuf[3000]; // buffer for ppp frame

struct {
    int online; 
    struct {
        char * buf;
        int head; 
        int tail; 
        int total;
    } rx; // serial port buffer
    struct {
        int id;
        int len;
        int crc;
        char * buf;
    } pkt; // ppp buffer
} ppp;

void pppInitStruct(){ ppp.online=0; ppp.rx.buf=rxbuf; ppp.rx.tail=0; ppp.rx.head=0; ppp.rx.total=0; ppp.pkt.buf=frbuf; ppp.pkt.len=0;}

int crcG; // frame check sequence (CRC) holder
void crcDo(int x){for (int i=0;i<8;i++){crcG=((crcG&1)^(x&1))?(crcG>>1)^0x8408:crcG>>1;x>>=1;}} // crc calculator
void crcReset(){crcG=0xffff;} // crc restart
int crcBuf(char * buf, int size){crcReset();for(int i=0;i<size;i++)crcDo(*buf++);return crcG;} // crc on a block of memory

void rxHandler() // serial port receive interrupt handler
{
    ppp.rx.buf[ppp.rx.head]=pc.getc(); // insert in buffer
    __disable_irq();
    ppp.rx.head=(ppp.rx.head+1)&(BUFLEN-1);
    ppp.rx.total++;
    __enable_irq();
}

int pc_readable() // check if buffer has data
{
    return (ppp.rx.head==ppp.rx.tail) ? 0 : 1 ;
}

int pc_getBuf() // get one character from the buffer
{
    if (pc_readable()) {
        int x = ppp.rx.buf[ ppp.rx.tail ];
        ppp.rx.tail=(ppp.rx.tail+1)&(BUFLEN-1);
        return x;
    }
    return -1;
}

void scanForConnectString(); // scan for connect attempts from pc

void processFrame(int start, int end) { // process received frame
    if(start==end) { xx.printf("Null Frame c=%d\n",ppp.rx.total); pc.putc(0x7e); return; }
    crcReset();
    char * dest = ppp.pkt.buf;
    ppp.pkt.len=0;
    int unstuff=0;
    for (int i=start; i<end; i++) {
        if (unstuff==0) {
            if (rxbuf[i]==0x7d) unstuff=1; 
            else { *dest++ = rxbuf[i]; ppp.pkt.len++; crcDo(rxbuf[i]);}
        } else {
            *dest++ = rxbuf[i]^0x20; ppp.pkt.len++; crcDo((int)rxbuf[i]^0x20);
            unstuff=0;
        }
    }
    ppp.pkt.crc = crcG & 0xffff;
    if (ppp.pkt.crc == 0xf0b8) { // check for good CRC
        void determinePacketType(); // declare early
        determinePacketType();
    } else {
         xx.printf("CRC was %x \n",ppp.pkt.crc);
         for(int i=0;i<ppp.pkt.len;i++)xx.printf("%02x ", ppp.pkt.buf[i]);
         xx.printf("\nLen = %d\n", ppp.pkt.len);
    }
}


void generalFrame() {
    debug("== General Frame ==\n");
    for(int i=0;i<ppp.pkt.len;i++) xx.printf("%02x ", ppp.pkt.buf[i]);
    xx.printf(" C %02x %02x L=%d\n", ppp.pkt.crc&0xff, (ppp.pkt.crc>>8)&0xff, ppp.pkt.len);
}    

void sendFrame(){
    int crc = crcBuf(ppp.pkt.buf, ppp.pkt.len-2); // get crc
    ppp.pkt.buf[ ppp.pkt.len-2 ] = (~crc>>0); // fcs lo
    ppp.pkt.buf[ ppp.pkt.len-1 ] = (~crc>>8); // fcs hi
    pc.putc(0x7e); // frame flag
    for(int i=0;i<ppp.pkt.len;i++) {
        unsigned int cc = (unsigned int)ppp.pkt.buf[i];
        if (cc>32) pc.putc(cc); else {pc.putc(0x7d); pc.putc(cc+32);}
    } 
    pc.putc(0x7e); // frame flag
}

void ipRequestHandler(){
    debug("IPCP Conf ");
    if ( ppp.pkt.buf[7] != 4 ) {
        debug("Rej\n"); // reject if any options are requested
        ppp.pkt.buf[4]=4;
        sendFrame();
    } else  {
        debug("Ack\n");
        ppp.pkt.buf[4]=2; // ack the minimum
        sendFrame(); // acknowledge
        // send our own request now
        debug("IPCP Ask\n");
        ppp.pkt.buf[4]=1; // request the minimum
        ppp.pkt.buf[5]++; // next sequence
        sendFrame(); // this is our request
    }
}

void ipAckHandler(){ debug("IPCP Grant\n"); }

void ipNackHandler(){ debug("IPCP Nack\n"); }

void ipDefaultHandler(){ debug("IPCP Other\n"); }

void IPCPframe() {
    led1 = ppp.pkt.buf[5] & 1; // This is the sequence number so the led blinks on packets
    //ppp.pkt.id = ppp.pkt.buf[5]; // remember the sequence number 
    int code = ppp.pkt.buf[4]; // packet type is here
    switch (code) {
        case 1: ipRequestHandler(); break;
        case 2: ipAckHandler(); break;
        case 3: ipNackHandler(); break;
        default: ipDefaultHandler();    
    }
}    

void IPframe() {
    xx.printf("IP frame proto %3d len %4d %d.%d.%d.%d  %d.%d.%d.%d\n", ppp.pkt.buf[13],(ppp.pkt.buf[6]<<8)+ppp.pkt.buf[7],ppp.pkt.buf[16],ppp.pkt.buf[17],ppp.pkt.buf[18],ppp.pkt.buf[19],ppp.pkt.buf[20],ppp.pkt.buf[21],ppp.pkt.buf[22],ppp.pkt.buf[23] );
}    



void LCPconfReq() {
    debug("LCP Conf ");
    if (ppp.pkt.buf[7] != 4) {
        ppp.pkt.buf[4]=4; // allow only minimal requests
        debug("Rej\n");
        sendFrame(); 
    } else {
        ppp.pkt.buf[4]=2; // ack zero conf
        debug("Ack\n");
        sendFrame();
        debug("LCP ask\n");
        ppp.pkt.buf[4]=1; // request zero conf
        sendFrame();
    }
}

void LCPconfAck() {
    debug("LCP Ack\n");
} 

void LCPend(){
     debug("LCP End\n");
     ppp.online=0; 
     ppp.pkt.buf[4]=6;
     sendFrame();
}

void LCPother(){
     debug("LCP Other\n");
     generalFrame();
}

void LCPframe(){
     int code = ppp.pkt.buf[4];
     switch (code) {
         case 1: LCPconfReq(); break;
         case 2: LCPconfAck(); break;
         case 5: LCPend(); break;
         default: LCPother();
     }
}

void xx21frame() {
    debug("Unknown frame type ff 03 xx 21\n");
}

void determinePacketType() {
    if ( ppp.pkt.buf[0] != 0xff ) {debug("byte0 != ff\n"); return;}
    if ( ppp.pkt.buf[1] != 3    ) {debug("byte1 !=  3\n"); return;}
    if ( ppp.pkt.buf[3] != 0x21 ) {debug("byte2 != 21\n"); return;}
    int packetType = ppp.pkt.buf[2];
    switch (packetType) {
        case 0xc0: LCPframe(); break; 
        case 0x80: IPCPframe(); break;
        case 0x00: IPframe(); break;
        default: xx21frame(); break;
    }
}    

void scanForConnectString() {
    if ( ppp.online==0 ) {
        char * clientFound = strstr( rxbuf, "CLIENTCLIENT" ); // look for PC string
        if( clientFound ) { 
            strcpy( clientFound, "FOUND!FOUND!" ); // overwrite so we don't get fixated
            pc.printf("CLIENTSERVER"); // respond to PC
            ppp.online=1; // we can stop looking for the string
            debug("Connect string found\n");
        }
    }
}

int main()
{
    pc.baud(9600);
    xx.baud(115200); 
    xx.puts("\x1b[2J\x1b[HReady\n"); // VT100 code for clear screen & home
    
    pppInitStruct(); // initialize all the PPP properties

    pc.attach(&rxHandler,Serial::RxIrq); // start the receive handler

    int frameStartIndex, frameEndIndex; int frameBusy=0;

    while(1) {
        if ( ppp.online==0 ) scanForConnectString(); // try to connect
        while ( pc_readable() ) {
            int rx = pc_getBuf();
            wait(0.001);
            if (frameBusy) { 
                if (rx==FRAME_7E) {
                    frameBusy=0; // done gathering frame
                    frameEndIndex=ppp.rx.tail-1; // remember where frame ends
                    void processFrame(int start, int end); // process a received frame
                    processFrame(frameStartIndex, frameEndIndex);
                }
            } 
            else {
                if (rx==FRAME_7E) {
                    frameBusy=1; // start gathering frame
                    frameStartIndex=ppp.rx.tail; // remember where frame started
                }
            }
        }
    }
}