Lightweight Ethernet

Like a great many of us, I am interested in pushing data to Cosm. This activity only uses Ethernet.begin() and EthernetClient::print yet consumes a whopping 14k of available sketch size and 404 bytes of SRAM. Has anyone rolled their own class which has a lighter footprint? I found Ethernet2 (and have not gotten it to work) but its savings are only modest. I realize that the linker is supposed to remove unused code but so far I've been able to compact OneWire and DallasTemperature FAR beyond what the linker is capable of. Any help is appreciated.

Well after a few very frustrating hours I am right back where I started. Talk about obfuscation! EthernetClient.cpp makes use of a function, rawIPAddress(), that I cannot find anywhere including all the libraries that EthernetClient.h links to! The code pulled straight from EthernetClient.cpp is below. Does anyone know where this chunk of code lives? Google was no help at all sadly.

int EthernetClient::connect(IPAddress ip, uint16_t port) {
  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    uint8_t s = W5100.readSnSR(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {
      _sock = i;
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;

  _srcport++;
  if (_srcport == 0) _srcport = 1024;
  socket(_sock, SnMR::TCP, _srcport, 0);

  if (!::connect(_sock, rawIPAddress(ip), port)) {
    _sock = MAX_SOCK_NUM;
    return 0;
  }

  while (status() != SnSR::ESTABLISHED) {
    delay(1);
    if (status() == SnSR::CLOSED) {
      _sock = MAX_SOCK_NUM;
      return 0;
    }
  }

  return 1;
}

If you are using a w5100 based ethernet shield, you might look at the w5100 chip data sheet for information.

OK, here it is:
rawIPAddress is declared in /hardware/arduino/cores/arduino/Client.h

  uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };

raw_address is declared in /hardware/arduino/cores/arduino/IPAddress.h

    uint8_t* raw_address() { return _address; };

_address is declared in the same file

    uint8_t _address[4];  // IPv4 address

Thanks SurferTim! I'm still struggling mightily though. Before I spend a ton of time, is what I'm attempting to do even feasible? That is, can I cram portions of w5100, socket, and EthernetClient into a single sketch capable of HTTP Puts without dragging the entire contents of those files into my sketch? I'm certainly no expert in C++ and the complexity of what I'm finding in the Ethernet library is daunting.

I think it does good considering what the library does and the limited memory it uses. You might be able to save a little, but I'm not sure it would be worth it. Then you would not be compatible with other example sketches. That is up to you. I opted for a Mega 2560.

one hour ago I was doing the same :slight_smile:
I have ENC28J60 ethernet modules and I am using EtherCard library.
I just want to take some info from my sensor and I was using only the web server.
Since I am using Atmega8 on my breadboard I have only 8k.The sketch size was 9-10k so I opened the .cpp and .h files of the library and I removed the code related to DNS and DHCP and now my sketch is around 6.5 k and is fine.
I dont know what are you doing and what is Cosm but if you don’t need DHCP and DNS just remove those parts of the lib that you are using.
I am a newbie so sorry If my post is not related to your question.

Tonko

Okay, I may actually be getting somewhere… I’ve added a bunch of debug information below as I pick my way through a connection request which should connect to port 80 of cosm.com https://cosm.com/docs/v2/ip_addresses.html. I get as far as the socket connection request which seems to be successful and returns 1. The problem is Status returns 0x13 which is SOCK_INIT according to the W5100 datasheet and nothing more happens. My code gets caught in the While loop waiting for the connection status to progress to ESTABLISHED (0x17).

Incidentally if I am able to get this to work the savings could be massive based on what I’m seeing so far! Can anyone help me spot what is making my socket get stuck at SOCK_INIT?

#include <SPI.h>
#include "w5100.h"
#include <IPAddress.h>

#define MAX_SOCK_NUM 4

W5100Class w5100;

static uint16_t _srcport = 1024;
uint8_t _sock = 4;
uint8_t _address[4];  // IPv4 address
static uint16_t local_port;


void setup()
{
  // This code will only run once, after each powerup or reset of the board
  w5100.init();
  IPAddress cosm = ( 173, 203, 98, 29 );    // This is the current IPv4 address for Cosm.com
  Serial.begin(9600);
  
  // Disable the SD card to prevent w5100 shield weirdness
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  delay(3000);
  int ret;
  ret = connect(cosm,80);
  Serial.print(ret);
}


int connect(IPAddress ip, uint16_t port) {
   Serial.print(MAX_SOCK_NUM);
   Serial.print("\t");
   Serial.println(_sock);
   if (_sock != MAX_SOCK_NUM)
    return 0;

  Serial.println("Got here");
  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    Serial.println("Entered for loop");
    uint8_t s = w5100.readSnSR(i);
    Serial.print(SnSR::CLOSED);
    Serial.print("\t");
    Serial.print(SnSR::FIN_WAIT);
    Serial.print("\t");
    Serial.println(SnSR::CLOSE_WAIT);
    Serial.println(float(s));
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {    // Looking for an available sock maybe?
      _sock = i;    // Sets _sock = to a sock that was Closed, Fin, or Close_Wait
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;
  Serial.println("Made it here because SnSR was CLOSED");
  _srcport++;
  if (_srcport == 0) _srcport = 1024;
  int ret;
  ret = socket(_sock, SnMR::TCP, _srcport, 0);
  Serial.print("Socket open result: ");
  Serial.println(ret);
  
  // Can't get this to work yet :(
  //if (!::connect(_sock, rawIPAddress(ip), port)) {
   // if (!::connect(_sock, *_address, port)) {  // changed to just yield the pointer to _address
   // _sock = MAX_SOCK_NUM;
   // return 0;
  //}

  while (status() != SnSR::ESTABLISHED) {
    Serial.print("Status: ");
    Serial.println(status(),HEX);
    
    delay(1);
    if (status() == SnSR::CLOSED) {
      _sock = MAX_SOCK_NUM;
      return 0;
    }
  }

  return 1;
}

//uint8_t* rawIPAddress(IPAddress& addr) { return addr; };
//uint8_t* raw_address() { return _address; };
//operator uint32_t() { return *((uint32_t*)_address); };


uint8_t status() {
  if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED;
  return w5100.readSnSR(_sock);
}

uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
{
  if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE))
  {
    close(s);
    w5100.writeSnMR(s, protocol | flag);
    if (port != 0) {
      w5100.writeSnPORT(s, port);
    } 
    else {
      local_port++; // if don't set the source port, set local_port number.
      w5100.writeSnPORT(s, local_port);
    }

    w5100.execCmdSn(s, Sock_OPEN);
    
    return 1;
  }

  return 0;
}

