view network/network.c @ 107:56d09a0969b5 avr-http

Import uIP and the PPP implementation from https://code.google.com/p/avrusbmodem/
author Matt Johnston <matt@ucc.asn.au>
date Fri, 07 Sep 2012 23:53:53 +0800
parents
children
line wrap: on
line source

#define  INCLUDE_FROM_NETWORK_C
#include "network.h"

static bool Escape = false;
static uint8_t PacketState = PACKET_STATE_NULL;
static uint16_t PacketProtocol = 0;
static uint16_t PacketLength = 0;
static uint16_t CurrentChecksum, OneBackChecksum, TwoBackChecksum;


// Framed packet looks like:
// Framing:     0x7e
// Address:     0xff
// Control:     0x03
// Protocol:    0xnn 0xnn
// Information: 0xnn 0xnn 0xnn 0xnn ...
// Checksum:    0xnn 0xnn
// Framing:     0x7e
//
// If Address-and-Control-Field-Compression is switched on then the remote end is allowed to leave out the 0xff 0x03 in the header
// If Protocol-Field-Compression is switched on and the protocol < 0x00ff then the remote end is allowed to leave out the initial 0x00 in the protocol field. 
// We can check for Protocol-Field-Compression by seeing if the first byte of the protocol is odd (the first byte of a full two-byte protocol value must be even).

uint16_t network_read(void)
{
	RingBuff_Elements_t c;
	
	while (Modem_ReceiveBuffer.Elements)
	{
		c = Buffer_GetElement(&Modem_ReceiveBuffer);

		switch (PacketState)
		{
			case PACKET_STATE_NULL:
				if (c == 0x7e)												// New Packet
				{
					PacketState = PACKET_STATE_INHEADER;					// We're now in the header
					PacketLength = 0;
					CurrentChecksum = 0xffff;								// Start new checksum
				}
			break;

			case PACKET_STATE_INHEADER:
				if (c == 0x7d)												// Escaped character. Set flag and process next time around
				{
					Escape = true;
					continue;
				}
				else if (Escape)											// Escaped character. Process now.
				{
					Escape = false;
					c = (c ^ 0x20);
				}
				
				if (PacketLength == 1 && c != 0xff)							// Should be 0xff. If not then Address-and-Control-Field-Compression is switched on
				{
					PacketLength += 2;										// Adjust the length as if the 0xff 0x03 was there
				}		

				if (PacketLength == 3)
				{
					if (c & 1)												// Should be even. If it's odd then Protocol-Field-Compression is switched on
					{
						PacketProtocol = 0x00;								// Add in the initial 0x00
						PacketLength++;										// Adjust the length as if the 0x00 was there
					}
					else
						PacketProtocol = c * 256;							// Store the MSB of the protocol
				}

				if (PacketLength == 4)										// End of header
				{														
					PacketProtocol |= c;									// Store the LSB of the protocol
					PacketLength = -1;										// This will be incremented to 0 at the end of this loop
					Escape = false;
					PacketState = PACKET_STATE_INBODY;						// We're now in the body
				}

				CurrentChecksum = CALC_CRC16(CurrentChecksum, c);			// Calculate checksum
			break;

			case PACKET_STATE_INBODY:
				if (c == 0x7e)												// End of packet
				{
					uip_len = PacketLength - 2;								// Strip off the checksum and framing
					Escape = false;
					PacketState = PACKET_STATE_NULL;						// Back to waiting for a header

					Debug_Print("\r\nReceive ");
					DumpPacket();

					if (~TwoBackChecksum == (*(uip_buf + PacketLength - 1) * 256 + *(uip_buf + PacketLength - 2)))
						return PacketProtocol;
					else
						Debug_Print("Bad CRC\r\n");
				}
				else
				{	
					if (c == 0x7d)											// Escaped character. Set flag and process next time around
					{
						Escape = true;
						continue;
					}
					else if (Escape)										// Escaped character. Process now.
					{
						Escape = false;
						c = (c ^ 0x20);
					}
					
					*(uip_buf + PacketLength) = c;							// Store the character in the buffer

					TwoBackChecksum = OneBackChecksum;						// Keep a rolling count of the last 3 checksums
					OneBackChecksum = CurrentChecksum;						// Eventually we need to see if the checksum is valid
					CurrentChecksum = CALC_CRC16(CurrentChecksum, c);		// and we need the one two back (as the current one includes the checksum itself)
				}
			break;
		}
		
		PacketLength++;														// Increment the length of the received packet
	}

	return 0;																// No data or packet not complete yet 
}

