RealtimeCompLab2

Dependencies:   mbed

Fork of PPP-Blinky by Nicolas Nackel

main.cpp

Committer:
nixnax
Date:
2016-12-29
Revision:
8:48e40f1ff316
Parent:
7:ab147f5e97ac
Child:
9:0992486d4a30

File content as of revision 8:48e40f1ff316:

#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.

// Nice 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

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

DigitalOut led1(LED1);

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

struct {
    int online; 
    struct {
        char * buf;
        int head; 
        int tail; 
    } 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.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

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);
    __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

int main()
{
    pc.baud(19200);
    xx.baud(115200); 
    xx.puts("\x1b[2J\x1b[H"); // VT100 terminal control code for screen clear/home
    
    pppInitStruct(); // structure containing all the PPP stuff

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

    int frameStartIndex, frameEndIndex;
    int frameBusy=0;

    while(1) {
        while ( pc_readable() ) {
            int rx = pc_getBuf();
            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 starts
                }
            }
        }
        if (ppp.online==0) scanForConnectString(); // try to connect
    }
}

void processFrame(int start, int end) {
    crcReset();
    char * dest = ppp.pkt.buf;
    ppp.pkt.len=0;
    int special=0;
    for (int i=start; i<end; i++) {
        if (special==0) {
            if (rxbuf[i]==0x7d) special=1; 
            else { *dest++ = rxbuf[i]; ppp.pkt.len++; crcDo(rxbuf[i]);}
        } else {
            *dest++ = rxbuf[i]-32; ppp.pkt.len++; crcDo(rxbuf[i]-32);
            special=0;
        }
    }
    ppp.rx.head=0; // reuse rxbuf
    ppp.rx.tail=0; // reuse rxbuf
    ppp.pkt.crc = crcG;
    if (crcG == 0xf0b8) { // check for good CRC
        void determinePacketType(); // declare early
        determinePacketType();
    }
}


void generalFrame() {
    xx.printf("== 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(){
    crcReset(); for(int i=0;i<ppp.pkt.len-2;i++) crcDo(ppp.pkt.buf[i]);
    ppp.pkt.buf[ ppp.pkt.len-2 ] = ((~crcG)>>0); // build crc lo
    ppp.pkt.buf[ ppp.pkt.len-1 ] = ((~crcG)>>8); // build crc hi
    pc.putc(0x7e); // start of frame
    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); // end of frame
}



void LCPrequestFrame() {
    xx.printf("== LCP Request ==\n");
    if (ppp.pkt.buf[7] != 4) {
        ppp.pkt.buf[4]=4; // nack everything until zero len
        sendFrame(); 
    } else {
        ppp.pkt.buf[4]=2; // ack zero conf
        sendFrame();
        // send our config request - also all zeros
        ppp.pkt.buf[4]=1; // request zero conf
        sendFrame();
    }
}

void LCPackFrame() {
    xx.printf("== Saw Ack - PPP is up ==\n");
} 


void ipRequestHandler(){
    xx.printf("== IP Request Frame ==\n");
    generalFrame();
    if ( ppp.pkt.buf[7] != 4 ) {
        ppp.pkt.buf[4]=4; // Nack
        sendFrame();
    } else  {
        ppp.pkt.buf[4]=2; // ack the minimum
        sendFrame(); // acknowledge
        xx.printf("zeroconf ack\n");
        // send our own request now
        ppp.pkt.buf[4]=1; // request the minimum
        ppp.pkt.buf[5]++; // next sequence
        sendFrame(); // this is our request
    }
}

void ipAckHandler(){
    xx.printf("== IP Ack Frame ==\n");
}

void ipNackHandler(){
     xx.printf("== IP Nack Frame ==\n");
}

void ipDefaultHandler(){
     xx.printf("== IP Unknown Frame ==\n");
}

void LCPgeneralFrame(){
     xx.printf("== LCP General Handler ==\n");
     generalFrame();
}


void LCPhandler(){
     int action = ppp.pkt.buf[4];
     if(0);
     else if ( action == 1 ) LCPrequestFrame();
     else if ( action == 2 ) LCPackFrame();
     else LCPgeneralFrame();
}

void IPFrame() {
    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 action = ppp.pkt.buf[4]; // packet type is here
    if(0);
    else if ( action == 1 ) ipRequestHandler();
    else if ( action == 2 ) ipAckHandler();
    else if ( action == 3 ) ipNackHandler();
    else ipDefaultHandler();    
}    

void determinePacketType() {
    static char pktLCPReqType  [] = { 0xff, 3, 0xc0, 0x21  }; // LCP packet
    static char pktIPCPtype    [] = { 0xff, 3, 0x80, 0x21, }; // IP packet

    if(0);
    else if (0==memcmp( ppp.pkt.buf,pktLCPReqType,4)) LCPhandler(); 
    else if (0==memcmp( ppp.pkt.buf,pktIPCPtype,  4)) IPFrame(); 
    else generalFrame(); // default handler
}    

void scanForConnectString(){
    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
    }
}