void close(SOCKET s)
{
  w5100.execCmdSn(s, Sock_CLOSE);
  w5100.writeSnIR(s, 0xFF);
}



void loop()
{
  // This code will loops consecutively
  
}

I laid some more debugging into my EthernetClient and worked out that indeed the connect that I had previously commented out (because I couldn’t make it work) is the one that ultimately gets called when the socket is created. I’ve tried to get this function call working but no matter what I try I am not able to feed it what it is expecting. I get the follow error message

w5100.ino: In function 'uint8_t connect(SOCKET, uint8_t*, uint16_t)':
w5100:121: error: invalid conversion from 'unsigned char' to 'uint8_t*'
w5100:121: error: initializing argument 2 of 'static uint16_t W5100Class::writeSnDIPR(SOCKET, uint8_t*)'
w5100.ino: In function 'uint8_t* rawIPAddress(IPAddress&)':
w5100:129: error: invalid conversion from 'uint32_t' to 'uint8_t*'

From this code:

#include <SPI.h>
#include "w5100.h"
#include <IPAddress.h>

#define MAX_SOCK_NUM 4
#define DEBUG 1
W5100Class w5100;

static uint16_t _srcport = 1024;
uint8_t _sock = 4;
uint8_t _address[4] = { 
  216, 52, 233, 121 };  // IPv4 address