void network_send(uint16_t protocol)
{
	unsigned int checksum = 0xffff;
	
	PacketProtocol = protocol;
	PacketState = PACKET_STATE_NULL;
	
	Debug_Print("\r\nSend ");
	DumpPacket();
	
	// Send out the packet with HDLC-like framing  - see http://tools.ietf.org/html/rfc1662
	
	// Start with the framing flag
	Buffer_StoreElement(&Modem_SendBuffer, 0x7e);

	// Address	
	Buffer_StoreElement(&Modem_SendBuffer, 0xff);
	checksum = CALC_CRC16(checksum, 0xff);

	// Control
	Buffer_StoreElement(&Modem_SendBuffer, 0x03);
	checksum = CALC_CRC16(checksum, 0x03);

	// Protocol
	Buffer_StoreElement(&Modem_SendBuffer, protocol / 256);
	checksum = CALC_CRC16(checksum, protocol / 256);

	Buffer_StoreElement(&Modem_SendBuffer, protocol & 255);
	checksum = CALC_CRC16(checksum, protocol & 255);

	// Add the information, escaping it as necessary
	for (uint16_t i = 0; i < uip_len; i++)
	{
		if (*(uip_buf + i) < 0x20 || *(uip_buf + i) == 0x7d || *(uip_buf + i) == 0x7e)
		{
			Buffer_StoreElement(&Modem_SendBuffer, 0x7d);
			Buffer_StoreElement(&Modem_SendBuffer, *(uip_buf + i) ^ 0x20);
		}
		else
		{
			Buffer_StoreElement(&Modem_SendBuffer, *(uip_buf + i));
		}

		checksum = CALC_CRC16(checksum, *(uip_buf + i));
	
		if (Modem_SendBuffer.Elements == BUFF_STATICSIZE)    			// Periodically flush the buffer to the modem
			USBManagement_SendReceivePipes();
	}

	// Add the checksum to the end of the packet, escaping it as necessary
	checksum = ~checksum;

	if ((checksum & 255) < 0x20 || (checksum & 255) == 0x7d || (checksum & 255) == 0x7e)
	{
		Buffer_StoreElement(&Modem_SendBuffer, 0x7d);
		Buffer_StoreElement(&Modem_SendBuffer, (checksum & 255) ^ 0x20);
	}
   	else
	{
		Buffer_StoreElement(&Modem_SendBuffer, checksum & 255);			// Insert checksum MSB
	}
	
	if ((checksum / 256) < 0x20 || (checksum / 256) == 0x7d || (checksum / 256) == 0x7e)
	{
		Buffer_StoreElement(&Modem_SendBuffer, 0x7d);
		Buffer_StoreElement(&Modem_SendBuffer, (checksum / 256) ^ 0x20);
	}
	else
	{
		Buffer_StoreElement(&Modem_SendBuffer, checksum / 256);			// Insert checksum LSB
	}
   
	Buffer_StoreElement(&Modem_SendBuffer, 0x7e);						// Framing

	uip_len = 0;

	USBManagement_SendReceivePipes();									// Flush the rest of the buffer
}

void network_init(void)
{
	//Initialise the device
	PacketState = PACKET_STATE_NULL;
	Escape = false;
	uip_len = 0;
}

void DumpPacket(void)
{
	int i, j;

	if (!DebugModeEnabled)
		return;

	Debug_Print("(Protocol = 0x");
	Debug_PrintHex(PacketProtocol  / 256); Debug_PrintHex(PacketProtocol  & 255);
	Debug_Print("):\r\n");
	
	for (i = 0; i < uip_len; i += 16)
	{	
		Debug_PrintHex(i / 256); Debug_PrintHex(i & 255); Debug_Print(": ");

		for (j = 0; j < 16; j++)
		{
			if ((i + j) >= uip_len)
				break;

			Debug_PrintHex(*(uip_buf + i + j));
			Debug_PrintChar(' ');
		}
		
		Debug_Print("\r\n      ");
		
		for (j = 0; j < 16; j++)
		{
			if ((i + j) >= uip_len)
				break;

			if (*(uip_buf + i + j) >= 0x20 && *(uip_buf + i + j) <= 0x7e)
			{
				Debug_PrintChar(' ');
				Debug_PrintChar(*(uip_buf + i + j));
				Debug_PrintChar(' ');
			}
			else
				Debug_Print(" . ");

		}

		Debug_Print("\r\n");
	}
}