I was planning on implementing TCP next but instead I decided that it would be more useful to start breaking up this application into separate files and deciding on how it will work. Below is what I would like the main C code to be like.

IPstackInit(&bytMacAddress[0]);
IPstackHTMLPost(url,data);
while(1) IPstackIdle();

From this it is pretty obvious what is happening. First the IP stack is initialised with the MAC address and then we post data to a url. After doing this we have the stack idle so that it can answer pings and arps. The IP stack initialisation sequence is not anything new.

int IPstackInit( unsigned char const* MacAddress)
{
  initMAC();
  // Announce we are here
  PrepArp();
  MACWrite();
  // Just waste a bit of time confirming no one has our IP
  for(unsigned int i = 0; i < 0xffff; i++)   
  {     
    if(MACRead())     
    {       
      EtherNetII* eth = (EtherNetII*)&uip_buf;       
      if( eth->type == HTONS(ARPPACKET) )
      {
        ARP* arp = (ARP*)&uip_buf;
        if( !memcmp(&arp->senderIP[0],&bytIPAddress[0],4))
        {
          // Uh oh this IP address is already in use
          return 0;
        }
      }
    }
    // Every now and then send out another ARP
    if( i % 0xfff )
    {
      PrepArp();
      MACWrite();
    }
  }
  // Well no one replied so its safe to assume IP address is OK
  return 1;
}

Its quite easy to see what is happening here first initialise the enc28j60 then send out an arp with our ip address.  If a reply happens for that ip address then it must be taken and we have a problem so return 0 for error. Every couple times through the loop send out an arp just to double check there is no ip address conflict. After this we should send an arp out for the router mac address but that has not been added in just yet.

In the future I would like to change the init so that it uses DHCP to receive a dynamic ip address, router ip and dns ip.

I will leave the explanation on how the second function will work for now and will show how the idle function is being implemented.

int IPstackIdle()
{
  GetPacket(0);
  return 1;
}

Nothing complex it just gets a packet and always returns true. Only one more part to show now the GetPacket function. I decided earlier on that I would need some sort of function that could get packets but if the packet was an ARP or Ping replied immediately this is the reasoning behind GetPacket. If the packet is not either ping arp or the protocol specified in the parameter then it disregards the packet.

int GetPacket( int protocol )
{
  while(1)//Should make this return 0 after so many failed packets
  {
    if ( MACRead() )
    {
      EtherNetII* eth = (EtherNetII*)&uip_buf[0];
      if ( eth->type == HTONS(ARPPACKET) )
      {
        //We have an arp and we should reply
        ReplyArp();
      }
      else if( eth->type == HTONS(IPPACKET) )
      {
        //We have an IP packet and we need to check protocol.
        IPhdr* ip = (IPhdr*)&uip_buf[0];
        if( ip->protocol == protocol )
        {
          return 1;
        }

        //Reply to any Pings
        if( ip->protocol == ICMPPROTOCOL )
        {
          PingReply();
        }
      }
    }
  }
}

There shouldn’t be anything that revolutionary in this. In the future this function should be changed so that the while(1) is changed to some sort of timer as we do not want to get into an infinite loop due to one or two lost packets. The ip stack is now started to take some shape and the tcp implementation can be worked on.

Advertisements