Lab3 - TSLite Phase III: SLIP Project

Phase III - Simple Software Development - SLIP Project


- To implement TSLite Phase III successfully first you need to complete TSLite Phase II (Two way communication between host (Win XP) and target (TSLite)).


A. SLIP Project Overview

  • In Phase II "Two way communication", it is already proved that UPS supports SLIP. Unfortunately, UPS does not provide SLIP source code, which is hard for us to debug. This issue is resolved by introducing our own SLIP implementation.

  • Similar to Phase II, UPS2 (server side) and WinUPS (client side) will be used. However, the code will not be directly used; instead, our own SLIP code will be integrated with both UPS2 and WinUPS.


B. Set up TCP/IP Lean Software


- Copy all the files of the CD which comes with the book "TCP/IP Lean, Second Edition" to C:\embed_net\tslite\tcp_ip_lean



- Back up these two directories

C:\embed_net\tslite\tcp_ip_lean\vc6

C:\embed_net\tslite\tcp_ip_lean\tcp_ip_lean\source




- Also back up your projects folder on which you worked in your last project TSLite Phase II.


C. Preparing a new workspace for Phase III


- Now open your projects workspace which you created in previous project phase III.


- Add the following projects to the projects workspace:

  • \course\embed_net\tcp_ip_lean\vc6\arpscan.dsp   

  • \course\embed_net\tcp_ip_lean\vc6\netmon.dsp  

  • \course\embed_net\tcp_ip_lean\vc6\router.dsp    

  • \course\embed_net\tcp_ip_lean\vc6\telnet.dsp   

  • \course\embed_net\tcp_ip_lean\vc6\webrom.dsp

  • \course\embed_net\tcp_ip_lean\vc6\datagram.dsp  

  • \course\embed_net\tcp_ip_lean\vc6\ping.dsp    

  • \course\embed_net\tcp_ip_lean\vc6\scratchp.dsp  

  • \course\embed_net\tcp_ip_lean\vc6\web_egi.dsp  

  • \course\embed_net\tcp_ip_lean\vc6\webserve.dsp


You can find those projects from folders which you copied from CD [In folder source and vc6 in tcp_ip_lean folder].








Strategy of integrating SLIP and UPS2/Winups
  1. Approaches to integrate SLIP with UPS' infrastructure

There are two approaches to integrate SLIP with UPS' infrastructure:

    • Approach 1:

Don't change ups2 and winups projects dratiscally. Only modify the serial-port-handling methods in ups2 and winups by integrating TCPLean's SLIP code.

    • Approach 2:

Only keep ups2 and winups projects' lower-level code, and modify the serial-port-handling methods in ups2 and winups by integrating TCPLean's SLIP code.


- I decided to use the first Approach.

  1. Options to use SLIP protocol

There are three options for the first approach:

    • Option 1:

Only encode the data to be read and written in ups2 and winups with SLIP frame format.

    • Option 2:

Not only encode the data to be read and written in ups2 and winups with SLIP frame format, but also need to use SLIP protocol.


Originally, I thought Option 2 is the right approach, but after studying "RFC 1055: A NONSTAND ARD FOR TRANSMISSION OF IP DATAGRAMS OVER SERIAL LINES: SLIP" I found SLIP protocol is very simple, thus, Option 1 and 2 are similar.

  1. Implementation of SLIP protocol

Options of sample code

There are two approaches to implement SLIP protocol

      • Approach 1:

Leverage TCPLean's code

      • Approach 2:

Leverage the code described in "RFC 1055: A NONSTANDARD FOR TRANSMISSION OF IP DATAGRAMS OVER SERIAL LINES: SLIP" (local copy)


First I use Approach 1, but later I changed mind to use Approach 2 because

      • TCPLean's SLIP code is not as isolated as Approach 2. This conclusion is based on the analysis described in the section Mapping of UPS2/Winups to SLIP_server/Winups.

      • There are a lot of compile errors need to resolve for Approach 1.

D. To create SLIP server

- Leverage the UPS2 project

  1. Open Cygwin window in your guest OS Win XP and go to the following directory.

$ cd C:/embed_net/tslite/projects



  1. In projects folder, copy all the contents of directory ups2 into SLIP.

$ cp -R ups2 SLIP

Go into the SLIP directory

$ cd SLIP

  1. Rename the directory “ups2” to “SLIP_server”

$ mv ups2 SLIP_server


  1. cd SLIP_server
  2. rm UPS2*
  1. Activate an empty VC++ 6.0
  2. Click New ETS Project in the Embedded StudioExpress toolbar

  1. Enter these parameters in the "ETS Project Wizard - Step 1" window

Workspace Name: SLIP_server

Workspace Base Directory:

C:\embed_net\tslite\projects\SLIP\SLIP_server

Linker Command File: (*) Create New File



  1. Check these parameters in the "ETS Project Wizard - Step 2 of 3" window

[x] PC-Compatible Screen Driver

[x] PC-Compatible Keyboard Driver





  1. Create a new folder SLIP_server in the project.



- Add the following files in the directory [C:\embed_net\tslite\projects\SLIP\SLIP_server] to the folder