static uint16_t local_port;


void setup()
{
  // This code will only run once, after each powerup or reset of the board
  w5100.init();
  IPAddress cosm = ( 216, 52, 233, 121 );    // This is the current IPv4 address for Cosm.com
  //IPAddress cosm = (196,168,11,1);

#if DEBUG
  Serial.begin(9600);
#endif

  // Disable the SD card to prevent w5100 shield weirdness
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  delay(3000);
  int ret;
  ret = connect(cosm,80);
#if DEBUG
  Serial.print(ret);
#endif
}


int connect(IPAddress ip, uint16_t port) {
#if DEBUG
  Serial.print(MAX_SOCK_NUM);
  Serial.print("\t");
  Serial.println(_sock);
#endif

  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    uint8_t s = w5100.readSnSR(i);
#if DEBUG
    Serial.print(SnSR::CLOSED);
    Serial.print("\t");
    Serial.print(SnSR::FIN_WAIT);
    Serial.print("\t");
    Serial.println(SnSR::CLOSE_WAIT);
    Serial.println(float(s));
#endif
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {    // Looking for an available sock maybe?
      _sock = i;    // Sets _sock = to a sock that was Closed, Fin, or Close_Wait
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;
#if DEBUG
  Serial.println("Made it here because SnSR was CLOSED");
#endif

  _srcport++;
  if (_srcport == 0) _srcport = 1024;
  int ret;
  ret = socket(_sock, SnMR::TCP, _srcport, 0);

#if DEBUG
  Serial.print("Socket open result: ");
  Serial.println(ret);
#endif

  // Can't get this to work yet :(
  if (!::connect(_sock, rawIPAddress(ip), port)) {
    _sock = MAX_SOCK_NUM;
    return 0;
  }

  while (status() != SnSR::ESTABLISHED) {
#if DEBUG
    Serial.print("Status: ");
    Serial.println(status(),HEX);
#endif

    delay(1);
    if (status() == SnSR::CLOSED) {
      _sock = MAX_SOCK_NUM;
      return 0;
    }
  }

  return 1;
}

/**
 * @brief	This function established  the connection for the channel in Active (client) mode. 
 * 		This function waits for the untill the connection is established.
 * 		
 * @return	1 for success else 0.
 */
uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
{
  Serial.print("Got here\n");
  if 
    (
  ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
    ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
    (port == 0x00) 
    ) 
    return 0;

  // set destination IP
  W5100.writeSnDIPR(s, *addr);
  W5100.writeSnDPORT(s, port);
  W5100.execCmdSn(s, Sock_CONNECT);

  return 1;
}

uint8_t* rawIPAddress(IPAddress& addr) { 
  return addr; 
};
//uint8_t* raw_address() { return _address; };
//operator uint32_t() { return *((uint32_t*)_address); };


uint8_t status() {
  if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED;
  return W5100.readSnSR(_sock);
}

uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
{
  if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE))
  {
    close(s);
    w5100.writeSnMR(s, protocol | flag);
    if (port != 0) {
      w5100.writeSnPORT(s, port);
    } 
    else {
      local_port++; // if don't set the source port, set local_port number.
      w5100.writeSnPORT(s, local_port);
    }

    w5100.execCmdSn(s, Sock_CONNECT);

    return 1;
  }

  return 0;
}

void close(SOCKET s)
{
  w5100.execCmdSn(s, Sock_CLOSE);
  w5100.writeSnIR(s, 0xFF);
}



void loop()
{
  // This code will loops consecutively

}

Have you looked at this: Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller | ermicroblog
It´s exactly what you want, the Wiznet functions naked(without arduino), see the total program bytes: around 7KB.

fabiohbm007 thank you so much! I had never come across that page in my searching but I was able to adapt it to be exactly what I need.

