/*********************************************
* vim:sw=8:ts=8:si:et
* To use the above modeline in vim you must have "set modeline" in your .vimrc
* Author: Guido Socher
* Copyright: GPL V2
*
* Ethernet remote device and sensor
*
* Title: Microchip ENC28J60 Ethernet Interface Driver
* Chip type : ATMEGA88 with ENC28J60
*********************************************/
#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#include "ip_arp_udp.h"
//#include "timeout.h"
#include "enc28j60.h"
#include "avr_compat.h"
#include "net.h"

// please modify the following two lines. mac and ip have to be unique
// in your local area network. You can not have the same numbers in
// two devices:
static uint8_t mymac[6] = {0x54,0x01,0x02,0x03,0x04,0x05};
static uint8_t myip[4] = {192,168,0,124};
static uint16_t myport = 1200; // listen port for udp
// how did I get the mac addr? Translate the first 3 numbers into ascii is: TUX

#define BUFFER_SIZE 250
static uint8_t buf[BUFFER_SIZE+1];

// the password string (only the first 5 char checked):
static char password[]="secret";

uint8_t verify_password(char *str)
{
// the first characters of the received string are
// a simple password/cookie:
if (strncmp(password,str,5)==0){
return(1);
}
return(0);
}

uint16_t plen;
uint8_t i=0;
uint8_t cmd_pos=0;
uint8_t payloadlen=0;
char str[30];
char cmdval;
void setup(void)
{
// set the clock speed to 8MHz
// set the clock prescaler. First write CLKPCE to enable setting of clock the
// next four instructions.
CLKPR=(1<<CLKPCE);
CLKPR=1; // 8 MHZ
delay(10);

/* enable PB0, reset as output */
DDRB|= (1<<DDB0);

/* enable PD2/INT0, as input */
DDRD&= ~(1<<DDD2);

/* set output to gnd, reset the ethernet chip */
PORTB &= ~(1<<PB0);
delay(10);
/* set output to Vcc, reset inactive */
PORTB|= (1<<PB0);
delay(200);

/*initialize enc28j60*/
enc28j60Init(mymac);
delay(20);

// LED
/* enable PB1, LED as output */
DDRB|= (1<<DDB1);

/* set output to Vcc, LED off */
PORTB|= (1<<PB1);

// the transistor on PD7
DDRD|= (1<<DDD7);
PORTD &= ~(1<<PD7);// transistor off

/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDB=yellow LEDA=green
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
enc28j60PhyWrite(PHLCON,0x476);
delay(20);

/* set output to GND, red LED on */
PORTB &= ~(1<<PB1);
i=1;

//init the ethernet/ip layer:
init_ip_arp_udp(mymac,myip);
Serial.begin(19200);
Serial.println("AVR Initialized");
}

int main(void)
{
init();

// Call user setup
setup();

// Call user main loop
while (1) {
// get the next new packet:
plen = enc28j60PacketReceive(BUFFER_SIZE, buf);

/** plen will ne unequal to zero if there is a valid
* packet (without crc error)
**/
if(plen==0)
{
continue;
}

// led----------
if (i)
{
/* set output to Vcc, LED off */
PORTB|= (1<<PB1);
i=0;
}
else{
/* set output to GND, LED on */
PORTB &= ~(1<<PB1);
i=1;
}

// arp is broadcast if unknown but a host may also
// verify the mac address by sending it to
// a unicast address.
if(eth_type_is_arp_and_my_ip(buf,plen))
{
Serial.println("eth_type_is_arp_and_my_ip==1");
delay(2000);
make_arp_answer_from_request(buf,plen);
continue;
}
// check if ip packets (icmp or udp) are for us:
if(eth_type_is_ip_and_my_ip(buf,plen)==0)
{
Serial.println("eth_type_is_arp_and_my_ip==0");
delay(2000);
continue;
}

if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V)
{
Serial.println("buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V");
delay(2000);
// a ping packet, let's send pong
make_echo_reply_from_request(buf,plen);
continue;
}
// we listen on port 1200=0x4B0
if (buf[IP_PROTO_P]==IP_PROTO_UDP_V&&buf[UDP_DST_PORT_H_P]==4&&buf[UDP_DST_PORT_L_P]==0xb0)
{
Serial.println("buf[IP_PROTO_P]==IP_PROTO_UDP_V&&buf[UDP_DST_PORT_H_P]==4&&buf[UDP_DST_PORT_L_P]==0xb0");
delay(2000);
payloadlen=buf[UDP_LEN_L_P]-UDP_HEADER_LEN;
// you must sent a string starting with v
// e.g udpcom version 10.0.0.24
if (verify_password((char *)&(buf[UDP_DATA_P])))
{
// find the first comma which indicates
// the start of a command:
cmd_pos=0;
while(cmd_pos<payloadlen)
{
cmd_pos++;
if (buf[UDP_DATA_P+cmd_pos]==',')
{
cmd_pos++; // put on start of cmd
break;
}
}
// a command is one char and a value. At
// least 3 characters long. It has an '=' on
// position 2:
if (cmd_pos<2 || cmd_pos>payloadlen-3 || buf[UDP_DATA_P+cmd_pos+1]!='=')
{
strcpy(str,"e=no_cmd");
goto ANSWER;
}
// supported commands are
// t=1 t=0 t=?
if (buf[UDP_DATA_P+cmd_pos]=='t')
{
cmdval=buf[UDP_DATA_P+cmd_pos+2];
if(cmdval=='1')
{
PORTD|= (1<<PD7);// transistor on
strcpy(str,"t=1");
goto ANSWER;
}
else if(cmdval=='0')
{
PORTD &= ~(1<<PD7);// transistor off
strcpy(str,"t=0");
goto ANSWER;
}
else if(cmdval=='?')
{
if (PORTD & (1<<PD7))
{
strcpy(str,"t=1");
goto ANSWER;
}
strcpy(str,"t=0");
goto ANSWER;
}
}
strcpy(str,"e=no_such_cmd");
goto ANSWER;
}
strcpy(str,"e=invalid_pw");
ANSWER:
make_udp_reply_from_request(buf,str,strlen(str),myport);
}
}

return 0;
}