CMDRECV.C  MESSAGE.C  UPS.C     UPSDATA.C      

Debug      SERIAL.C   UPS.H     UPSDATA.H     

EVENT.C    TIMER.C    UPSALL.H







  1. Create a new folder SLIP in the project.


- And add the following files in the directory [C: \embed_net\tslite\projects\SLIP] to the folder.


UPSIFACE.H  X86PACK.C  X86PACK.H



  1. Create a new folder utils in the project and add the following files in the directory [C:\embed_net\tslite\projects\utils] to the folder.

SPEAKER.C



  1. Modify SLIP_sevr.lnk to comment out

! PC-Compatible Screen Driver

! Comment out by Henry

! @pcat_sc.emb


! PC-Compatible Keyboard Driver

! Comment out by Henry

! @pcat_kb.emb


  1. Right click SLIP_server project and change the settings Project Options

Old:

  /nologo /MLd /W3 /Z7 /Od /D "WIN32" /D "_DEBUG" /FR"Debug/"

  /Fo"Debug/" /Fd"Debug/" /FD /c

New:

  /nologo /MT /Z7 /Od /D "WIN32" /D "_DEBUG" /FR"Debug/"

  /Fo"Debug/" /Fd"Debug/" /FD /c




  1. Rebuild the project from menu [Build Build SLIP_server.exe]. The project should be built successfully.



E. Create Server SLIP code

Approach 1: Leverage TCPLean's code for SLIP server.


Approach 2: Leverage from RFC 1055's code for SLIP server


I am going to use Approach 2. [Reference: "RFC 1055: A NONSTAND ARD FOR TRANSMISSION OF IP DATAGRAMS OVER SERIAL LINES: SLIP" (local copy)]


1. Create the following file in [C:\embed_net\tslite\projects\SLIP\rfc1055_SLIP.c], whose content is shown in APPENDIX - A in this document.


2. Then add this file rfc1055_SLIP.c under SLIP folder of your SLIP_server project as shown in the following snapshot.