I got the connect and HTTP Put down to 1,466 bytes and 171 bytes SRAM. Most of that SRAM consumption can be reclaimed by using the EEPROM. This is just a fraction of the size that the standard Ethernet library consumes even though I am not using the vast majority of its implementation. Below is the code for anyone that stumbles upon this thread later. Just adapt lines 198-201 to match your particular Cosm feed and change the size of buf to hold the entire HTTP Put.

#include <util/delay.h>

// AVRJazz Mega328 SPI I/O
#define SPI_PORT PORTB
#define SPI_DDR  DDRB
#define SPI_CS   PORTB2

// Wiznet W5100 Op Code
#define WIZNET_WRITE_OPCODE 0xF0
#define WIZNET_READ_OPCODE 0x0F

// Wiznet W5100 Register Addresses
#define MR         0x0000      // Mode Register
#define GAR        0x0001      // Gateway Address: 0x0001 to 0x0004
#define SUBR       0x0005      // Subnet mask Address: 0x0005 to 0x0008
#define SAR        0x0009      // Source Hardware Address (MAC): 0x0009 to 0x000E
#define SIPR       0x000F      // Source IP Address: 0x000F to 0x0012
#define RMSR       0x001A      // RX Memory Size Register
#define TMSR       0x001B      // TX Memory Size Register

#define S0_MR	   0x0400      // Socket 0: Mode Register Address
#define S0_CR	   0x0401      // Socket 0: Command Register Address
#define S0_IR	   0x0402      // Socket 0: Interrupt Register Address
#define S0_SR	   0x0403      // Socket 0: Status Register Address
#define S0_DIPR    0x040C      // Socket 0: Destination IP Address: 0x040C to 0x040F
#define S0_DPORT   0x0410      // Socket 0: Destination Port: 0x0410 to 0x0411
#define S0_PORT    0x0404      // Socket 0: Source Port: 0x0404 to 0x0405
#define SO_TX_FSR  0x0420      // Socket 0: Tx Free Size Register: 0x0420 to 0x0421
#define S0_TX_RD   0x0422      // Socket 0: Tx Read Pointer Register: 0x0422 to 0x0423
#define S0_TX_WR   0x0424      // Socket 0: Tx Write Pointer Register: 0x0424 to 0x0425
#define S0_RX_RSR  0x0426      // Socket 0: Rx Received Size Pointer Register: 0x0425 to 0x0427
#define S0_RX_RD   0x0428      // Socket 0: Rx Read Pointer: 0x0428 to 0x0429

#define TXBUFADDR  0x4000      // W5100 Send Buffer Base Address
#define RXBUFADDR  0x6000      // W5100 Read Buffer Base Address

// S0_MR values
#define MR_CLOSE	  0x00    // Unused socket
#define MR_TCP		  0x01    // TCP
#define MR_UDP		  0x02    // UDP
#define MR_IPRAW	  0x03	  // IP LAYER RAW SOCK
#define MR_MACRAW	  0x04	  // MAC LAYER RAW SOCK
#define MR_PPPOE	  0x05	  // PPPoE
#define MR_ND		  0x20	  // No Delayed Ack(TCP) flag
#define MR_MULTI	  0x80	  // support multicating

// S0_CR values
#define CR_OPEN          0x01	  // Initialize or open socket
#define CR_LISTEN        0x02	  // Wait connection request in tcp mode(Server mode)
#define CR_CONNECT       0x04	  // Send connection request in tcp mode(Client mode)
#define CR_DISCON        0x08	  // Send closing reqeuset in tcp mode
#define CR_CLOSE         0x10	  // Close socket
#define CR_SEND          0x20	  // Update Tx memory pointer and send data
#define CR_SEND_MAC      0x21	  // Send data with MAC address, so without ARP process
#define CR_SEND_KEEP     0x22	  // Send keep alive message
#define CR_RECV          0x40	  // Update Rx memory buffer pointer and receive data

// S0_SR values
#define SOCK_CLOSED      0x00     // Closed
#define SOCK_INIT        0x13	  // Init state
#define SOCK_LISTEN      0x14	  // Listen state
#define SOCK_SYNSENT     0x15	  // Connection state
#define SOCK_SYNRECV     0x16	  // Connection state
#define SOCK_ESTABLISHED 0x17	  // Success to connect
#define SOCK_FIN_WAIT    0x18	  // Closing state
#define SOCK_CLOSING     0x1A	  // Closing state
#define SOCK_TIME_WAIT	 0x1B	  // Closing state
#define SOCK_CLOSE_WAIT  0x1C	  // Closing state
#define SOCK_LAST_ACK    0x1D	  // Closing state
#define SOCK_UDP         0x22	  // UDP socket
#define SOCK_IPRAW       0x32	  // IP raw mode socket
#define SOCK_MACRAW      0x42	  // MAC raw mode socket
#define SOCK_PPPOE       0x5F	  // PPPOE socket

#define TX_BUF_MASK      0x07FF   // Tx 2K Buffer Mask:
#define RX_BUF_MASK      0x07FF   // Rx 2K Buffer Mask:
#define NET_MEMALLOC     0x05     // Use 2K of Tx/Rx Buffer

#define TCP_PORT         80       // TCP/IP Port

// Debugging Mode, 0 - Debug OFF, 1 - Debug ON
#define _DEBUG_MODE      0




#define MAX_BUF 169

uint8_t buf[MAX_BUF];

void SPI_Write(uint16_t addr,uint8_t data) {
  SPI_PORT &= ~(1<<SPI_CS);      // Activate the CS pin
  SPDR = WIZNET_WRITE_OPCODE;    // Start Wiznet W5100 Write OpCode transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPDR = (addr & 0xFF00) >> 8;   // Start Wiznet W5100 Address High Bytes transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPDR = addr & 0x00FF;          // Start Wiznet W5100 Address Low Bytes transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPDR = data;                   // Start Data transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPI_PORT |= (1<<SPI_CS);       // CS pin is not active
}

unsigned char SPI_Read(uint16_t addr) {
  SPI_PORT &= ~(1<<SPI_CS);      // Activate the CS pin
  SPDR = WIZNET_READ_OPCODE;     // Start Wiznet W5100 Read OpCode transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPDR = (addr & 0xFF00) >> 8;   // Start Wiznet W5100 Address High Bytes transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPDR = addr & 0x00FF;          // Start Wiznet W5100 Address Low Bytes transmission
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPDR = 0x00;                   // Send Dummy transmission for reading the data
  while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
  SPI_PORT |= (1<<SPI_CS);       // CS pin is not active
  return(SPDR);
}

Continuation of code because of the 9,500 character limit…