F. Use winups as SLIP client
  • Leverage the original winups project
    1. cd C:/embed_net/tslite/projects/SLIP
    2. cp -R ../ups2/winups .


      1. Then, add this copied project winups.dsp from SLIP folder into current workspace SLIP_server.dsw in Visual C++. Compile this winups project from menu Build Build winups.exe. The compilation should be successful.




    G. Create SLIP client code

    Approach 1: Leverage TCP Lean's code for winups
    Approach 2: Leverage from RFC1055's code for winups

    I am using Approach 2, because winups uses C++ code, the RFC 1055's code will be integrated into winups' upsser.cpp directly instead of creating separate C or C++ code.


    - Integrate RFC 1055's SLIP code with winups code

    APPENDIX - A

    #ifdef SLIP_SERVER

    #ifdef SLIP_SERVER
    #include <hw386.h> // For the definition of BOOL
    #include <pcatdefs.h>
    #include <pcio.h>
    #endif // SLIP_SERVER

    /* SLIP special character codes
    */
    #define END             0300    /* indicates end of packet */
    #define ESC             0333    /* indicates byte stuffing */
    #define ESC_END         0334    /* ESC ESC_END means END data byte */
    #define ESC_ESC         0335    /* ESC ESC_ESC means ESC data byte */

    //
    // Writes characters to the serial port.  If fWait is
    // TRUE, will wait for sufficient buffer space.  If fWait
    // is FALSE, will write as many characters as possible to
    // the buffer and then return immediately.
    //
    // This function is non-reentrant; it may only be called
    // by one thread in the system.
    //
    // Returns: nChar      if success
    //          otherwise  number of chars written
    //
    // DWORD send_char(char *pBuf, DWORD nChar, BOOL fWait)
    unsigned long  send_char(char c, unsigned long  nChar, BOOL fWait)
    {
      char pBuf[1];
      pBuf[0]=c;

      return SerialWrite(pBuf, nChar, fWait);
    }


    #ifdef SLIP_SERVER_SEND
    /* SEND_PACKET: sends a packet of length "len", starting at
    * location "p".
    */
    #ifdef SLIP_SERVER_SEND
    // Returns: len      if success
    //          otherwise  number of chars written
    unsigned long send_packet(char* p, int len, BOOL fWait)
    #else
    void send_packet(char* p, int len)
    #endif // SLIP_SERVER_SEND
    {
    #ifdef SLIP_SERVER_SEND
      unsigned long nChar=0;
      unsigned char c;
    #endif // SLIP_SERVER_SEND

     /* send an initial END character to flush out any data that may
      * have accumulated in the receiver due to line noise
      */
    #ifdef SLIP_SERVER_SEND
        send_char(END, 1, fWait);
    #else
        send_char(END);
    #endif // SLIP_SERVER_SEND

     /* for each byte in the packet, send the appropriate character
      * sequence
      */
     while(len--) {

    #ifdef SLIP_SERVER_SEND
       c=(unsigned char)(*p);
        switch(c) {
    #else
        switch(*p) {
    #endif  // SLIP_SERVER_SEND
        /* if it's the same code as an END character, we send a
         * special two character code so as not to make the
         * receiver think we sent an END
         */
        case END:
    #ifdef SLIP_SERVER_SEND
                nChar += send_char(ESC, 1, fWait);
                nChar += send_char(ESC_END, 1, fWait);
    #else
                send_char(ESC);
                send_char(ESC_END);
    #endif // SLIP_SERVER_SEND
                break;

        /* if it's the same code as an ESC character,
         * we send a special two character code so as not
         * to make the receiver think we sent an ESC
         */
        case ESC:
    #ifdef SLIP_SERVER_SEND
                nChar += send_char(ESC, 1, fWait);
                nChar += send_char(ESC_ESC, 1, fWait);
    #else
                send_char(ESC);
                send_char(ESC_ESC);
    #endif // SLIP_SERVER_SEND
                break;
        /* otherwise, we just send the character
         */
        default:
    #ifdef SLIP_SERVER_SEND
                nChar += send_char(*p, 1, fWait);
    #else
                send_char(*p);
    #endif // SLIP_SERVER_SEND
        }

        p++;
     }

     /* tell the receiver that we're done sending the packet
     */
    #ifdef SLIP_SERVER_SEND
     nChar += send_char(END, 1, fWait);

     return nChar;
    #else
     send_char(END);
    #endif // SLIP_SERVER_SEND
    }
    #endif  // SLIP_SERVER_SEND

    ///////////////////////////////////////////////////////////////////

    #ifdef SLIP_SERVER_RECV
    //
    // Reads characters from the serial port.  If fWait is
    // TRUE, will wait for the requested number of characters
    // to be received before returning.  If fWait is FALSE, will
    // return immediately with an error if there are less than
    // the requested number of characters available.
    //
    // This function is non-reentrant; it may only be called
    // by one thread in the system.
    //
    // Returns: nChar if success
    //          if error, number of available characters
    //
    // DWORD recv_char(char *pBuf, DWORD nChar, BOOL fWait)
    unsigned long recv_char(char *pBuf, unsigned long nChar, BOOL fWait)
    {
      return SerialRead(pBuf, nChar, fWait);
    }


    /* RECV_PACKET: receives a packet into the buffer located at "p".
    *      If more than len bytes are received, the packet will
    *      be truncated.
    *      Returns the number of bytes stored in the buffer.
    */
    #ifdef SLIP_SERVER_RECV
    // Returns: len if success
    //          if error, number of available characters
    unsigned long  recv_packet(char *p, int len, BOOL fWait)
    #else
    void recv_packet(char *p, int len)
    #endif
    {
    #ifdef SLIP_SERVER_RECV
      unsigned long nChar=0;
      unsigned char* q, *r;
      unsigned char c;
    #else
      char c;
    #endif // SLIP_SERVER_RECV
      int received = 0;

    #ifdef SLIP_SERVER_RECV
       r = (char*)malloc(len);
       nChar=SerialRead(r, len, fWait);
      // display(r, len);
      if (nChar != len)
         return nChar;
      else {
         nChar=0;
         q=r;
      }
    #endif // SLIP_SERVER_RECV
      /* sit in a loop reading bytes until we put together
       * a whole packet.
       * Make sure not to copy them into the packet if we
       * run out of room.
       */
      while(1)
      {
          /* get a character to process
           */
    #ifdef SLIP_SERVER_RECV
         //nChar += recv_char(&c, 1, fWait);
         c=(unsigned char)(*q++);
         nChar++;
    #else
          c = recv_char();
    #endif // SLIP_SERVER_RECV

          /* handle bytestuffing if necessary
           */
          switch(c) {

          /* if it's an END character then we're done with
           * the packet
           */
          case END:
             /* a minor optimization: if there is no
             * data in the packet, ignore it. This is
             * meant to avoid bothering IP with all
             * the empty packets generated by the
             * duplicate END characters which are in
             * turn sent to try to detect line noise.
             */
           if(received) {
             free(r);
                return received;
           }
             else
                break;

          /* if it's the same code as an ESC character, wait
           * and get another character and then figure out
           * what to store in the packet based on that.
           */
          case ESC:
    #ifdef SLIP_SERVER_RECV
         //nChar += recv_char(&c, 1, fWait);
         c=(unsigned char)(*q++);
         nChar++;
    #else
         c = recv_char();
    #endif // SLIP_SERVER_RECV

             /* if "c" is not one of these two, then we
             * have a protocol violation.  The best bet
             * seems to be to leave the byte alone and
             * just stuff it into the packet
             */
             switch(c) {
             case ESC_END:
                c = END;
                break;
             case ESC_ESC:
                c = ESC;
                break;
             }

          /* here we fall into the default handler and let
           * it store the character for us
           */
          default:
             if (received < len)
                 p[received++] = c;
          }
      }
    #ifdef SLIP_SERVER_RECV
     return nChar;
    #else
     send_char(END);
    #endif // SLIP_SERVER_RECV
    }

    #endif // SLIP_SERVER_RECV
    #endif // SLIP_SERVER


Comments