void W5100_Init(void)
{
  // Ethernet Setup
  unsigned char mac_addr[] = {0x00, 0x1D, 0x0D, 0x2C, 0x55, 0x3D};
  unsigned char ip_addr[] = {192,168,11,8};
  unsigned char sub_mask[] = {255,255,255,0};
  unsigned char gtw_addr[] = {192,168,11,1};
  unsigned char cosm_addr[] = {216,52,233,121};
  
  //_delay_ms(1000);
  
  // Setting the Wiznet W5100 Mode Register: 0x0000
  SPI_Write(MR,0x80);            // MR = 0b10000000;

  // Setting the Wiznet W5100 Gateway Address (GAR): 0x0001 to 0x0004
  SPI_Write(GAR + 0,gtw_addr[0]);
  SPI_Write(GAR + 1,gtw_addr[1]);
  SPI_Write(GAR + 2,gtw_addr[2]);
  SPI_Write(GAR + 3,gtw_addr[3]);

  // Setting the Wiznet W5100 Source Address Register (SAR): 0x0009 to 0x000E
  SPI_Write(SAR + 0,mac_addr[0]);
  SPI_Write(SAR + 1,mac_addr[1]);
  SPI_Write(SAR + 2,mac_addr[2]);
  SPI_Write(SAR + 3,mac_addr[3]);
  SPI_Write(SAR + 4,mac_addr[4]);
  SPI_Write(SAR + 5,mac_addr[5]);

  // Setting the Wiznet W5100 Sub Mask Address (SUBR): 0x0005 to 0x0008
  SPI_Write(SUBR + 0,sub_mask[0]);
  SPI_Write(SUBR + 1,sub_mask[1]);
  SPI_Write(SUBR + 2,sub_mask[2]);
  SPI_Write(SUBR + 3,sub_mask[3]);

  // Setting the Wiznet W5100 IP Address (SIPR): 0x000F to 0x0012
  SPI_Write(SIPR + 0,ip_addr[0]);
  SPI_Write(SIPR + 1,ip_addr[1]);
  SPI_Write(SIPR + 2,ip_addr[2]);
  SPI_Write(SIPR + 3,ip_addr[3]);    

  // Setting the Wiznet W5100 RX and TX Memory Size (2KB),
  SPI_Write(RMSR,NET_MEMALLOC);
  SPI_Write(TMSR,NET_MEMALLOC);
  
  // Setting the Wiznet to connect to the Cosm server port 80
  SPI_Write(S0_DIPR + 0,cosm_addr[0]);
  SPI_Write(S0_DIPR + 1,cosm_addr[1]);
  SPI_Write(S0_DIPR + 2,cosm_addr[2]);
  SPI_Write(S0_DIPR + 3,cosm_addr[3]);
  
  // Initialize procedure
  SPI_Write(S0_MR,MR_TCP);                    // Set the mode to TCP
  SPI_Write(S0_PORT,((1 & 0xFF00) >> 8 ));    // Set the source port to 1
  SPI_Write(S0_PORT + 1,(1 & 0x00FF));        // Set the source port to 1
  SPI_Write(S0_CR,CR_OPEN);
  while(SPI_Read(S0_CR));
  if(SPI_Read(S0_SR)!=SOCK_INIT) {
    //Serial.println("Open command failed to SOCK_INIT");
  }
  
  close(0);
  SPI_Write(S0_MR,MR_TCP);
  SPI_Write(S0_DIPR + 0,cosm_addr[0]);
  SPI_Write(S0_DIPR + 1,cosm_addr[1]);
  SPI_Write(S0_DIPR + 2,cosm_addr[2]);
  SPI_Write(S0_DIPR + 3,cosm_addr[3]);
  SPI_Write(S0_DPORT,((TCP_PORT & 0xFF00) >> 8 ));
  SPI_Write(S0_DPORT + 1,(TCP_PORT & 0x00FF));
  
  
  SPI_Write(S0_CR,CR_CONNECT);                   // Open Socket

  // Wait for Opening Process
  while(SPI_Read(S0_CR));
  
  do {
    _delay_ms(1);
  } while(SPI_Read(S0_SR)!=SOCK_ESTABLISHED);
  
  strcpy_P((char *)buf,PSTR("PUT /v2/feeds/102607.csv HTTP/1.1\nHost: api.cosm.com\n"));
  strcat_P((char *)buf,PSTR("X-ApiKey: dU2OFa0hD0kjGte5FkhZeMJeoqCSAKxva3hwZ3hCVitsMD0g\n"));
  strcat_P((char *)buf,PSTR("User-Agent: Test\n"));
  strcat_P((char *)buf,PSTR("Content-Length: 19\n\n1,71.2111\n2,72.4222\n"));
  
  send(0,buf,strlen((char *)buf));
  
}

void close(uint8_t sock)
{
   if (sock != 0) return;

   // Send Close Command
   SPI_Write(S0_CR,CR_CLOSE);

   // Waiting until the S0_CR is clear
   while(SPI_Read(S0_CR));
}

void disconnect(uint8_t sock)
{
   if (sock != 0) return;

   // Send Disconnect Command
   SPI_Write(S0_CR,CR_DISCON);

   // Wait for Disconecting Process
   while(SPI_Read(S0_CR));
}

uint16_t send(uint8_t sock,const uint8_t *buf,uint16_t buflen)
{
    uint16_t ptr,offaddr,realaddr,txsize,timeout;   

    if (buflen <= 0 || sock != 0) return 0;



    // Make sure the TX Free Size Register is available
    txsize=SPI_Read(SO_TX_FSR);
    txsize=(((txsize & 0x00FF) << 8 ) + SPI_Read(SO_TX_FSR + 1));



    timeout=0;
    while (txsize < buflen) {
      _delay_ms(1);

     txsize=SPI_Read(SO_TX_FSR);
     txsize=(((txsize & 0x00FF) << 8 ) + SPI_Read(SO_TX_FSR + 1));

     // Timeout for approx 1000 ms
     if (timeout++ > 1000) {

       // Disconnect the connection
       disconnect(sock);
       return 0;
     }
   }	

   // Read the Tx Write Pointer
   ptr = SPI_Read(S0_TX_WR);
   offaddr = (((ptr & 0x00FF) << 8 ) + SPI_Read(S0_TX_WR + 1));
	

    while(buflen) {
      buflen--;
      // Calculate the real W5100 physical Tx Buffer Address
      realaddr = TXBUFADDR + (offaddr & TX_BUF_MASK);

      // Copy the application data to the W5100 Tx Buffer
      SPI_Write(realaddr,*buf);
      offaddr++;
      buf++;
    }

    // Increase the S0_TX_WR value, so it point to the next transmit
    SPI_Write(S0_TX_WR,(offaddr & 0xFF00) >> 8 );
    SPI_Write(S0_TX_WR + 1,(offaddr & 0x00FF));	

    // Now Send the SEND command
    SPI_Write(S0_CR,CR_SEND);

    // Wait for Sending Process
    while(SPI_Read(S0_CR));	

    return 1;
}



ISR(TIMER0_OVF_vect)
{
  static unsigned char tenms=1;

  tenms++;                  // Read ADC every 20 x 10ms = 200 milisecond
  if (tenms >= 20) {
    cli();                                // Disable Interupt

    // Set ADMUX Channel for LM35DZ Input
    ADMUX=0x01;

    // Start conversion by setting ADSC on ADCSRA Register
    ADCSRA |= (1<<ADSC);

    // wait until convertion complete ADSC=0 -> Complete
    while (ADCSRA & (1<<ADSC));

    tenms=1;	 

    sei();                            // Enable Interupt
  }

  // Start counter from 0x94, overflow at 10 mSec
  TCNT0=0x94;
}


int main(void){

  // Reset Port D
  DDRD = 0xFF;       // Set PORTD as Output
  PORTD = 0x00;	     

  // Initial ATMega386 ADC Peripheral
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);

  // Free running ADC Mode
  ADCSRB = 0x00;

  // Initial the AVR ATMega328 SPI Peripheral
  // Set MOSI (PORTB3),SCK (PORTB5) and PORTB2 (SS) as output, others as input
  SPI_DDR = (1<<PORTB3)|(1<<PORTB5)|(1<<PORTB2);

  // CS pin is not active
  SPI_PORT |= (1<<SPI_CS);

  // Enable SPI, Master Mode 0, set the clock rate fck/2
  SPCR = (1<<SPE)|(1<<MSTR);
  SPSR |= (1<<SPI2X);  

  // Initial ATMega368 Timer/Counter0 Peripheral
  TCCR0A=0x00;                  // Normal Timer0 Operation
  TCCR0B=(1<<CS02)|(1<<CS00);   // Use maximum prescaller: Clk/1024
  TCNT0=0x94;                   // Start counter from 0x94, overflow at 10 mSec
  TIMSK0=(1<<TOIE0);            // Enable Counter Overflow Interrupt
  sei();                        // Enable Interrupt

  // Initial the W5100 Ethernet
  W5100_Init();
}