dumped all my old arduino stuff in here.

This commit is contained in:
Johannes Findeisen 2015-08-15 23:03:28 +02:00
commit 8f8959b76f
76 changed files with 8127 additions and 2 deletions

View file

@ -0,0 +1,162 @@
/*
FrequencyTimer2.h - A frequency generator and interrupt generator library
Author: Jim Studt, jim@federated.com
Copyright (c) 2007 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <FrequencyTimer2.h>
#include <avr/interrupt.h>
void (*FrequencyTimer2::onOverflow)() = 0;
uint8_t FrequencyTimer2::enabled = 0;
#if defined(__AVR_ATmega168__)
SIGNAL(SIG_OUTPUT_COMPARE2A)
#else
SIGNAL(SIG_OUTPUT_COMPARE2)
#endif
{
static uint8_t inHandler = 0; // protect us from recursion if our handler enables interrupts
if ( !inHandler && FrequencyTimer2::onOverflow) {
inHandler = 1;
(*FrequencyTimer2::onOverflow)();
inHandler = 0;
}
}
void FrequencyTimer2::setOnOverflow( void (*func)() )
{
FrequencyTimer2::onOverflow = func;
#if defined(__AVR_ATmega168__)
if ( func) TIMSK2 |= _BV(OCIE2A);
else TIMSK2 &= ~_BV(OCIE2A);
#else
if ( func) TIMSK |= _BV(OCIE2);
else TIMSK &= ~_BV(OCIE2);
#endif
}
void FrequencyTimer2::setPeriod(unsigned long period)
{
uint8_t pre, top;
if ( period == 0) period = 1;
period *= clockCyclesPerMicrosecond();
period /= 2; // we work with half-cycles before the toggle
if ( period <= 256) {
pre = 1;
top = period-1;
} else if ( period <= 256L*8) {
pre = 2;
top = period/8-1;
} else if ( period <= 256L*32) {
pre = 3;
top = period/32-1;
} else if ( period <= 256L*64) {
pre = 4;
top = period/64-1;
} else if ( period <= 256L*128) {
pre = 5;
top = period/128-1;
} else if ( period <= 256L*256) {
pre = 6;
top = period/256-1;
} else if ( period <= 256L*1024) {
pre = 7;
top = period/1024-1;
} else {
pre = 7;
top = 255;
}
#if defined(__AVR_ATmega168__)
TCCR2B = 0;
TCCR2A = 0;
TCNT2 = 0;
ASSR &= ~_BV(AS2); // use clock, not T2 pin
OCR2A = top;
TCCR2A = (_BV(WGM21) | ( FrequencyTimer2::enabled ? _BV(COM2A0) : 0));
TCCR2B = pre;
#else
TCCR2 = 0;
TCNT2 = 0;
ASSR &= ~_BV(AS2); // use clock, not T2 pin
OCR2 = top;
TCCR2 = (_BV(WGM21) | ( FrequencyTimer2::enabled ? _BV(COM20) : 0) | pre);
#endif
}
unsigned long FrequencyTimer2::getPeriod()
{
#if defined(__AVR_ATmega168__)
uint8_t p = (TCCR2B & 7);
unsigned long v = OCR2A;
#else
uint8_t p = (TCCR2 & 7);
unsigned long v = OCR2;
#endif
uint8_t shift;
switch(p) {
case 0 ... 1:
shift = 0;
break;
case 2:
shift = 3;
break;
case 3:
shift = 5;
break;
case 4:
shift = 6;
break;
case 5:
shift = 7;
break;
case 6:
shift = 8;
break;
case 7:
shift = 10;
break;
}
return (((v+1) << (shift+1)) + 1) / clockCyclesPerMicrosecond(); // shift+1 converts from half-period to period
}
void FrequencyTimer2::enable()
{
FrequencyTimer2::enabled = 1;
#if defined(__AVR_ATmega168__)
TCCR2A |= _BV(COM2A0);
#else
TCCR2 |= _BV(COM20);
#endif
}
void FrequencyTimer2::disable()
{
FrequencyTimer2::enabled = 0;
#if defined(__AVR_ATmega168__)
TCCR2A &= ~_BV(COM2A0);
#else
TCCR2 &= ~_BV(COM20);
#endif
}

View file

@ -0,0 +1,42 @@
#ifndef FREQUENCYTIMER2_IS_IN
#define FREQUENCYTIMER2_IS_IN
/*
FrequencyTimer2.h - A frequency generator and interrupt generator library
Author: Jim Studt, jim@federated.com
Copyright (c) 2007 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <wiring.h>
class FrequencyTimer2
{
private:
static uint8_t enabled;
public:
static void (*onOverflow)(); // not really public, but I can't work out the 'friend' for the SIGNAL
public:
static void setPeriod(unsigned long);
static unsigned long getPeriod();
static void setOnOverflow( void (*)() );
static void enable();
static void disable();
};
#endif

View file

@ -0,0 +1,22 @@
#######################################
# Syntax Coloring Map FrequencyTimer2
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
FrequencyTimer2 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
setPeriod KEYWORD2
getPeriod KEYWORD2
enable KEYWORD2
disable KEYWORD2
setOnOverflow KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View file

@ -0,0 +1,232 @@
/*
LCD4Bit v0.1 16/Oct/2006 neillzero http://abstractplain.net
What is this?
An arduino library for comms with HD44780-compatible LCD, in 4-bit mode (saves pins)
Sources:
- The original "LiquidCrystal" 8-bit library and tutorial
http://www.arduino.cc/en/uploads/Tutorial/LiquidCrystal.zip
http://www.arduino.cc/en/Tutorial/LCDLibrary
- DEM 16216 datasheet http://www.maplin.co.uk/Media/PDFs/N27AZ.pdf
- Massimo's suggested 4-bit code (I took initialization from here) http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1144924220/8
See also:
- glasspusher's code (probably more correct): http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1160586800/0#0
Tested only with a DEM 16216 (maplin "N27AZ" - http://www.maplin.co.uk/Search.aspx?criteria=N27AZ)
If you use this successfully, consider feeding back to the arduino wiki with a note of which LCD it worked on.
Usage:
see the examples folder of this library distribution.
*/
#include "LCD4Bit.h"
extern "C" {
#include <stdio.h> //not needed yet
#include <string.h> //needed for strlen()
#include <inttypes.h>
#include "WConstants.h" //all things wiring / arduino
}
//command bytes for LCD
#define CMD_CLR 0x01
#define CMD_RIGHT 0x1C
#define CMD_LEFT 0x18
#define CMD_HOME 0x02
// --------- PINS -------------------------------------
//is the RW pin of the LCD under our control? If we're only ever going to write to the LCD, we can use one less microcontroller pin, and just tie the LCD pin to the necessary signal, high or low.
//this stops us sending signals to the RW pin if it isn't being used.
int USING_RW = false;
//RS, RW and Enable can be set to whatever you like
int RS = 12;
int RW = 11;
int Enable = 2;
//DB should be an unseparated group of pins - because of lazy coding in pushNibble()
int DB[] = {7, 8, 9, 10}; //wire these to DB4~7 on LCD.
//--------------------------------------------------------
//how many lines has the LCD? (don't change here - specify on calling constructor)
int g_num_lines = 2;
//pulse the Enable pin high (for a microsecond).
//This clocks whatever command or data is in DB4~7 into the LCD controller.
void LCD4Bit::pulseEnablePin(){
digitalWrite(Enable,LOW);
delayMicroseconds(1);
// send a pulse to enable
digitalWrite(Enable,HIGH);
delayMicroseconds(1);
digitalWrite(Enable,LOW);
delay(1); // pause 1 ms. TODO: what delay, if any, is necessary here?
}
//push a nibble of data through the the LCD's DB4~7 pins, clocking with the Enable pin.
//We don't care what RS and RW are, here.
void LCD4Bit::pushNibble(int value){
int val_nibble= value & 0x0F; //clean the value. (unnecessary)
for (int i=DB[0]; i <= DB[3]; i++) {
digitalWrite(i,val_nibble & 01);
val_nibble >>= 1;
}
pulseEnablePin();
}
//push a byte of data through the LCD's DB4~7 pins, in two steps, clocking each with the enable pin.
void LCD4Bit::pushByte(int value){
int val_lower = value & 0x0F;
int val_upper = value >> 4;
pushNibble(val_upper);
pushNibble(val_lower);
}
//stuff the library user might call---------------------------------
//constructor. num_lines must be 1 or 2, currently.
LCD4Bit::LCD4Bit (int num_lines) {
g_num_lines = num_lines;
if (g_num_lines < 1 || g_num_lines > 2)
{
g_num_lines = 1;
}
}
void LCD4Bit::commandWriteNibble(int nibble) {
digitalWrite(RS, LOW);
if (USING_RW) { digitalWrite(RW, LOW); }
pushNibble(nibble);
}
void LCD4Bit::commandWrite(int value) {
digitalWrite(RS, LOW);
if (USING_RW) { digitalWrite(RW, LOW); }
pushByte(value);
//TODO: perhaps better to add a delay after EVERY command, here. many need a delay, apparently.
}
//print the given character at the current cursor position. overwrites, doesn't insert.
void LCD4Bit::print(int value) {
//set the RS and RW pins to show we're writing data
digitalWrite(RS, HIGH);
if (USING_RW) { digitalWrite(RW, LOW); }
//let pushByte worry about the intricacies of Enable, nibble order.
pushByte(value);
}
//print the given string to the LCD at the current cursor position. overwrites, doesn't insert.
//While I don't understand why this was named printIn (PRINT IN?) in the original LiquidCrystal library, I've preserved it here to maintain the interchangeability of the two libraries.
void LCD4Bit::printIn(char msg[]) {
uint8_t i; //fancy int. avoids compiler warning when comparing i with strlen()'s uint8_t
for (i=0;i < strlen(msg);i++){
print(msg[i]);
}
}
//send the clear screen command to the LCD
void LCD4Bit::clear(){
commandWrite(CMD_CLR);
delay(1);
}
// initiatize lcd after a short pause
//while there are hard-coded details here of lines, cursor and blink settings, you can override these original settings after calling .init()
void LCD4Bit::init () {
pinMode(Enable,OUTPUT);
pinMode(RS,OUTPUT);
if (USING_RW) { pinMode(RW,OUTPUT); }
pinMode(DB[0],OUTPUT);
pinMode(DB[1],OUTPUT);
pinMode(DB[2],OUTPUT);
pinMode(DB[3],OUTPUT);
delay(50);
//The first 4 nibbles and timings are not in my DEM16217 SYH datasheet, but apparently are HD44780 standard...
commandWriteNibble(0x03);
delay(5);
commandWriteNibble(0x03);
delayMicroseconds(100);
commandWriteNibble(0x03);
delay(5);
// needed by the LCDs controller
//this being 2 sets up 4-bit mode.
commandWriteNibble(0x02);
commandWriteNibble(0x02);
//todo: make configurable by the user of this library.
//NFXX where
//N = num lines (0=1 line or 1=2 lines).
//F= format (number of dots (0=5x7 or 1=5x10)).
//X=don't care
int num_lines_ptn = g_num_lines - 1 << 3;
int dot_format_ptn = 0x00; //5x7 dots. 0x04 is 5x10
commandWriteNibble(num_lines_ptn | dot_format_ptn);
delayMicroseconds(60);
//The rest of the init is not specific to 4-bit mode.
//NOTE: we're writing full bytes now, not nibbles.
// display control:
// turn display on, cursor off, no blinking
commandWrite(0x0C);
delayMicroseconds(60);
//clear display
commandWrite(0x01);
delay(3);
// entry mode set: 06
// increment automatically, display shift, entire shift off
commandWrite(0x06);
delay(1);//TODO: remove unnecessary delays
}
//non-core stuff --------------------------------------
//move the cursor to the given absolute position. line numbers start at 1.
//if this is not a 2-line LCD4Bit instance, will always position on first line.
void LCD4Bit::cursorTo(int line_num, int x){
//first, put cursor home
commandWrite(CMD_HOME);
//if we are on a 1-line display, set line_num to 1st line, regardless of given
if (g_num_lines==1){
line_num = 1;
}
//offset 40 chars in if second line requested
if (line_num == 2){
x += 40;
}
//advance the cursor to the right according to position. (second line starts at position 40).
for (int i=0; i<x; i++) {
commandWrite(0x14);
}
}
//scroll whole display to left
void LCD4Bit::leftScroll(int num_chars, int delay_time){
for (int i=0; i<num_chars; i++) {
commandWrite(CMD_LEFT);
delay(delay_time);
}
}
//Improvements ------------------------------------------------
//Remove the unnecessary delays (e.g. from the end of pulseEnablePin()).
//Allow the user to pass the pins to be used by the LCD in the constructor, and store them as member variables of the class instance.
//-------------------------------------------------------------

View file

@ -0,0 +1,27 @@
#ifndef LCD4Bit_h
#define LCD4Bit_h
#include <inttypes.h>
class LCD4Bit {
public:
LCD4Bit(int num_lines);
void commandWrite(int value);
void init();
void print(int value);
void printIn(char value[]);
void clear();
//non-core---------------
void cursorTo(int line_num, int x);
void leftScroll(int chars, int delay_time);
//end of non-core--------
//4bit only, therefore ideally private but may be needed by user
void commandWriteNibble(int nibble);
private:
void pulseEnablePin();
void pushNibble(int nibble);
void pushByte(int value);
};
#endif

View file

@ -0,0 +1,47 @@
//example use of LCD4Bit library
#include <LCD4Bit.h>
//create object to control an LCD.
//number of lines in display=1
LCD4Bit lcd = LCD4Bit(1);
//some messages to display on the LCD
char msgs[6][15] = {"apple", "banana", "pineapple", "mango", "watermelon", "pear"};
int NUM_MSGS = 6;
void setup() {
pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat
lcd.init();
//optionally, now set up our application-specific display settings, overriding whatever the lcd did in lcd.init()
//lcd.commandWrite(0x0F);//cursor on, display on, blink on. (nasty!)
}
void loop() {
digitalWrite(13, HIGH); //light the debug LED
//pick a random message from the array
int pick = random(NUM_MSGS);
char* msg = msgs[pick];
lcd.clear();
lcd.printIn(msg);
delay(1000);
digitalWrite(13, LOW);
//print some dots individually
for (int i=0; i<3; i++){
lcd.print('.');
delay(100);
}
//print something on the display's second line.
//uncomment this if your display HAS two lines!
/*
lcd.cursorTo(2, 0); //line=2, x=0.
lcd.printIn("Score: 6/7");
delay(1000);
*/
//scroll entire display 20 chars to left, delaying 50ms each inc
lcd.leftScroll(20, 50);
}

View file

@ -0,0 +1,27 @@
#######################################
# Syntax Coloring Map For Matrix
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LCD4Bit KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
clear KEYWORD2
commandWrite KEYWORD2
cursorTo KEYWORD2
init KEYWORD2
leftScroll KEYWORD2
print KEYWORD2
printIn KEYWORD2
commandWriteNibble KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View file

@ -0,0 +1,38 @@
This is a C++ library for Arduino for controlling an HD74800-compatible LCD in 4-bit mode.
Tested on Arduino 0005 Alpha.
Installation
--------------------------------------------------------------------------------
To install this library, just place this entire folder as a subfolder in your
Arduino/lib/targets/libraries folder.
When installed, this library should look like:
Arduino/lib/targets/libraries/LCD4Bit (this library's folder)
Arduino/lib/targets/libraries/LCD4Bit/LCD4Bit.cpp (the library implementation file)
Arduino/lib/targets/libraries/LCD4Bit/LCD4Bit.h (the library description file)
Arduino/lib/targets/libraries/LCD4Bit/keywords.txt (the syntax coloring file)
Arduino/lib/targets/libraries/LCD4Bit/examples (the examples in the "open" menu)
Arduino/lib/targets/libraries/LCD4Bit/readme.txt (this file)
Building
--------------------------------------------------------------------------------
After this library is installed, you just have to start the Arduino application.
You may see a few warning messages as it's built.
To use this library in a sketch, go to the Sketch | Import Library menu and
select LCD4Bit. This will add a corresponding line to the top of your sketch:
#include <LCD4Bit.h>
To stop using this library, delete that line from your sketch.
Geeky information:
After a successful build of this library, a new file named "LCD4Bit.o" will appear
in "Arduino/lib/targets/libraries/LCD4Bit". This file is the built/compiled library
code.
If you choose to modify the code for this library (i.e. "LCD4Bit.cpp" or "LCD4Bit.h"),
then you must first 'unbuild' this library by deleting the "LCD4Bit.o" file. The
new "LCD4Bit.o" with your code will appear after the next press of "verify"

View file

@ -0,0 +1,233 @@
#define A { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,0,0}, \
{0,0,0,1,0,1,0}, \
{0,1,1,1,1,0,0}, \
{0,0,0,0,0,0,0} \
}
#define B { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,1,0,1,0}, \
{0,0,1,0,1,0,0}, \
{0,0,0,0,0,0,0} \
}
#define C { \
{0,0,0,0,0,0,0}, \
{0,0,1,1,1,0,0}, \
{0,1,0,0,0,1,0}, \
{0,0,1,0,1,0,0}, \
{0,0,0,0,0,0,0} \
}
#define D { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,0,0,1,0}, \
{0,0,1,1,1,0,0}, \
{0,0,0,0,0,0,0} \
}
#define E { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,1,0,1,0}, \
{0,1,0,0,0,1,0}, \
{0,0,0,0,0,0,0} \
}
#define F { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,1,0,1,0}, \
{0,0,0,0,0,1,0}, \
{0,0,0,0,0,0,0} \
}
#define G { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,1,0,1,0}, \
{0,1,1,1,0,1,0}, \
{0,0,0,0,0,0,0} \
}
#define H { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,1,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define I { \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0} \
}
#define J { \
{0,0,0,0,0,0,0}, \
{0,0,1,1,0,0,0}, \
{0,1,0,0,0,0,0}, \
{0,0,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define K { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,1,0,0,0}, \
{0,1,1,0,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define L { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,0,0,0,0}, \
{0,1,0,0,0,0,0}, \
{0,0,0,0,0,0,0} \
}
#define M { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,1,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define N { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,1,1,1,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define O { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,0,0,1,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define P { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,1,0,1,0}, \
{0,0,0,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define Q { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,0,0,1,0}, \
{0,0,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define R { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,1,1,0,1,0}, \
{0,1,0,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define S { \
{0,0,0,0,0,0,0}, \
{0,1,0,0,1,0,0}, \
{0,1,0,1,0,1,0}, \
{0,0,1,0,0,1,0}, \
{0,0,0,0,0,0,0} \
}
#define T { \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,1,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,1,0}, \
{0,0,0,0,0,0,0} \
}
#define U { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,1,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define V { \
{0,0,0,0,0,0,0}, \
{0,0,1,1,1,1,0}, \
{0,1,0,0,0,0,0}, \
{0,0,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define W { \
{0,0,0,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,1,0,0,0,0}, \
{0,1,1,1,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define X { \
{0,0,0,0,0,0,0}, \
{0,1,1,0,1,1,0}, \
{0,0,0,1,0,0,0}, \
{0,1,1,0,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define Y { \
{0,0,0,0,0,0,0}, \
{0,0,0,0,1,1,0}, \
{0,1,1,1,0,0,0}, \
{0,0,0,0,1,1,0}, \
{0,0,0,0,0,0,0} \
}
#define Z { \
{0,0,0,0,0,0,0}, \
{0,1,0,0,1,1,0}, \
{0,1,0,1,0,1,0}, \
{0,1,1,0,0,1,0}, \
{0,0,0,0,0,0,0} \
}
#define DASH { \
{0,0,0,0,0,0,0}, \
{0,0,0,1,0,0,0}, \
{0,0,0,1,0,0,0}, \
{0,0,0,1,0,0,0}, \
{0,0,0,0,0,0,0} \
}
#define SPACE { \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0} \
}
#define DOT { \
{0,0,0,0,0,0,0}, \
{0,1,0,0,0,0,0}, \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0}, \
{0,0,0,0,0,0,0} \
}

101
libraries/TimerOne/TimerOne.cpp Executable file
View file

@ -0,0 +1,101 @@
/*
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
*
* This is free software. You can redistribute it and/or modify it under
* the terms of Creative Commons Attribution 3.0 United States License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
* or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
*/
#include "TimerOne.h"
TimerOne Timer1; // preinstatiate
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
Timer1.isrCallback();
}
void TimerOne::initialize(long microseconds)
{
TCCR1A = 0; // clear control register A
TCCR1B = _BV(WGM13); // set mode as phase and frequency correct pwm, stop the timer
setPeriod(microseconds);
}
void TimerOne::setPeriod(long microseconds)
{
long cycles = (F_CPU * microseconds) / 2000000; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum
ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
TCCR1B |= clockSelectBits; // reset clock select register
}
void TimerOne::setPwmDuty(char pin, int duty)
{
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if(pin == 1 || pin == 9) OCR1A = dutyCycle;
else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
}
void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
{
if(microseconds > 0) setPeriod(microseconds);
if(pin == 1 || pin == 9) {
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
}
else if(pin == 2 || pin == 10) {
DDRB |= _BV(PORTB2);
TCCR1A |= _BV(COM1B1);
}
setPwmDuty(pin, duty);
start();
}
void TimerOne::disablePwm(char pin)
{
if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
}
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
sei(); // ensures that interrupts are globally enabled
start();
}
void TimerOne::detachInterrupt()
{
TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit
}
void TimerOne::start()
{
TCCR1B |= clockSelectBits;
}
void TimerOne::stop()
{
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits
}
void TimerOne::restart()
{
TCNT1 = 0;
}

41
libraries/TimerOne/TimerOne.h Executable file
View file

@ -0,0 +1,41 @@
/*
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
*
* This is free software. You can redistribute it and/or modify it under
* the terms of Creative Commons Attribution 3.0 United States License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
* or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define RESOLUTION 65536 // Timer1 is 16 bit
class TimerOne
{
public:
// properties
unsigned int pwmPeriod;
unsigned char clockSelectBits;
// methods
void initialize(long microseconds=1000000);
void start();
void stop();
void restart();
void pwm(char pin, int duty, long microseconds=-1);
void disablePwm(char pin);
void attachInterrupt(void (*isr)(), long microseconds=-1);
void detachInterrupt();
void setPeriod(long microseconds);
void setPwmDuty(char pin, int duty);
void (*isrCallback)();
};
extern TimerOne Timer1;

View file

@ -0,0 +1,343 @@
/*********************************************
* 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
* http://www.gnu.org/licenses/gpl.html
*
* Based on the enc28j60.c file from the AVRlib library by Pascal Stang.
* For AVRlib See http://www.procyonengineering.com/
* Used with explicit permission of Pascal Stang.
*
* Title: Microchip ENC28J60 Ethernet Interface Driver
* Chip type : ATMEGA88 with ENC28J60
*********************************************/
#include <avr/io.h>
//#include "avr_compat.h"
#include "enc28j60.h"
#include "WConstants.h" //all things wiring / arduino
//#include "timeout.h"
//
//#define F_CPU 10000000UL // 12.5 MHz
/*
#ifndef ALIBC_OLD
#include <util/delay.h>
#else
#include <avr/delay.h>
#endif
*/
static uint8_t Enc28j60Bank;
static uint16_t NextPacketPtr;
#define ENC28J60_CONTROL_CS 10
#define SPI_MOSI 11
#define SPI_MISO 12
#define SPI_SCK 13
// set CS to 0 = active
#define CSACTIVE digitalWrite(ENC28J60_CONTROL_CS, LOW)
// set CS to 1 = passive
#define CSPASSIVE digitalWrite(ENC28J60_CONTROL_CS, HIGH)
//
#define waitspi() while(!(SPSR&(1<<SPIF)))
uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
{
CSACTIVE;
// issue read command
SPDR = op | (address & ADDR_MASK);
waitspi();
// read data
SPDR = 0x00;
waitspi();
// do dummy read if needed (for mac and mii, see datasheet page 29)
if(address & 0x80)
{
SPDR = 0x00;
waitspi();
}
// release CS
CSPASSIVE;
return(SPDR);
}
void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
{
CSACTIVE;
// issue write command
SPDR = op | (address & ADDR_MASK);
waitspi();
// write data
SPDR = data;
waitspi();
CSPASSIVE;
}
void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
{
CSACTIVE;
// issue read command
SPDR = ENC28J60_READ_BUF_MEM;
waitspi();
while(len)
{
len--;
// read data
SPDR = 0x00;
waitspi();
*data = SPDR;
data++;
}
*data='\0';
CSPASSIVE;
}
void enc28j60WriteBuffer(uint16_t len, uint8_t* data)
{
CSACTIVE;
// issue write command
SPDR = ENC28J60_WRITE_BUF_MEM;
waitspi();
while(len)
{
len--;
// write data
SPDR = *data;
data++;
waitspi();
}
CSPASSIVE;
}
void enc28j60SetBank(uint8_t address)
{
// set the bank (if needed)
if((address & BANK_MASK) != Enc28j60Bank)
{
// set the bank
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
Enc28j60Bank = (address & BANK_MASK);
}
}
uint8_t enc28j60Read(uint8_t address)
{
// set the bank
enc28j60SetBank(address);
// do the read
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}
void enc28j60Write(uint8_t address, uint8_t data)
{
// set the bank
enc28j60SetBank(address);
// do the write
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}
void enc28j60PhyWrite(uint8_t address, uint16_t data)
{
// set the PHY register address
enc28j60Write(MIREGADR, address);
// write the PHY data
enc28j60Write(MIWRL, data);
enc28j60Write(MIWRH, data>>8);
// wait until the PHY write completes
while(enc28j60Read(MISTAT) & MISTAT_BUSY){
delayMicroseconds(15);
}
}
void enc28j60clkout(uint8_t clk)
{
//setup clkout: 2 is 12.5MHz:
enc28j60Write(ECOCON, clk & 0x7);
}
void enc28j60Init(uint8_t* macaddr)
{
// initialize I/O
// ss as output:
pinMode(ENC28J60_CONTROL_CS, OUTPUT);
CSPASSIVE; // ss=0
//
pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_SCK, OUTPUT);
pinMode(SPI_MISO, INPUT);
digitalWrite(SPI_MOSI, LOW);
digitalWrite(SPI_SCK, LOW);
/*DDRB |= 1<<PB3 | 1<<PB5; // mosi, sck output
cbi(DDRB,PINB4); // MISO is input
//
cbi(PORTB,PB3); // MOSI low
cbi(PORTB,PB5); // SCK low
*/
//
// initialize SPI interface
// master mode and Fosc/2 clock:
SPCR = (1<<SPE)|(1<<MSTR);
SPSR |= (1<<SPI2X);
// perform system reset
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
delay(50);
// check CLKRDY bit to see if reset is complete
// The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
//while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
// do bank 0 stuff
// initialize receive buffer
// 16-bit transfers, must write low byte first
// set receive buffer start address
NextPacketPtr = RXSTART_INIT;
// Rx start
enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
enc28j60Write(ERXSTH, RXSTART_INIT>>8);
// set receive pointer address
enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
// RX end
enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
// TX start
enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
enc28j60Write(ETXSTH, TXSTART_INIT>>8);
// TX end
enc28j60Write(ETXNDL, TXSTOP_INIT&0xFF);
enc28j60Write(ETXNDH, TXSTOP_INIT>>8);
// do bank 1 stuff, packet filter:
// For broadcast packets we allow only ARP packtets
// All other packets should be unicast only for our mac (MAADR)
//
// The pattern to match on is therefore
// Type ETH.DST
// ARP BROADCAST
// 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
// in binary these poitions are:11 0000 0011 1111
// This is hex 303F->EPMM0=0x3f,EPMM1=0x30
enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
enc28j60Write(EPMM0, 0x3f);
enc28j60Write(EPMM1, 0x30);
enc28j60Write(EPMCSL, 0xf9);
enc28j60Write(EPMCSH, 0xf7);
//
//
// do bank 2 stuff
// enable MAC receive
enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
// bring MAC out of reset
enc28j60Write(MACON2, 0x00);
// enable automatic padding to 60bytes and CRC operations
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
// set inter-frame gap (non-back-to-back)
enc28j60Write(MAIPGL, 0x12);
enc28j60Write(MAIPGH, 0x0C);
// set inter-frame gap (back-to-back)
enc28j60Write(MABBIPG, 0x12);
// Set the maximum packet size which the controller will accept
// Do not send packets longer than MAX_FRAMELEN:
enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF);
enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
// do bank 3 stuff
// write MAC address
// NOTE: MAC address in ENC28J60 is byte-backward
enc28j60Write(MAADR5, macaddr[0]);
enc28j60Write(MAADR4, macaddr[1]);
enc28j60Write(MAADR3, macaddr[2]);
enc28j60Write(MAADR2, macaddr[3]);
enc28j60Write(MAADR1, macaddr[4]);
enc28j60Write(MAADR0, macaddr[5]);
// no loopback of transmitted frames
enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
// switch to bank 0
enc28j60SetBank(ECON1);
// enable interrutps
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
// enable packet reception
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
}
// read the revision of the chip:
uint8_t enc28j60getrev(void)
{
return(enc28j60Read(EREVID));
}
void enc28j60PacketSend(uint16_t len, uint8_t* packet)
{
// Set the write pointer to start of transmit buffer area
enc28j60Write(EWRPTL, TXSTART_INIT&0xFF);
enc28j60Write(EWRPTH, TXSTART_INIT>>8);
// Set the TXND pointer to correspond to the packet size given
enc28j60Write(ETXNDL, (TXSTART_INIT+len)&0xFF);
enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
// write per-packet control byte (0x00 means use macon3 settings)
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
// copy the packet into the transmit buffer
enc28j60WriteBuffer(len, packet);
// send the contents of the transmit buffer onto the network
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
// Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
if( (enc28j60Read(EIR) & EIR_TXERIF) ){
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
}
}
// Gets a packet from the network receive buffer, if one is available.
// The packet will by headed by an ethernet header.
// maxlen The maximum acceptable length of a retrieved packet.
// packet Pointer where packet data should be stored.
// Returns: Packet length in bytes if a packet was retrieved, zero otherwise.
uint16_t enc28j60PacketReceive(uint16_t maxlen, uint8_t* packet)
{
uint16_t rxstat;
uint16_t len;
// check if a packet has been received and buffered
//if( !(enc28j60Read(EIR) & EIR_PKTIF) ){
// The above does not work. See Rev. B4 Silicon Errata point 6.
if( enc28j60Read(EPKTCNT) ==0 ){
return(0);
}
// Set the read pointer to the start of the received packet
enc28j60Write(ERDPTL, (NextPacketPtr));
enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
// read the next packet pointer
NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
// read the packet length (see datasheet page 43)
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
len-=4; //remove the CRC count
// read the receive status (see datasheet page 43)
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
// limit retrieve length
if (len>maxlen-1){
len=maxlen-1;
}
// check CRC and symbol errors (see datasheet page 44, table 7-3):
// The ERXFCON.CRCEN is set by default. Normally we should not
// need to check this.
if ((rxstat & 0x80)==0){
// invalid
len=0;
}else{
// copy the packet from the receive buffer
enc28j60ReadBuffer(len, packet);
}
// Move the RX read pointer to the start of the next received packet
// This frees the memory we just read out
enc28j60Write(ERXRDPTL, (NextPacketPtr));
enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
// decrement the packet counter indicate we are done with this packet
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
return(len);
}

View file

@ -0,0 +1,280 @@
/*****************************************************************************
* vim:sw=8:ts=8:si:et
*
* Title : Microchip ENC28J60 Ethernet Interface Driver
* Author : Pascal Stang (c)2005
* Modified by Guido Socher
* Copyright: GPL V2
*
*This driver provides initialization and transmit/receive
*functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
*This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
*chip, using an SPI interface to the host processor.
*
*
*****************************************************************************/
/*********************************************
* Modified: nuelectronics.com -- Ethershield for Arduino
*********************************************/
//@{
#ifndef ENC28J60_H
#define ENC28J60_H
#include <inttypes.h>
// ENC28J60 Control Registers
// Control register definitions are a combination of address,
// bank number, and Ethernet/MAC/PHY indicator bits.
// - Register address (bits 0-4)
// - Bank number (bits 5-6)
// - MAC/PHY indicator (bit 7)
#define ADDR_MASK 0x1F
#define BANK_MASK 0x60
#define SPRD_MASK 0x80
// All-bank registers
#define EIE 0x1B
#define EIR 0x1C
#define ESTAT 0x1D
#define ECON2 0x1E
#define ECON1 0x1F
// Bank 0 registers
#define ERDPTL (0x00|0x00)
#define ERDPTH (0x01|0x00)
#define EWRPTL (0x02|0x00)
#define EWRPTH (0x03|0x00)
#define ETXSTL (0x04|0x00)
#define ETXSTH (0x05|0x00)
#define ETXNDL (0x06|0x00)
#define ETXNDH (0x07|0x00)
#define ERXSTL (0x08|0x00)
#define ERXSTH (0x09|0x00)
#define ERXNDL (0x0A|0x00)
#define ERXNDH (0x0B|0x00)
#define ERXRDPTL (0x0C|0x00)
#define ERXRDPTH (0x0D|0x00)
#define ERXWRPTL (0x0E|0x00)
#define ERXWRPTH (0x0F|0x00)
#define EDMASTL (0x10|0x00)
#define EDMASTH (0x11|0x00)
#define EDMANDL (0x12|0x00)
#define EDMANDH (0x13|0x00)
#define EDMADSTL (0x14|0x00)
#define EDMADSTH (0x15|0x00)
#define EDMACSL (0x16|0x00)
#define EDMACSH (0x17|0x00)
// Bank 1 registers
#define EHT0 (0x00|0x20)
#define EHT1 (0x01|0x20)
#define EHT2 (0x02|0x20)
#define EHT3 (0x03|0x20)
#define EHT4 (0x04|0x20)
#define EHT5 (0x05|0x20)
#define EHT6 (0x06|0x20)
#define EHT7 (0x07|0x20)
#define EPMM0 (0x08|0x20)
#define EPMM1 (0x09|0x20)
#define EPMM2 (0x0A|0x20)
#define EPMM3 (0x0B|0x20)
#define EPMM4 (0x0C|0x20)
#define EPMM5 (0x0D|0x20)
#define EPMM6 (0x0E|0x20)
#define EPMM7 (0x0F|0x20)
#define EPMCSL (0x10|0x20)
#define EPMCSH (0x11|0x20)
#define EPMOL (0x14|0x20)
#define EPMOH (0x15|0x20)
#define EWOLIE (0x16|0x20)
#define EWOLIR (0x17|0x20)
#define ERXFCON (0x18|0x20)
#define EPKTCNT (0x19|0x20)
// Bank 2 registers
#define MACON1 (0x00|0x40|0x80)
#define MACON2 (0x01|0x40|0x80)
#define MACON3 (0x02|0x40|0x80)
#define MACON4 (0x03|0x40|0x80)
#define MABBIPG (0x04|0x40|0x80)
#define MAIPGL (0x06|0x40|0x80)
#define MAIPGH (0x07|0x40|0x80)
#define MACLCON1 (0x08|0x40|0x80)
#define MACLCON2 (0x09|0x40|0x80)
#define MAMXFLL (0x0A|0x40|0x80)
#define MAMXFLH (0x0B|0x40|0x80)
#define MAPHSUP (0x0D|0x40|0x80)
#define MICON (0x11|0x40|0x80)
#define MICMD (0x12|0x40|0x80)
#define MIREGADR (0x14|0x40|0x80)
#define MIWRL (0x16|0x40|0x80)
#define MIWRH (0x17|0x40|0x80)
#define MIRDL (0x18|0x40|0x80)
#define MIRDH (0x19|0x40|0x80)
// Bank 3 registers
#define MAADR1 (0x00|0x60|0x80)
#define MAADR0 (0x01|0x60|0x80)
#define MAADR3 (0x02|0x60|0x80)
#define MAADR2 (0x03|0x60|0x80)
#define MAADR5 (0x04|0x60|0x80)
#define MAADR4 (0x05|0x60|0x80)
#define EBSTSD (0x06|0x60)
#define EBSTCON (0x07|0x60)
#define EBSTCSL (0x08|0x60)
#define EBSTCSH (0x09|0x60)
#define MISTAT (0x0A|0x60|0x80)
#define EREVID (0x12|0x60)
#define ECOCON (0x15|0x60)
#define EFLOCON (0x17|0x60)
#define EPAUSL (0x18|0x60)
#define EPAUSH (0x19|0x60)
// PHY registers
#define PHCON1 0x00
#define PHSTAT1 0x01
#define PHHID1 0x02
#define PHHID2 0x03
#define PHCON2 0x10
#define PHSTAT2 0x11
#define PHIE 0x12
#define PHIR 0x13
#define PHLCON 0x14
// ENC28J60 ERXFCON Register Bit Definitions
#define ERXFCON_UCEN 0x80
#define ERXFCON_ANDOR 0x40
#define ERXFCON_CRCEN 0x20
#define ERXFCON_PMEN 0x10
#define ERXFCON_MPEN 0x08
#define ERXFCON_HTEN 0x04
#define ERXFCON_MCEN 0x02
#define ERXFCON_BCEN 0x01
// ENC28J60 EIE Register Bit Definitions
#define EIE_INTIE 0x80
#define EIE_PKTIE 0x40
#define EIE_DMAIE 0x20
#define EIE_LINKIE 0x10
#define EIE_TXIE 0x08
#define EIE_WOLIE 0x04
#define EIE_TXERIE 0x02
#define EIE_RXERIE 0x01
// ENC28J60 EIR Register Bit Definitions
#define EIR_PKTIF 0x40
#define EIR_DMAIF 0x20
#define EIR_LINKIF 0x10
#define EIR_TXIF 0x08
#define EIR_WOLIF 0x04
#define EIR_TXERIF 0x02
#define EIR_RXERIF 0x01
// ENC28J60 ESTAT Register Bit Definitions
#define ESTAT_INT 0x80
#define ESTAT_LATECOL 0x10
#define ESTAT_RXBUSY 0x04
#define ESTAT_TXABRT 0x02
#define ESTAT_CLKRDY 0x01
// ENC28J60 ECON2 Register Bit Definitions
#define ECON2_AUTOINC 0x80
#define ECON2_PKTDEC 0x40
#define ECON2_PWRSV 0x20
#define ECON2_VRPS 0x08
// ENC28J60 ECON1 Register Bit Definitions
#define ECON1_TXRST 0x80
#define ECON1_RXRST 0x40
#define ECON1_DMAST 0x20
#define ECON1_CSUMEN 0x10
#define ECON1_TXRTS 0x08
#define ECON1_RXEN 0x04
#define ECON1_BSEL1 0x02
#define ECON1_BSEL0 0x01
// ENC28J60 MACON1 Register Bit Definitions
#define MACON1_LOOPBK 0x10
#define MACON1_TXPAUS 0x08
#define MACON1_RXPAUS 0x04
#define MACON1_PASSALL 0x02
#define MACON1_MARXEN 0x01
// ENC28J60 MACON2 Register Bit Definitions
#define MACON2_MARST 0x80
#define MACON2_RNDRST 0x40
#define MACON2_MARXRST 0x08
#define MACON2_RFUNRST 0x04
#define MACON2_MATXRST 0x02
#define MACON2_TFUNRST 0x01
// ENC28J60 MACON3 Register Bit Definitions
#define MACON3_PADCFG2 0x80
#define MACON3_PADCFG1 0x40
#define MACON3_PADCFG0 0x20
#define MACON3_TXCRCEN 0x10
#define MACON3_PHDRLEN 0x08
#define MACON3_HFRMLEN 0x04
#define MACON3_FRMLNEN 0x02
#define MACON3_FULDPX 0x01
// ENC28J60 MICMD Register Bit Definitions
#define MICMD_MIISCAN 0x02
#define MICMD_MIIRD 0x01
// ENC28J60 MISTAT Register Bit Definitions
#define MISTAT_NVALID 0x04
#define MISTAT_SCAN 0x02
#define MISTAT_BUSY 0x01
// ENC28J60 PHY PHCON1 Register Bit Definitions
#define PHCON1_PRST 0x8000
#define PHCON1_PLOOPBK 0x4000
#define PHCON1_PPWRSV 0x0800
#define PHCON1_PDPXMD 0x0100
// ENC28J60 PHY PHSTAT1 Register Bit Definitions
#define PHSTAT1_PFDPX 0x1000
#define PHSTAT1_PHDPX 0x0800
#define PHSTAT1_LLSTAT 0x0004
#define PHSTAT1_JBSTAT 0x0002
// ENC28J60 PHY PHCON2 Register Bit Definitions
#define PHCON2_FRCLINK 0x4000
#define PHCON2_TXDIS 0x2000
#define PHCON2_JABBER 0x0400
#define PHCON2_HDLDIS 0x0100
// ENC28J60 Packet Control Byte Bit Definitions
#define PKTCTRL_PHUGEEN 0x08
#define PKTCTRL_PPADEN 0x04
#define PKTCTRL_PCRCEN 0x02
#define PKTCTRL_POVERRIDE 0x01
// SPI operation codes
#define ENC28J60_READ_CTRL_REG 0x00
#define ENC28J60_READ_BUF_MEM 0x3A
#define ENC28J60_WRITE_CTRL_REG 0x40
#define ENC28J60_WRITE_BUF_MEM 0x7A
#define ENC28J60_BIT_FIELD_SET 0x80
#define ENC28J60_BIT_FIELD_CLR 0xA0
#define ENC28J60_SOFT_RESET 0xFF
// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
// buffer boundaries applied to internal 8K ram
// the entire available packet buffer space is allocated
//
// start with recbuf at 0/
#define RXSTART_INIT 0x0
// receive buffer end
#define RXSTOP_INIT (0x1FFF-0x0600-1)
// start TX buffer at 0x1FFF-0x0600, pace for one full ethernet frame (~1500 bytes)
#define TXSTART_INIT (0x1FFF-0x0600)
// stp TX buffer at end of mem
#define TXSTOP_INIT 0x1FFF
//
// max frame length which the conroller will accept:
#define MAX_FRAMELEN 1500 // (note: maximum ethernet frame length would be 1518)
//#define MAX_FRAMELEN 600
// functions
extern uint8_t enc28j60ReadOp(uint8_t op, uint8_t address);
extern void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data);
extern void enc28j60ReadBuffer(uint16_t len, uint8_t* data);
extern void enc28j60WriteBuffer(uint16_t len, uint8_t* data);
extern void enc28j60SetBank(uint8_t address);
extern uint8_t enc28j60Read(uint8_t address);
extern void enc28j60Write(uint8_t address, uint8_t data);
extern void enc28j60PhyWrite(uint8_t address, uint16_t data);
extern void enc28j60clkout(uint8_t clk);
extern void enc28j60Init(uint8_t* macaddr);
extern void enc28j60PacketSend(uint16_t len, uint8_t* packet);
extern uint16_t enc28j60PacketReceive(uint16_t maxlen, uint8_t* packet);
extern uint8_t enc28j60getrev(void);
#endif
//@}

View file

@ -0,0 +1,109 @@
// a wrapper class for EtherShield
extern "C" {
#include "enc28j60.h"
#include "ip_arp_udp_tcp.h"
}
#include "etherShield.h"
//constructor
EtherShield::EtherShield(){
}
uint16_t EtherShield::ES_fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s){
return fill_tcp_data_p(buf, pos, progmem_s);
}
uint16_t EtherShield::ES_fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s){
return fill_tcp_data(buf,pos, s);
}
void EtherShield::ES_enc28j60Init(uint8_t* macaddr){
enc28j60Init(macaddr);
}
void EtherShield::ES_enc28j60clkout(uint8_t clk){
enc28j60clkout(clk);
}
void EtherShield::ES_enc28j60PhyWrite(uint8_t address, uint16_t data){
enc28j60PhyWrite(address, data);
}
uint16_t EtherShield::ES_enc28j60PacketReceive(uint16_t len, uint8_t* packet){
return enc28j60PacketReceive(len, packet);
}
void EtherShield::ES_init_ip_arp_udp_tcp(uint8_t *mymac,uint8_t *myip,uint8_t wwwp){
init_ip_arp_udp_tcp(mymac,myip,wwwp);
}
uint8_t EtherShield::ES_eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len){
return eth_type_is_arp_and_my_ip(buf,len);
}
void EtherShield::ES_make_arp_answer_from_request(uint8_t *buf){
make_arp_answer_from_request(buf);
}
uint8_t EtherShield::ES_eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len){
return eth_type_is_ip_and_my_ip(buf, len);
}
void EtherShield::ES_make_echo_reply_from_request(uint8_t *buf,uint16_t len){
make_echo_reply_from_request(buf,len);
}
void EtherShield::ES_make_tcp_synack_from_syn(uint8_t *buf){
make_tcp_synack_from_syn(buf);
}
void EtherShield::ES_init_len_info(uint8_t *buf){
init_len_info(buf);
}
uint16_t EtherShield::ES_get_tcp_data_pointer(void){
return get_tcp_data_pointer();
}
void EtherShield::ES_make_tcp_ack_from_any(uint8_t *buf){
make_tcp_ack_from_any(buf);
}
void EtherShield::ES_make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen){
make_tcp_ack_with_data(buf,dlen);
}
void EtherShield::ES_make_arp_request(uint8_t *buf, uint8_t *server_ip){
make_arp_request(buf, server_ip);
}
uint8_t EtherShield::ES_arp_packet_is_myreply_arp ( uint8_t *buf ){
return arp_packet_is_myreply_arp (buf);
}
void EtherShield::ES_tcp_client_send_packet(uint8_t *buf,uint16_t dest_port, uint16_t src_port, uint8_t flags, uint8_t max_segment_size,
uint8_t clear_seqck, uint16_t next_ack_num, uint16_t dlength, uint8_t *dest_mac, uint8_t *dest_ip){
tcp_client_send_packet(buf, dest_port, src_port, flags, max_segment_size, clear_seqck, next_ack_num, dlength,dest_mac,dest_ip);
}
uint16_t EtherShield::ES_tcp_get_dlength( uint8_t *buf ){
return tcp_get_dlength(buf);
}

View file

@ -0,0 +1,61 @@
/*
EHTERSHIELD_H library for Arduino etherShield
Copyright (c) 2008 Xing Yu. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ETHERSHIELD_H
#define ETHERSHIELD_H
#include <inttypes.h>
#include "enc28j60.h"
#include "ip_arp_udp_tcp.h"
#include "net.h"
class EtherShield
{
public:
EtherShield();
uint16_t ES_fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s);
uint16_t ES_fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s);
void ES_enc28j60Init(uint8_t* macaddr);
void ES_enc28j60clkout(uint8_t clk);
void ES_enc28j60PhyWrite(uint8_t address, uint16_t data);
uint16_t ES_enc28j60PacketReceive(uint16_t len, uint8_t* packet);
void ES_init_ip_arp_udp_tcp(uint8_t *mymac,uint8_t *myip,uint8_t wwwp);
uint8_t ES_eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len);
void ES_make_arp_answer_from_request(uint8_t *buf);
uint8_t ES_eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len);
void ES_make_echo_reply_from_request(uint8_t *buf,uint16_t len);
void ES_make_tcp_synack_from_syn(uint8_t *buf);
void ES_init_len_info(uint8_t *buf);
uint16_t ES_get_tcp_data_pointer(void);
void ES_make_tcp_ack_from_any(uint8_t *buf);
void ES_make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen);
// new web client functions
void ES_make_arp_request(uint8_t *buf, uint8_t *server_ip);
uint8_t ES_arp_packet_is_myreply_arp ( uint8_t *buf );
void ES_tcp_client_send_packet(uint8_t *buf,uint16_t dest_port, uint16_t src_port, uint8_t flags, uint8_t max_segment_size,
uint8_t clear_seqck, uint16_t next_ack_num, uint16_t dlength, uint8_t *dest_mac, uint8_t *dest_ip);
uint16_t ES_tcp_get_dlength( uint8_t *buf );
};
#endif

View file

@ -0,0 +1,411 @@
#include "etherShield.h"
// please modify the following 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,0x55,0x58,0x10,0x00,0x24};
static uint8_t myip[4] = {192,168,1,88};
static uint16_t my_port = 1200; // client port
// client_ip - modify it when you have multiple client on the network
// for server to distinguish each ethershield client
static char client_ip[] = "192.168.1.88";
// server settings - modify the service ip to your own server
static uint8_t dest_ip[4]={192,168,1,4};
static uint8_t dest_mac[6];
enum CLIENT_STATE
{
IDLE, ARP_SENT, ARP_REPLY, SYNC_SENT
};
static CLIENT_STATE client_state;
static uint8_t client_data_ready;
static uint8_t syn_ack_timeout = 0;
#define BUFFER_SIZE 500
static uint8_t buf[BUFFER_SIZE+1];
char sensorData[10];
EtherShield es=EtherShield();
// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf);
int8_t analyse_cmd(char *str);
// get current temperature
#define TEMP_PIN 3
void getCurrentTemp( char *temperature);
void client_process(void);
void setup(){
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDA=greed LEDB=yellow
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
es.ES_enc28j60PhyWrite(PHLCON,0x476);
delay(100);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
// intialize varible;
syn_ack_timeout =0;
client_data_ready = 0;
client_state = IDLE;
// initialize DS18B20 datapin
digitalWrite(TEMP_PIN, LOW);
pinMode(TEMP_PIN, INPUT); // sets the digital pin as input (logic 1)
}
void loop(){
if(client_data_ready==0){
delay(60000UL); // delay 60s
getCurrentTemp(sensorData);
client_data_ready = 1;
}
client_process();
}
uint16_t gen_client_request(uint8_t *buf )
{
uint16_t plen;
byte i;
plen= es.ES_fill_tcp_data_p(buf,0, PSTR ( "GET /ethershield_log/save.php?pwd=secret&client=" ) );
for(i=0; client_ip[i]!='\0'; i++){
buf[TCP_DATA_P+plen]=client_ip[i];
plen++;
}
plen= es.ES_fill_tcp_data_p(buf,plen, PSTR ( "&status=temperature-" ) );
for(i=0; sensorData[i]!='\0'; i++){
buf[TCP_DATA_P+plen]=sensorData[i];
plen++;
}
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( " HTTP/1.0\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Host: 192.168.1.4\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "User-Agent: AVR ethernet\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Accept: text/html\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Keep-Alive: 300\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Connection: keep-alive\r\n\r\n" ));
return plen;
}
//*****************************************************************************************
//
// Function : client_process
// Description : send temparature to web server, this option is disabled by default.
// YOU MUST install webserver and server script before enable this option,
// I recommented Apache webserver and PHP script.
// More detail about Apache and PHP installation please visit http://www.avrportal.com/
//
//*****************************************************************************************
void client_process ( void )
{
uint16_t plen;
uint8_t i;
if (client_data_ready == 0) return; // nothing to send
if(client_state == IDLE){ // initialize ARP
es.ES_make_arp_request(buf, dest_ip);
client_state = ARP_SENT;
return;
}
if(client_state == ARP_SENT){
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
// destination ip address was found on network
if ( plen!=0 )
{
if ( es.ES_arp_packet_is_myreply_arp ( buf ) ){
client_state = ARP_REPLY;
syn_ack_timeout=0;
return;
}
}
delay(10);
syn_ack_timeout++;
if(syn_ack_timeout== 100) { //timeout, server ip not found
client_state = IDLE;
client_data_ready =0;
syn_ack_timeout=0;
return;
}
}
// send SYN packet to initial connection
if(client_state == ARP_REPLY){
// save dest mac
for(i=0; i<6; i++){
dest_mac[i] = buf[ETH_SRC_MAC+i];
}
es.ES_tcp_client_send_packet (
buf,
80,
1200,
TCP_FLAG_SYN_V, // flag
1, // (bool)maximum segment size
1, // (bool)clear sequence ack number
0, // 0=use old seq, seqack : 1=new seq,seqack no data : new seq,seqack with data
0, // tcp data length
dest_mac,
dest_ip
);
client_state = SYNC_SENT;
}
// get new packet
if(client_state == SYNC_SENT){
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
// no new packet incoming
if ( plen == 0 )
{
return;
}
// check ip packet send to avr or not?
// accept ip packet only
if ( es.ES_eth_type_is_ip_and_my_ip(buf,plen)==0){
return;
}
// check SYNACK flag, after AVR send SYN server response by send SYNACK to AVR
if ( buf [ TCP_FLAGS_P ] == ( TCP_FLAG_SYN_V | TCP_FLAG_ACK_V ) )
{
// send ACK to answer SYNACK
es.ES_tcp_client_send_packet (
buf,
80,
1200,
TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
1, // 0=use old seq, seqack : 1=new seq,seqack no data : new seq,seqack with data
0, // tcp data length
dest_mac,
dest_ip
);
// setup http request to server
plen = gen_client_request( buf );
// send http request packet
// send packet with PSHACK
es.ES_tcp_client_send_packet (
buf,
80, // destination port
1200, // source port
TCP_FLAG_ACK_V | TCP_FLAG_PUSH_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
0, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
plen, // tcp data length
dest_mac,
dest_ip
);
return;
}
// after AVR send http request to server, server response by send data with PSHACK to AVR
// AVR answer by send ACK and FINACK to server
if ( buf [ TCP_FLAGS_P ] == (TCP_FLAG_ACK_V|TCP_FLAG_PUSH_V) )
{
plen = es.ES_tcp_get_dlength( (uint8_t*)&buf );
// send ACK to answer PSHACK from server
es.ES_tcp_client_send_packet (
buf,
80, // destination port
1200, // source port
TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
plen, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
0, // tcp data length
dest_mac,
dest_ip
);;
// send finack to disconnect from web server
es.ES_tcp_client_send_packet (
buf,
80, // destination port
1200, // source port
TCP_FLAG_FIN_V|TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
0, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
0,
dest_mac,
dest_ip
);
return;
}
// answer FINACK from web server by send ACK to web server
if ( buf [ TCP_FLAGS_P ] == (TCP_FLAG_ACK_V|TCP_FLAG_FIN_V) )
{
// send ACK with seqack = 1
es.ES_tcp_client_send_packet(
buf,
80, // destination port
1200, // source port
TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
1, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
0,
dest_mac,
dest_ip
);
client_state = IDLE; // return to IDLE state
client_data_ready =0; // client data sent
}
}
}
void OneWireReset(int Pin) // reset. Should improve to act as a presence pulse
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT); // bring low for 500 us
delayMicroseconds(500);
pinMode(Pin, INPUT);
delayMicroseconds(500);
}
void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
byte n;
for(n=8; n!=0; n--)
{
if ((d & 0x01) == 1) // test least sig bit
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(5);
pinMode(Pin, INPUT);
delayMicroseconds(60);
}
else
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(60);
pinMode(Pin, INPUT);
}
d=d>>1; // now the next bit is in the least sig bit position.
}
}
byte OneWireInByte(int Pin) // read byte, least sig byte first
{
byte d, n, b;
for (n=0; n<8; n++)
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(5);
pinMode(Pin, INPUT);
delayMicroseconds(5);
b = digitalRead(Pin);
delayMicroseconds(50);
d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
}
return(d);
}
void getCurrentTemp(char *temp)
{
int HighByte, LowByte, TReading, Tc_100, sign, whole, fract;
OneWireReset(TEMP_PIN);
OneWireOutByte(TEMP_PIN, 0xcc);
OneWireOutByte(TEMP_PIN, 0x44); // perform temperature conversion, strong pullup for one sec
OneWireReset(TEMP_PIN);
OneWireOutByte(TEMP_PIN, 0xcc);
OneWireOutByte(TEMP_PIN, 0xbe);
LowByte = OneWireInByte(TEMP_PIN);
HighByte = OneWireInByte(TEMP_PIN);
TReading = (HighByte << 8) + LowByte;
sign = TReading & 0x8000; // test most sig bit
if (sign) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25
whole = Tc_100 / 100; // separate off the whole and fractional portions
fract = Tc_100 % 100;
if(sign) temp[0]='-';
else temp[0]='+';
temp[1]= (whole-(whole/100)*100)/10 +'0' ;
temp[2]= whole-(whole/10)*10 +'0';
temp[3]='.';
temp[4]=fract/10 +'0';
temp[5]=fract-(fract/10)*10 +'0';
temp[6] = '\0';
}

View file

@ -0,0 +1,333 @@
#include "etherShield.h"
/*infrared sensor setting*/
#define INFRARED_IN 3
#define LED_STATUS 5
#define ENABLE_EXTERNAL1_INTERRUPT() ( EIMSK |= ( 1<< INT1 ) )
#define DISABLE_EXTERNAL1_INTERRUPT() ( EIMSK &= ~( 1<< INT1 ) )
// please modify the following 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,0x55,0x58,0x10,0x00,0x33};
static uint8_t myip[4] = {192,168,1,89};
static uint16_t my_port = 1200; // client port
// client_ip - modify it when you have multiple client on the network
// for server to distinguish each ethershield client
static char client_ip[] = "192.168.1.89";
// server settings - modify the service ip to your own server
static uint8_t dest_ip[4]={192,168,1,4};
static uint8_t dest_mac[6];
enum CLIENT_STATE
{
IDLE, ARP_SENT, ARP_REPLY, SYNC_SENT
};
static CLIENT_STATE client_state;
static uint8_t client_data_ready;
static uint8_t syn_ack_timeout = 0;
#define BUFFER_SIZE 500
static uint8_t buf[BUFFER_SIZE+1];
EtherShield es=EtherShield();
void setup(){
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDA=greed LEDB=yellow
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
es.ES_enc28j60PhyWrite(PHLCON,0x476);
delay(100);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
// intialize varible;
syn_ack_timeout =0;
client_data_ready = 0;
client_state = IDLE;
// infrared sensor initialization
pinMode(LED_STATUS, OUTPUT); // infrad
digitalWrite(LED_STATUS,LOW);
pinMode(INFRARED_IN, INPUT);
ENABLE_EXTERNAL1_INTERRUPT();
// tigger at INT1 rising edge
EICRA = 0x0c;
SREG|=1<<SREG_I;
}
void loop(){
if(client_data_ready==1){
DISABLE_EXTERNAL1_INTERRUPT();
client_process();
digitalWrite(LED_STATUS, HIGH);
}
else{
delay(100);
ENABLE_EXTERNAL1_INTERRUPT();
digitalWrite(LED_STATUS, LOW);
}
}
ISR(INT1_vect) {
client_data_ready= 1;
}
uint16_t gen_client_request(uint8_t *buf )
{
uint16_t plen;
byte i;
plen= es.ES_fill_tcp_data_p(buf,0, PSTR ( "GET /ethershield_log/save.php?pwd=secret&client=" ) );
for(i=0; client_ip[i]!='\0'; i++){
buf[TCP_DATA_P+plen]=client_ip[i];
plen++;
}
plen= es.ES_fill_tcp_data_p(buf,plen, PSTR ( "&status=Infrared_ON" ) );
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( " HTTP/1.0\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Host: 192.168.1.4\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "User-Agent: AVR ethernet\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Accept: text/html\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Keep-Alive: 300\r\n" ));
plen= es.ES_fill_tcp_data_p(buf, plen, PSTR ( "Connection: keep-alive\r\n\r\n" ));
return plen;
}
//*****************************************************************************************
//
// Function : client_process
// Description : send temparature to web server, this option is disabled by default.
// YOU MUST install webserver and server script before enable this option,
// I recommented Apache webserver and PHP script.
// More detail about Apache and PHP installation please visit http://www.avrportal.com/
//
//*****************************************************************************************
void client_process ( void )
{
uint16_t plen;
uint8_t i;
if (client_data_ready == 0) return; // nothing to send
if(client_state == IDLE){ // initialize ARP
es.ES_make_arp_request(buf, dest_ip);
client_state = ARP_SENT;
return;
}
if(client_state == ARP_SENT){
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
// destination ip address was found on network
if ( plen!=0 )
{
if ( es.ES_arp_packet_is_myreply_arp ( buf ) ){
client_state = ARP_REPLY;
syn_ack_timeout=0;
return;
}
}
delay(10);
syn_ack_timeout++;
if(syn_ack_timeout== 100) { //timeout, server ip not found
client_state = IDLE;
client_data_ready =0;
syn_ack_timeout=0;
return;
}
}
// send SYN packet to initial connection
if(client_state == ARP_REPLY){
// save dest mac
for(i=0; i<6; i++){
dest_mac[i] = buf[ETH_SRC_MAC+i];
}
es.ES_tcp_client_send_packet (
buf,
80,
1200,
TCP_FLAG_SYN_V, // flag
1, // (bool)maximum segment size
1, // (bool)clear sequence ack number
0, // 0=use old seq, seqack : 1=new seq,seqack no data : new seq,seqack with data
0, // tcp data length
dest_mac,
dest_ip
);
client_state = SYNC_SENT;
}
// get new packet
if(client_state == SYNC_SENT){
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
// no new packet incoming
if ( plen == 0 )
{
return;
}
// check ip packet send to avr or not?
// accept ip packet only
if ( es.ES_eth_type_is_ip_and_my_ip(buf,plen)==0){
return;
}
// check SYNACK flag, after AVR send SYN server response by send SYNACK to AVR
if ( buf [ TCP_FLAGS_P ] == ( TCP_FLAG_SYN_V | TCP_FLAG_ACK_V ) )
{
// send ACK to answer SYNACK
es.ES_tcp_client_send_packet (
buf,
80,
1200,
TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
1, // 0=use old seq, seqack : 1=new seq,seqack no data : new seq,seqack with data
0, // tcp data length
dest_mac,
dest_ip
);
// setup http request to server
plen = gen_client_request( buf );
// send http request packet
// send packet with PSHACK
es.ES_tcp_client_send_packet (
buf,
80, // destination port
1200, // source port
TCP_FLAG_ACK_V | TCP_FLAG_PUSH_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
0, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
plen, // tcp data length
dest_mac,
dest_ip
);
return;
}
// after AVR send http request to server, server response by send data with PSHACK to AVR
// AVR answer by send ACK and FINACK to server
if ( buf [ TCP_FLAGS_P ] == (TCP_FLAG_ACK_V|TCP_FLAG_PUSH_V) )
{
plen = es.ES_tcp_get_dlength( (uint8_t*)&buf );
// send ACK to answer PSHACK from server
es.ES_tcp_client_send_packet (
buf,
80, // destination port
1200, // source port
TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
plen, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
0, // tcp data length
dest_mac,
dest_ip
);;
// send finack to disconnect from web server
es.ES_tcp_client_send_packet (
buf,
80, // destination port
1200, // source port
TCP_FLAG_FIN_V|TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
0, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
0,
dest_mac,
dest_ip
);
return;
}
// answer FINACK from web server by send ACK to web server
if ( buf [ TCP_FLAGS_P ] == (TCP_FLAG_ACK_V|TCP_FLAG_FIN_V) )
{
// send ACK with seqack = 1
es.ES_tcp_client_send_packet(
buf,
80, // destination port
1200, // source port
TCP_FLAG_ACK_V, // flag
0, // (bool)maximum segment size
0, // (bool)clear sequence ack number
1, // 0=use old seq, seqack : 1=new seq,seqack no data : >1 new seq,seqack with data
0,
dest_mac,
dest_ip
);
client_state = IDLE; // return to IDLE state
client_data_ready =0; // client data sent
}
}
}

View file

@ -0,0 +1,239 @@
# Arduino makefile
#
# This makefile allows you to build sketches from the command line
# without the Arduino environment (or Java).
#
# The Arduino environment does preliminary processing on a sketch before
# compiling it. If you're using this makefile instead, you'll need to do
# a few things differently:
#
# - Give your program's file a .cpp extension (e.g. foo.cpp).
#
# - Put this line at top of your code: #include <WProgram.h>
#
# - Write prototypes for all your functions (or define them before you
# call them). A prototype declares the types of parameters a
# function will take and what type of value it will return. This
# means that you can have a call to a function before the definition
# of the function. A function prototype looks like the first line of
# the function, with a semi-colon at the end. For example:
# int digitalRead(int pin);
#
# - Write a main() function for your program that returns an int, calls
# init() and setup() once (in that order), and then calls loop()
# repeatedly():
#
# int main()
# {
# init();
# setup();
#
# for (;;)
# loop();
#
# return 0;
# }
#
# Instructions for using the makefile:
#
# 1. Copy this file into the folder with your sketch.
#
# 2. Below, modify the line containing "TARGET" to refer to the name of
# of your program's file without an extension (e.g. TARGET = foo).
#
# 3. Modify the line containg "ARDUINO" to point the directory that
# contains the Arduino core (for normal Arduino installations, this
# is the hardware/cores/arduino sub-directory).
#
# 4. Modify the line containing "PORT" to refer to the filename
# representing the USB or serial connection to your Arduino board
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
#
# 5. At the command line, change to the directory containing your
# program's file and the makefile.
#
# 6. Type "make" and press enter to compile/verify your program.
#
# 7. Type "make upload", reset your Arduino board, and press enter to
# upload your program to the Arduino board.
#
# $Id$
PORT = /dev/tty.usbserial*
TARGET = foo
ARDUINO = arduino
SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
$(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \
$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c
CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WRandom.cpp
MCU = atmega168
F_CPU = 16000000
FORMAT = ihex
UPLOAD_RATE = 19200
# Name of this Makefile (used for "make depend").
MAKEFILE = Makefile
# Debugging format.
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
DEBUG = stabs
OPT = s
# Place -D or -U options here
CDEFS = -DF_CPU=$(F_CPU)
CXXDEFS = -DF_CPU=$(F_CPU)
# Place -I options here
CINCS = -I$(ARDUINO)
CXXINCS = -I$(ARDUINO)
# Compiler flag to set the C Standard level.
# c89 - "ANSI" C
# gnu89 - c89 plus GCC extensions
# c99 - ISO C99 standard (not yet fully implemented)
# gnu99 - c99 plus GCC extensions
CSTANDARD = -std=gnu99
CDEBUG = -g$(DEBUG)
CWARN = -Wall -Wstrict-prototypes
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT)
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
LDFLAGS = -lm
# Programming support using avrdude. Settings and variables.
AVRDUDE_PROGRAMMER = stk500
AVRDUDE_PORT = $(PORT)
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
-b $(UPLOAD_RATE)
# Program settings
CC = avr-gcc
CXX = avr-g++
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AR = avr-ar
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
MV = mv -f
# Define all object files.
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
# Define all listing files.
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: build
build: elf hex
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
# Program the device.
upload: $(TARGET).hex
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000
coff: $(TARGET).elf
$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym
.elf.hex:
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
.elf.eep:
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
# Create extended listing file from ELF output file.
.elf.lss:
$(OBJDUMP) -h -S $< > $@
# Create a symbol table from ELF output file.
.elf.sym:
$(NM) -n $< > $@
core.a: $(OBJ)
@for i in $(OBJ); do echo $(AR) rcs core.a $$i; $(AR) rcs core.a $$i; done
# Link: create ELF output file from library.
$(TARGET).elf: core.a
$(CC) $(ALL_CFLAGS) -o $@ $(TARGET).cpp -L. core.a $(LDFLAGS) -Map=$(TARGET).map
# Compile: create object files from C++ source files.
.cpp.o:
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
# Compile: create object files from C source files.
.c.o:
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C source files.
.c.s:
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
.S.o:
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Target: clean project.
clean:
$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
$(TARGET).map $(TARGET).sym $(TARGET).lss core.a \
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
depend:
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
then \
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
$(MAKEFILE).$$$$ && \
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
fi
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
>> $(MAKEFILE); \
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend

View file

@ -0,0 +1,87 @@
#include "etherShield.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,0x55,0x58,0x10,0x00,0x24};
static uint8_t myip[4] = {
192,168,1,15};
// how did I get the mac addr? Translate the first 3 numbers into ascii is: TUX
#define BUFFER_SIZE 250
unsigned char buf[BUFFER_SIZE+1];
uint16_t plen;
EtherShield es=EtherShield();
void setup(){
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDA=green LEDB=yellow
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
es.ES_enc28j60PhyWrite(PHLCON,0x476);
delay(100);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
}
void loop(){
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
/*plen will be unequal to zero if there is a valid packet (without crc error) */
if(plen!=0){
if(es.ES_eth_type_is_arp_and_my_ip(buf,plen)){
es.ES_make_arp_answer_from_request(buf);
}
// check if ip packets (icmp or udp) are for us:
if(es.ES_eth_type_is_ip_and_my_ip(buf,plen)!=0){
if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
// a ping packet, let's send pong
es.ES_make_echo_reply_from_request(buf,plen);
}
}
}
}

View file

@ -0,0 +1,229 @@
#include "etherShield.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,0x55,0x58,0x10,0x00,0x24};
static uint8_t myip[4] = {192,168,1,15};
static char baseurl[]="http://192.168.1.15/";
static uint16_t mywwwport =80; // listen port for tcp/www (max range 1-254)
#define BUFFER_SIZE 500
static uint8_t buf[BUFFER_SIZE+1];
#define STR_BUFFER_SIZE 22
static char strbuf[STR_BUFFER_SIZE+1];
EtherShield es=EtherShield();
// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf, byte on_off);
int8_t analyse_cmd(char *str);
// LED cathode connects the Pin4, anode to 5V through 1K resistor
#define LED_PIN 4
void setup(){
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDA=greed LEDB=yellow
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
es.ES_enc28j60PhyWrite(PHLCON,0x476);
delay(100);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // switch on LED
}
void loop(){
uint16_t plen, dat_p;
int8_t cmd;
byte on_off = 1;
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
/*plen will ne unequal to zero if there is a valid packet (without crc error) */
if(plen!=0){
// arp is broadcast if unknown but a host may also verify the mac address by sending it to a unicast address.
if(es.ES_eth_type_is_arp_and_my_ip(buf,plen)){
es.ES_make_arp_answer_from_request(buf);
return;
}
// check if ip packets are for us:
if(es.ES_eth_type_is_ip_and_my_ip(buf,plen)==0){
return;
}
if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
es.ES_make_echo_reply_from_request(buf,plen);
return;
}
// tcp port www start, compare only the lower byte
if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==mywwwport){
if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
es.ES_make_tcp_synack_from_syn(buf); // make_tcp_synack_from_syn does already send the syn,ack
return;
}
if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
es.ES_init_len_info(buf); // init some data structures
dat_p=es.ES_get_tcp_data_pointer();
if (dat_p==0){ // we can possibly have no data, just ack:
if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
es.ES_make_tcp_ack_from_any(buf);
}
return;
}
if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){
// head, post and other methods for possible status codes see:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));
goto SENDTCP;
}
if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){
plen=print_webpage(buf, on_off);
goto SENDTCP;
}
cmd=analyse_cmd((char *)&(buf[dat_p+5]));
if (cmd==2){
on_off=1;
digitalWrite(LED_PIN, LOW); // switch on LED
}
else if (cmd==3){
on_off=0;
digitalWrite(LED_PIN, HIGH); // switch off LED
}
plen=print_webpage(buf, on_off);
plen=print_webpage(buf, on_off);
SENDTCP: es.ES_make_tcp_ack_from_any(buf); // send ack for http get
es.ES_make_tcp_ack_with_data(buf,plen); // send data
}
}
}
}
// The returned value is stored in the global var strbuf
uint8_t find_key_val(char *str,char *key)
{
uint8_t found=0;
uint8_t i=0;
char *kp;
kp=key;
while(*str && *str!=' ' && found==0){
if (*str == *kp){
kp++;
if (*kp == '\0'){
str++;
kp=key;
if (*str == '='){
found=1;
}
}
}else{
kp=key;
}
str++;
}
if (found==1){
// copy the value to a buffer and terminate it with '\0'
while(*str && *str!=' ' && *str!='&' && i<STR_BUFFER_SIZE){
strbuf[i]=*str;
i++;
str++;
}
strbuf[i]='\0';
}
return(found);
}
int8_t analyse_cmd(char *str)
{
int8_t r=-1;
if (find_key_val(str,"cmd")){
if (*strbuf < 0x3a && *strbuf > 0x2f){
// is a ASCII number, return it
r=(*strbuf-0x30);
}
}
return r;
}
uint16_t print_webpage(uint8_t *buf, byte on_off)
{
int i=0;
uint16_t plen;
plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Arduino Ethernet Shield V1.0 </h1></p> "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr><br><form METHOD=get action=\""));
plen=es.ES_fill_tcp_data(buf,plen,baseurl);
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("\">"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h2> REMOTE LED is </h2> "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h1><font color=\"#00FF00\"> "));
if(on_off)
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("ON"));
else
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("OFF"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(" </font></h1><br> ") );
if(on_off){
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=3>"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Switch off\"></form>"));
}
else {
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=2>"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Switch on\"></form>"));
}
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</center><hr> <p> V1.0 <a href=\"http://www.nuelectronics.com\">www.nuelectronics.com<a>"));
return(plen);
}

View file

@ -0,0 +1,317 @@
#include "etherShield.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,0x55,0x58,0x10,0x00,0x24};
static uint8_t myip[4] = {192,168,1,15};
static char baseurl[]="http://192.168.1.15/";
static uint16_t mywwwport =80; // listen port for tcp/www (max range 1-254)
// or on a different port:
//static char baseurl[]="http://10.0.0.24:88/";
//static uint16_t mywwwport =88; // listen port for tcp/www (max range 1-254)
//
#define BUFFER_SIZE 500
static uint8_t buf[BUFFER_SIZE+1];
#define STR_BUFFER_SIZE 22
static char strbuf[STR_BUFFER_SIZE+1];
EtherShield es=EtherShield();
// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf);
int8_t analyse_cmd(char *str);
// get current temperature
#define TEMP_PIN 3
void getCurrentTemp( int *sign, int *whole, int *fract);
void setup(){
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDA=greed LEDB=yellow
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
es.ES_enc28j60PhyWrite(PHLCON,0x476);
delay(100);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
// initialize DS18B20 datapin
digitalWrite(TEMP_PIN, LOW);
pinMode(TEMP_PIN, INPUT); // sets the digital pin as input (logic 1)
}
void loop(){
uint16_t plen, dat_p;
int8_t cmd;
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
/*plen will ne unequal to zero if there is a valid packet (without crc error) */
if(plen!=0){
// arp is broadcast if unknown but a host may also verify the mac address by sending it to a unicast address.
if(es.ES_eth_type_is_arp_and_my_ip(buf,plen)){
es.ES_make_arp_answer_from_request(buf);
return;
}
// check if ip packets are for us:
if(es.ES_eth_type_is_ip_and_my_ip(buf,plen)==0){
return;
}
if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
es.ES_make_echo_reply_from_request(buf,plen);
return;
}
// tcp port www start, compare only the lower byte
if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==mywwwport){
if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
es.ES_make_tcp_synack_from_syn(buf); // make_tcp_synack_from_syn does already send the syn,ack
return;
}
if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
es.ES_init_len_info(buf); // init some data structures
dat_p=es.ES_get_tcp_data_pointer();
if (dat_p==0){ // we can possibly have no data, just ack:
if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
es.ES_make_tcp_ack_from_any(buf);
}
return;
}
if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){
// head, post and other methods for possible status codes see:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));
goto SENDTCP;
}
if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){
plen=print_webpage(buf);
goto SENDTCP;
}
cmd=analyse_cmd((char *)&(buf[dat_p+5]));
if (cmd==1){
plen=print_webpage(buf);
}
SENDTCP: es.ES_make_tcp_ack_from_any(buf); // send ack for http get
es.ES_make_tcp_ack_with_data(buf,plen); // send data
}
}
}
}
// The returned value is stored in the global var strbuf
uint8_t find_key_val(char *str,char *key)
{
uint8_t found=0;
uint8_t i=0;
char *kp;
kp=key;
while(*str && *str!=' ' && found==0){
if (*str == *kp){
kp++;
if (*kp == '\0'){
str++;
kp=key;
if (*str == '='){
found=1;
}
}
}else{
kp=key;
}
str++;
}
if (found==1){
// copy the value to a buffer and terminate it with '\0'
while(*str && *str!=' ' && *str!='&' && i<STR_BUFFER_SIZE){
strbuf[i]=*str;
i++;
str++;
}
strbuf[i]='\0';
}
return(found);
}
int8_t analyse_cmd(char *str)
{
int8_t r=-1;
if (find_key_val(str,"cmd")){
if (*strbuf < 0x3a && *strbuf > 0x2f){
// is a ASCII number, return it
r=(*strbuf-0x30);
}
}
return r;
}
uint16_t print_webpage(uint8_t *buf)
{
char temp_string[10];
int i=0;
//char *temp_string="100";
uint16_t plen;
getCurrentTemp(temp_string);
plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Arduino Ethernet Shield V1.0 </h1></p> "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr><br><form METHOD=get action=\""));
plen=es.ES_fill_tcp_data(buf,plen,baseurl);
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("\">"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h2> Current Temperature is </h2> "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h1><font color=\"#00FF00\"> "));
while (temp_string[i]) {
buf[TCP_CHECKSUM_L_P+3+plen]=temp_string[i++];
plen++;
}
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(" &#176C</font></h1><br> ") );
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=hidden name=cmd value=1>"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<input type=submit value=\"Get Temperature\"></form>"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</center><hr> <p> V1.0 <a href=\"http://www.nuelectronics.com\">www.nuelectronics.com<a>"));
return(plen);
}
void OneWireReset(int Pin) // reset. Should improve to act as a presence pulse
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT); // bring low for 500 us
delayMicroseconds(500);
pinMode(Pin, INPUT);
delayMicroseconds(500);
}
void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
byte n;
for(n=8; n!=0; n--)
{
if ((d & 0x01) == 1) // test least sig bit
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(5);
pinMode(Pin, INPUT);
delayMicroseconds(60);
}
else
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(60);
pinMode(Pin, INPUT);
}
d=d>>1; // now the next bit is in the least sig bit position.
}
}
byte OneWireInByte(int Pin) // read byte, least sig byte first
{
byte d, n, b;
for (n=0; n<8; n++)
{
digitalWrite(Pin, LOW);
pinMode(Pin, OUTPUT);
delayMicroseconds(5);
pinMode(Pin, INPUT);
delayMicroseconds(5);
b = digitalRead(Pin);
delayMicroseconds(50);
d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
}
return(d);
}
void getCurrentTemp(char *temp)
{
int HighByte, LowByte, TReading, Tc_100, sign, whole, fract;
OneWireReset(TEMP_PIN);
OneWireOutByte(TEMP_PIN, 0xcc);
OneWireOutByte(TEMP_PIN, 0x44); // perform temperature conversion, strong pullup for one sec
OneWireReset(TEMP_PIN);
OneWireOutByte(TEMP_PIN, 0xcc);
OneWireOutByte(TEMP_PIN, 0xbe);
LowByte = OneWireInByte(TEMP_PIN);
HighByte = OneWireInByte(TEMP_PIN);
TReading = (HighByte << 8) + LowByte;
sign = TReading & 0x8000; // test most sig bit
if (sign) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25
whole = Tc_100 / 100; // separate off the whole and fractional portions
fract = Tc_100 % 100;
if(sign) temp[0]='-';
else temp[0]='+';
if(whole/100==0)
temp[1] =' ';
else
temp[1]= whole/100+'0';
temp[2]= (whole-(whole/100)*100)/10 +'0' ;
temp[3]= whole-(whole/10)*10 +'0';
temp[4]='.';
temp[5]=fract/10 +'0';
temp[6]=fract-(fract/10)*10 +'0';
temp[7] = '\0';
}

View file

@ -0,0 +1,187 @@
#include "etherShield.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,0x55,0x58,0x10,0x00,0x24};
static uint8_t myip[4] = {192,168,1,15};
static char baseurl[]="http://192.168.1.15/";
static uint16_t mywwwport =80; // listen port for tcp/www (max range 1-254)
// or on a different port:
//static char baseurl[]="http://10.0.0.24:88/";
//static uint16_t mywwwport =88; // listen port for tcp/www (max range 1-254)
//
#define BUFFER_SIZE 500
static uint8_t buf[BUFFER_SIZE+1];
#define STR_BUFFER_SIZE 22
static char strbuf[STR_BUFFER_SIZE+1];
EtherShield es=EtherShield();
// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf);
int8_t analyse_cmd(char *str);
void setup(){
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
// LEDA=greed LEDB=yellow
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x880 is PHLCON LEDB=on, LEDA=on
// enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x880);
delay(500);
//
// 0x990 is PHLCON LEDB=off, LEDA=off
// enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
es.ES_enc28j60PhyWrite(PHLCON,0x990);
delay(500);
//
// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
es.ES_enc28j60PhyWrite(PHLCON,0x476);
delay(100);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
}
void loop(){
uint16_t plen, dat_p;
int8_t cmd;
plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
/*plen will ne unequal to zero if there is a valid packet (without crc error) */
if(plen!=0){
// arp is broadcast if unknown but a host may also verify the mac address by sending it to a unicast address.
if(es.ES_eth_type_is_arp_and_my_ip(buf,plen)){
es.ES_make_arp_answer_from_request(buf);
return;
}
// check if ip packets are for us:
if(es.ES_eth_type_is_ip_and_my_ip(buf,plen)==0){
return;
}
if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
es.ES_make_echo_reply_from_request(buf,plen);
return;
}
// tcp port www start, compare only the lower byte
if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==mywwwport){
if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
es.ES_make_tcp_synack_from_syn(buf); // make_tcp_synack_from_syn does already send the syn,ack
return;
}
if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
es.ES_init_len_info(buf); // init some data structures
dat_p=es.ES_get_tcp_data_pointer();
if (dat_p==0){ // we can possibly have no data, just ack:
if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
es.ES_make_tcp_ack_from_any(buf);
}
return;
}
if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){
// head, post and other methods for possible status codes see:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));
goto SENDTCP;
}
if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){
plen=print_webpage(buf);
goto SENDTCP;
}
cmd=analyse_cmd((char *)&(buf[dat_p+5]));
if (cmd==1){
plen=print_webpage(buf);
}
SENDTCP: es.ES_make_tcp_ack_from_any(buf); // send ack for http get
es.ES_make_tcp_ack_with_data(buf,plen); // send data
}
}
}
}
// The returned value is stored in the global var strbuf
uint8_t find_key_val(char *str,char *key)
{
uint8_t found=0;
uint8_t i=0;
char *kp;
kp=key;
while(*str && *str!=' ' && found==0){
if (*str == *kp){
kp++;
if (*kp == '\0'){
str++;
kp=key;
if (*str == '='){
found=1;
}
}
}else{
kp=key;
}
str++;
}
if (found==1){
// copy the value to a buffer and terminate it with '\0'
while(*str && *str!=' ' && *str!='&' && i<STR_BUFFER_SIZE){
strbuf[i]=*str;
i++;
str++;
}
strbuf[i]='\0';
}
return(found);
}
int8_t analyse_cmd(char *str)
{
int8_t r=-1;
if (find_key_val(str,"cmd")){
if (*strbuf < 0x3a && *strbuf > 0x2f){
// is a ASCII number, return it
r=(*strbuf-0x30);
}
}
return r;
}
uint16_t print_webpage(uint8_t *buf)
{
uint16_t plen;
plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Arduino Ethernet Shield V1.0 </h1></p> "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr><br> <h2><font color=\"blue\">-- Put your ARDUINO online -- "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<br> Control digital outputs "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<br> Read digital analog inputs HERE "));
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(" <br></font></h2> ") );
plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</center><hr> V1.0 <a href=\"http://www.nuelectronics.com\">www.nuelectronics.com<a>"));
return(plen);
}

View file

@ -0,0 +1,714 @@
/*********************************************
* 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
* See http://www.gnu.org/licenses/gpl.html
*
* IP, Arp, UDP and TCP functions.
*
* The TCP implementation uses some size optimisations which are valid
* only if all data can be sent in one single packet. This is however
* not a big limitation for a microcontroller as you will anyhow use
* small web-pages. The TCP stack is therefore a SDP-TCP stack (single data packet TCP).
*
* Chip type : ATMEGA88 with ENC28J60
*********************************************/
/*********************************************
* Modified: nuelectronics.com -- Ethershield for Arduino
*********************************************/
#include <avr/io.h>
#include <avr/pgmspace.h>
//#include "avr_compat.h"
#include "net.h"
#include "enc28j60.h"
static uint8_t wwwport=80;
static uint8_t macaddr[6];
static uint8_t ipaddr[4];
static int16_t info_hdr_len=0;
static int16_t info_data_len=0;
static uint8_t seqnum=0xa; // my initial tcp sequence number
// The Ip checksum is calculated over the ip header only starting
// with the header length field and a total length of 20 bytes
// unitl ip.dst
// You must set the IP checksum field to zero before you start
// the calculation.
// len for ip is 20.
//
// For UDP/TCP we do not make up the required pseudo header. Instead we
// use the ip.src and ip.dst fields of the real packet:
// The udp checksum calculation starts with the ip.src field
// Ip.src=4bytes,Ip.dst=4 bytes,Udp header=8bytes + data length=16+len
// In other words the len here is 8 + length over which you actually
// want to calculate the checksum.
// You must set the checksum field to zero before you start
// the calculation.
// len for udp is: 8 + 8 + data length
// len for tcp is: 4+4 + 20 + option len + data length
//
// For more information on how this algorithm works see:
// http://www.netfor2.com/checksum.html
// http://www.msc.uky.edu/ken/cs471/notes/chap3.htm
// The RFC has also a C code example: http://www.faqs.org/rfcs/rfc1071.html
uint16_t checksum(uint8_t *buf, uint16_t len,uint8_t type){
// type 0=ip
// 1=udp
// 2=tcp
uint32_t sum = 0;
//if(type==0){
// // do not add anything
//}
if(type==1){
sum+=IP_PROTO_UDP_V; // protocol udp
// the length here is the length of udp (data+header len)
// =length given to this function - (IP.scr+IP.dst length)
sum+=len-8; // = real tcp len
}
if(type==2){
sum+=IP_PROTO_TCP_V;
// the length here is the length of tcp (data+header len)
// =length given to this function - (IP.scr+IP.dst length)
sum+=len-8; // = real tcp len
}
// build the sum of 16bit words
while(len >1){
sum += 0xFFFF & (*buf<<8|*(buf+1));
buf+=2;
len-=2;
}
// if there is a byte left then add it (padded with zero)
if (len){
sum += (0xFF & *buf)<<8;
}
// now calculate the sum over the bytes in the sum
// until the result is only 16bit long
while (sum>>16){
sum = (sum & 0xFFFF)+(sum >> 16);
}
// build 1's complement:
return( (uint16_t) sum ^ 0xFFFF);
}
// you must call this function once before you use any of the other functions:
void init_ip_arp_udp_tcp(uint8_t *mymac,uint8_t *myip,uint8_t wwwp){
uint8_t i=0;
wwwport=wwwp;
while(i<4){
ipaddr[i]=myip[i];
i++;
}
i=0;
while(i<6){
macaddr[i]=mymac[i];
i++;
}
}
uint8_t eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len){
uint8_t i=0;
//
if (len<41){
return(0);
}
if(buf[ETH_TYPE_H_P] != ETHTYPE_ARP_H_V ||
buf[ETH_TYPE_L_P] != ETHTYPE_ARP_L_V){
return(0);
}
while(i<4){
if(buf[ETH_ARP_DST_IP_P+i] != ipaddr[i]){
return(0);
}
i++;
}
return(1);
}
uint8_t eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len){
uint8_t i=0;
//eth+ip+udp header is 42
if (len<42){
return(0);
}
if(buf[ETH_TYPE_H_P]!=ETHTYPE_IP_H_V ||
buf[ETH_TYPE_L_P]!=ETHTYPE_IP_L_V){
return(0);
}
if (buf[IP_HEADER_LEN_VER_P]!=0x45){
// must be IP V4 and 20 byte header
return(0);
}
while(i<4){
if(buf[IP_DST_P+i]!=ipaddr[i]){
return(0);
}
i++;
}
return(1);
}
// make a return eth header from a received eth packet
void make_eth(uint8_t *buf)
{
uint8_t i=0;
//
//copy the destination mac from the source and fill my mac into src
while(i<6){
buf[ETH_DST_MAC +i]=buf[ETH_SRC_MAC +i];
buf[ETH_SRC_MAC +i]=macaddr[i];
i++;
}
}
// make a new eth header for IP packet
void make_eth_ip_new(uint8_t *buf, uint8_t* dst_mac)
{
uint8_t i=0;
//
//copy the destination mac from the source and fill my mac into src
while(i<6){
buf[ETH_DST_MAC +i]=dst_mac[i];
buf[ETH_SRC_MAC +i]=macaddr[i];
i++;
}
buf[ ETH_TYPE_H_P ] = ETHTYPE_IP_H_V;
buf[ ETH_TYPE_L_P ] = ETHTYPE_IP_L_V;
}
void fill_ip_hdr_checksum(uint8_t *buf)
{
uint16_t ck;
// clear the 2 byte checksum
buf[IP_CHECKSUM_P]=0;
buf[IP_CHECKSUM_P+1]=0;
buf[IP_FLAGS_P]=0x40; // don't fragment
buf[IP_FLAGS_P+1]=0; // fragement offset
buf[IP_TTL_P]=64; // ttl
// calculate the checksum:
ck=checksum(&buf[IP_P], IP_HEADER_LEN,0);
buf[IP_CHECKSUM_P]=ck>>8;
buf[IP_CHECKSUM_P+1]=ck& 0xff;
}
static uint16_t ip_identifier = 1;
// make a new ip header for tcp packet
// make a return ip header from a received ip packet
void make_ip_tcp_new(uint8_t *buf, uint16_t len,uint8_t *dst_ip)
{
uint8_t i=0;
// set ipv4 and header length
buf[ IP_P ] = IP_V4_V | IP_HEADER_LENGTH_V;
// set TOS to default 0x00
buf[ IP_TOS_P ] = 0x00;
// set total length
buf[ IP_TOTLEN_H_P ] = (len >>8)& 0xff;
buf[ IP_TOTLEN_L_P ] = len & 0xff;
// set packet identification
buf[ IP_ID_H_P ] = (ip_identifier >>8) & 0xff;
buf[ IP_ID_L_P ] = ip_identifier & 0xff;
ip_identifier++;
// set fragment flags
buf[ IP_FLAGS_H_P ] = 0x00;
buf[ IP_FLAGS_L_P ] = 0x00;
// set Time To Live
buf[ IP_TTL_P ] = 128;
// set ip packettype to tcp/udp/icmp...
buf[ IP_PROTO_P ] = IP_PROTO_TCP_V;
// set source and destination ip address
while(i<4){
buf[IP_DST_P+i]=dst_ip[i];
buf[IP_SRC_P+i]=ipaddr[i];
i++;
}
fill_ip_hdr_checksum(buf);
}
// make a return ip header from a received ip packet
void make_ip(uint8_t *buf)
{
uint8_t i=0;
while(i<4){
buf[IP_DST_P+i]=buf[IP_SRC_P+i];
buf[IP_SRC_P+i]=ipaddr[i];
i++;
}
fill_ip_hdr_checksum(buf);
}
// make a return tcp header from a received tcp packet
// rel_ack_num is how much we must step the seq number received from the
// other side. We do not send more than 255 bytes of text (=data) in the tcp packet.
// If mss=1 then mss is included in the options list
//
// After calling this function you can fill in the first data byte at TCP_OPTIONS_P+4
// If cp_seq=0 then an initial sequence number is used (should be use in synack)
// otherwise it is copied from the packet we received
void make_tcphead(uint8_t *buf,uint16_t rel_ack_num,uint8_t mss,uint8_t cp_seq)
{
uint8_t i=0;
uint8_t tseq;
while(i<2){
buf[TCP_DST_PORT_H_P+i]=buf[TCP_SRC_PORT_H_P+i];
buf[TCP_SRC_PORT_H_P+i]=0; // clear source port
i++;
}
// set source port (http):
buf[TCP_SRC_PORT_L_P]=wwwport;
i=4;
// sequence numbers:
// add the rel ack num to SEQACK
while(i>0){
rel_ack_num=buf[TCP_SEQ_H_P+i-1]+rel_ack_num;
tseq=buf[TCP_SEQACK_H_P+i-1];
buf[TCP_SEQACK_H_P+i-1]=0xff&rel_ack_num;
if (cp_seq){
// copy the acknum sent to us into the sequence number
buf[TCP_SEQ_H_P+i-1]=tseq;
}else{
buf[TCP_SEQ_H_P+i-1]= 0; // some preset vallue
}
rel_ack_num=rel_ack_num>>8;
i--;
}
if (cp_seq==0){
// put inital seq number
buf[TCP_SEQ_H_P+0]= 0;
buf[TCP_SEQ_H_P+1]= 0;
// we step only the second byte, this allows us to send packts
// with 255 bytes or 512 (if we step the initial seqnum by 2)
buf[TCP_SEQ_H_P+2]= seqnum;
buf[TCP_SEQ_H_P+3]= 0;
// step the inititial seq num by something we will not use
// during this tcp session:
seqnum+=2;
}
// zero the checksum
buf[TCP_CHECKSUM_H_P]=0;
buf[TCP_CHECKSUM_L_P]=0;
// The tcp header length is only a 4 bit field (the upper 4 bits).
// It is calculated in units of 4 bytes.
// E.g 24 bytes: 24/4=6 => 0x60=header len field
//buf[TCP_HEADER_LEN_P]=(((TCP_HEADER_LEN_PLAIN+4)/4)) <<4; // 0x60
if (mss){
// the only option we set is MSS to 1408:
// 1408 in hex is 0x580
buf[TCP_OPTIONS_P]=2;
buf[TCP_OPTIONS_P+1]=4;
buf[TCP_OPTIONS_P+2]=0x05;
buf[TCP_OPTIONS_P+3]=0x80;
// 24 bytes:
buf[TCP_HEADER_LEN_P]=0x60;
}else{
// no options:
// 20 bytes:
buf[TCP_HEADER_LEN_P]=0x50;
}
}
void make_arp_answer_from_request(uint8_t *buf)
{
uint8_t i=0;
//
make_eth(buf);
buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V;
buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V;
// fill the mac addresses:
while(i<6){
buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i];
buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i];
i++;
}
i=0;
while(i<4){
buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i];
buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
i++;
}
// eth+arp is 42 bytes:
enc28j60PacketSend(42,buf);
}
void make_echo_reply_from_request(uint8_t *buf,uint16_t len)
{
make_eth(buf);
make_ip(buf);
buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;
// we changed only the icmp.type field from request(=8) to reply(=0).
// we can therefore easily correct the checksum:
if (buf[ICMP_CHECKSUM_P] > (0xff-0x08)){
buf[ICMP_CHECKSUM_P+1]++;
}
buf[ICMP_CHECKSUM_P]+=0x08;
//
enc28j60PacketSend(len,buf);
}
// you can send a max of 220 bytes of data
void make_udp_reply_from_request(uint8_t *buf,char *data,uint8_t datalen,uint16_t port)
{
uint8_t i=0;
uint16_t ck;
make_eth(buf);
if (datalen>220){
datalen=220;
}
// total length field in the IP header must be set:
buf[IP_TOTLEN_H_P]=0;
buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
make_ip(buf);
buf[UDP_DST_PORT_H_P]=port>>8;
buf[UDP_DST_PORT_L_P]=port & 0xff;
// source port does not matter and is what the sender used.
// calculte the udp length:
buf[UDP_LEN_H_P]=0;
buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
// zero the checksum
buf[UDP_CHECKSUM_H_P]=0;
buf[UDP_CHECKSUM_L_P]=0;
// copy the data:
while(i<datalen){
buf[UDP_DATA_P+i]=data[i];
i++;
}
ck=checksum(&buf[IP_SRC_P], 16 + datalen,1);
buf[UDP_CHECKSUM_H_P]=ck>>8;
buf[UDP_CHECKSUM_L_P]=ck& 0xff;
enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
}
void make_tcp_synack_from_syn(uint8_t *buf)
{
uint16_t ck;
make_eth(buf);
// total length field in the IP header must be set:
// 20 bytes IP + 24 bytes (20tcp+4tcp options)
buf[IP_TOTLEN_H_P]=0;
buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
make_ip(buf);
buf[TCP_FLAG_P]=TCP_FLAGS_SYNACK_V;
make_tcphead(buf,1,1,0);
// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + 4 (one option: mss)
ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2);
buf[TCP_CHECKSUM_H_P]=ck>>8;
buf[TCP_CHECKSUM_L_P]=ck& 0xff;
// add 4 for option mss:
enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
}
// get a pointer to the start of tcp data in buf
// Returns 0 if there is no data
// You must call init_len_info once before calling this function
uint16_t get_tcp_data_pointer(void)
{
if (info_data_len){
return((uint16_t)TCP_SRC_PORT_H_P+info_hdr_len);
}else{
return(0);
}
}
// do some basic length calculations and store the result in static varibales
void init_len_info(uint8_t *buf)
{
info_data_len=(buf[IP_TOTLEN_H_P]<<8)|(buf[IP_TOTLEN_L_P]&0xff);
info_data_len-=IP_HEADER_LEN;
info_hdr_len=(buf[TCP_HEADER_LEN_P]>>4)*4; // generate len in bytes;
info_data_len-=info_hdr_len;
if (info_data_len<=0){
info_data_len=0;
}
}
// fill in tcp data at position pos. pos=0 means start of
// tcp data. Returns the position at which the string after
// this string could be filled.
uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s)
{
char c;
// fill in tcp data at position pos
//
// with no options the data starts after the checksum + 2 more bytes (urgent ptr)
while ((c = pgm_read_byte(progmem_s++))) {
buf[TCP_CHECKSUM_L_P+3+pos]=c;
pos++;
}
return(pos);
}
// fill in tcp data at position pos. pos=0 means start of
// tcp data. Returns the position at which the string after
// this string could be filled.
uint16_t fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s)
{
// fill in tcp data at position pos
//
// with no options the data starts after the checksum + 2 more bytes (urgent ptr)
while (*s) {
buf[TCP_CHECKSUM_L_P+3+pos]=*s;
pos++;
s++;
}
return(pos);
}
// Make just an ack packet with no tcp data inside
// This will modify the eth/ip/tcp header
void make_tcp_ack_from_any(uint8_t *buf)
{
uint16_t j;
make_eth(buf);
// fill the header:
buf[TCP_FLAG_P]=TCP_FLAG_ACK_V;
if (info_data_len==0){
// if there is no data then we must still acknoledge one packet
make_tcphead(buf,1,0,1); // no options
}else{
make_tcphead(buf,info_data_len,0,1); // no options
}
// total length field in the IP header must be set:
// 20 bytes IP + 20 bytes tcp (when no options)
j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
buf[IP_TOTLEN_H_P]=j>>8;
buf[IP_TOTLEN_L_P]=j& 0xff;
make_ip(buf);
// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
buf[TCP_CHECKSUM_H_P]=j>>8;
buf[TCP_CHECKSUM_L_P]=j& 0xff;
enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
}
// you must have called init_len_info at some time before calling this function
// dlen is the amount of tcp data (http data) we send in this packet
// You can use this function only immediately after make_tcp_ack_from_any
// This is because this function will NOT modify the eth/ip/tcp header except for
// length and checksum
void make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen)
{
uint16_t j;
// fill the header:
// This code requires that we send only one data packet
// because we keep no state information. We must therefore set
// the fin here:
buf[TCP_FLAG_P]=TCP_FLAG_ACK_V|TCP_FLAG_PUSH_V|TCP_FLAG_FIN_V;
// total length field in the IP header must be set:
// 20 bytes IP + 20 bytes tcp (when no options) + len of data
j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
buf[IP_TOTLEN_H_P]=j>>8;
buf[IP_TOTLEN_L_P]=j& 0xff;
fill_ip_hdr_checksum(buf);
// zero the checksum
buf[TCP_CHECKSUM_H_P]=0;
buf[TCP_CHECKSUM_L_P]=0;
// calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlen,2);
buf[TCP_CHECKSUM_H_P]=j>>8;
buf[TCP_CHECKSUM_L_P]=j& 0xff;
enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN,buf);
}
/* new functions for web client interface */
void make_arp_request(uint8_t *buf, uint8_t *server_ip)
{
uint8_t i=0;
while(i<6)
{
buf[ETH_DST_MAC +i]=0xff;
buf[ETH_SRC_MAC +i]=macaddr[i];
i++;
}
buf[ ETH_TYPE_H_P ] = ETHTYPE_ARP_H_V;
buf[ ETH_TYPE_L_P ] = ETHTYPE_ARP_L_V;
// generate arp packet
buf[ARP_OPCODE_H_P]=ARP_OPCODE_REQUEST_H_V;
buf[ARP_OPCODE_L_P]=ARP_OPCODE_REQUEST_L_V;
// fill in arp request packet
// setup hardware type to ethernet 0x0001
buf[ ARP_HARDWARE_TYPE_H_P ] = ARP_HARDWARE_TYPE_H_V;
buf[ ARP_HARDWARE_TYPE_L_P ] = ARP_HARDWARE_TYPE_L_V;
// setup protocol type to ip 0x0800
buf[ ARP_PROTOCOL_H_P ] = ARP_PROTOCOL_H_V;
buf[ ARP_PROTOCOL_L_P ] = ARP_PROTOCOL_L_V;
// setup hardware length to 0x06
buf[ ARP_HARDWARE_SIZE_P ] = ARP_HARDWARE_SIZE_V;
// setup protocol length to 0x04
buf[ ARP_PROTOCOL_SIZE_P ] = ARP_PROTOCOL_SIZE_V;
// setup arp destination and source mac address
for ( i=0; i<6; i++)
{
buf[ ARP_DST_MAC_P + i ] = 0x00;
buf[ ARP_SRC_MAC_P + i ] = macaddr[i];
}
// setup arp destination and source ip address
for ( i=0; i<4; i++)
{
buf[ ARP_DST_IP_P + i ] = server_ip[i];
buf[ ARP_SRC_IP_P + i ] = ipaddr[i];
}
// eth+arp is 42 bytes:
enc28j60PacketSend(42,buf);
}
uint8_t arp_packet_is_myreply_arp ( uint8_t *buf )
{
uint8_t i;
// if packet type is not arp packet exit from function
if( buf[ ETH_TYPE_H_P ] != ETHTYPE_ARP_H_V || buf[ ETH_TYPE_L_P ] != ETHTYPE_ARP_L_V)
return 0;
// check arp request opcode
if ( buf[ ARP_OPCODE_H_P ] != ARP_OPCODE_REPLY_H_V || buf[ ARP_OPCODE_L_P ] != ARP_OPCODE_REPLY_L_V )
return 0;
// if destination ip address in arp packet not match with avr ip address
for(i=0; i<4; i++){
if(buf[ETH_ARP_DST_IP_P+i] != ipaddr[i]){
return 0;
}
}
return 1;
}
// make a tcp header
void tcp_client_send_packet(uint8_t *buf,uint16_t dest_port, uint16_t src_port, uint8_t flags, uint8_t max_segment_size,
uint8_t clear_seqack, uint16_t next_ack_num, uint16_t dlength, uint8_t *dest_mac, uint8_t *dest_ip)
{
uint8_t i=0;
uint8_t tseq;
uint16_t ck;
make_eth_ip_new(buf, dest_mac);
buf[TCP_DST_PORT_H_P]= (uint8_t) ( (dest_port>>8) & 0xff);
buf[TCP_DST_PORT_L_P]= (uint8_t) (dest_port & 0xff);
buf[TCP_SRC_PORT_H_P]= (uint8_t) ( (src_port>>8) & 0xff);
buf[TCP_SRC_PORT_L_P]= (uint8_t) (src_port & 0xff);
// sequence numbers:
// add the rel ack num to SEQACK
if(next_ack_num)
{
for(i=4; i>0; i--)
{
next_ack_num=buf[TCP_SEQ_H_P+i-1]+next_ack_num;
tseq=buf[TCP_SEQACK_H_P+i-1];
buf[TCP_SEQACK_H_P+i-1]=0xff&next_ack_num;
// copy the acknum sent to us into the sequence number
buf[TCP_SEQ_P + i - 1 ] = tseq;
next_ack_num>>=8;
}
}
// initial tcp sequence number,require to setup for first transmit/receive
if(max_segment_size)
{
// put inital seq number
buf[TCP_SEQ_H_P+0]= 0;
buf[TCP_SEQ_H_P+1]= 0;
// we step only the second byte, this allows us to send packts
// with 255 bytes or 512 (if we step the initial seqnum by 2)
buf[TCP_SEQ_H_P+2]= seqnum;
buf[TCP_SEQ_H_P+3]= 0;
// step the inititial seq num by something we will not use
// during this tcp session:
seqnum+=2;
// setup maximum segment size
buf[TCP_OPTIONS_P]=2;
buf[TCP_OPTIONS_P+1]=4;
buf[TCP_OPTIONS_P+2]=0x05;
buf[TCP_OPTIONS_P+3]=0x80;
// 24 bytes:
buf[TCP_HEADER_LEN_P]=0x60;
dlength +=4;
}
else{
// no options:
// 20 bytes:
buf[TCP_HEADER_LEN_P]=0x50;
}
make_ip_tcp_new(buf,IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlength, dest_ip);
// clear sequence ack numer before send tcp SYN packet
if(clear_seqack)
{
buf[TCP_SEQACK_P] = 0;
buf[TCP_SEQACK_P+1] = 0;
buf[TCP_SEQACK_P+2] = 0;
buf[TCP_SEQACK_P+3] = 0;
}
// zero the checksum
buf[TCP_CHECKSUM_H_P]=0;
buf[TCP_CHECKSUM_L_P]=0;
// set up flags
buf[TCP_FLAG_P] = flags;
// setup maximum windows size
buf[ TCP_WINDOWSIZE_H_P ] = ((600 - IP_HEADER_LEN - ETH_HEADER_LEN)>>8) & 0xff;
buf[ TCP_WINDOWSIZE_L_P ] = (600 - IP_HEADER_LEN - ETH_HEADER_LEN) & 0xff;
// setup urgend pointer (not used -> 0)
buf[ TCP_URGENT_PTR_H_P ] = 0;
buf[ TCP_URGENT_PTR_L_P ] = 0;
// check sum
ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlength,2);
buf[TCP_CHECKSUM_H_P]=ck>>8;
buf[TCP_CHECKSUM_L_P]=ck& 0xff;
// add 4 for option mss:
enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlength+ETH_HEADER_LEN,buf);
}
uint16_t tcp_get_dlength ( uint8_t *buf )
{
int dlength, hlength;
dlength = ( buf[ IP_TOTLEN_H_P ] <<8 ) | ( buf[ IP_TOTLEN_L_P ] );
dlength -= IP_HEADER_LEN;
hlength = (buf[ TCP_HEADER_LEN_P ]>>4) * 4; // generate len in bytes;
dlength -= hlength;
if ( dlength <= 0 )
dlength=0;
return ((uint16_t)dlength);
}
/* end of ip_arp_udp.c */

View file

@ -0,0 +1,44 @@
/*********************************************
* 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
*
* IP/ARP/UDP/TCP functions
*
* Chip type : ATMEGA88 with ENC28J60
*********************************************/
/*********************************************
* Modified: nuelectronics.com -- Ethershield for Arduino
*********************************************/
//@{
#ifndef IP_ARP_UDP_TCP_H
#define IP_ARP_UDP_TCP_H
#include <avr/pgmspace.h>
// you must call this function once before you use any of the other functions:
extern void init_ip_arp_udp_tcp(uint8_t *mymac,uint8_t *myip,uint8_t wwwp);
//
extern uint8_t eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len);
extern uint8_t eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len);
extern void make_arp_answer_from_request(uint8_t *buf);
extern void make_echo_reply_from_request(uint8_t *buf,uint16_t len);
extern void make_udp_reply_from_request(uint8_t *buf,char *data,uint8_t datalen,uint16_t port);
extern void make_tcp_synack_from_syn(uint8_t *buf);
extern void init_len_info(uint8_t *buf);
extern uint16_t get_tcp_data_pointer(void);
extern uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s);
extern uint16_t fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s);
extern void make_tcp_ack_from_any(uint8_t *buf);
extern void make_tcp_ack_with_data(uint8_t *buf,uint16_t dlen);
extern void make_arp_request(uint8_t *buf, uint8_t *server_ip);
extern uint8_t arp_packet_is_myreply_arp ( uint8_t *buf );
extern void tcp_client_send_packet(uint8_t *buf,uint16_t dest_port, uint16_t src_port, uint8_t flags, uint8_t max_segment_size,
uint8_t clear_seqck, uint16_t next_ack_num, uint16_t dlength, uint8_t *dest_mac, uint8_t *dest_ip);
extern uint16_t tcp_get_dlength ( uint8_t *buf );
#endif /* IP_ARP_UDP_TCP_H */
//@}

View file

@ -0,0 +1,39 @@
#######################################
# Syntax Coloring Map For Matrix
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
EtherShield KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
ES_fill_tcp_data_p KEYWORD2
ES_fill_tcp_data KEYWORD2
ES_enc28j60Init KEYWORD2
ES_enc28j60clkout KEYWORD2
ES_enc28j60PhyWrite KEYWORD2
ES_enc28j60PacketReceive KEYWORD2
ES_init_ip_arp_udp_tcp KEYWORD2
ES_eth_type_is_arp_and_my_ip KEYWORD2
ES_make_arp_answer_from_request KEYWORD2
ES_eth_type_is_ip_and_my_ip KEYWORD2
ES_make_echo_reply_from_request KEYWORD2
ES_make_tcp_synack_from_syn KEYWORD2
ES_init_len_info KEYWORD2
ES_get_tcp_data_pointer KEYWORD2
ES_make_tcp_ack_from_any KEYWORD2
ES_make_tcp_ack_with_data KEYWORD2
ES_make_arp_request KEYWORD2
ES_arp_packet_is_myreply_arp KEYWORD2
ES_tcp_client_send_packet KEYWORD2
ES_tcp_get_dlength KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

177
libraries/etherShield/net.h Normal file
View file

@ -0,0 +1,177 @@
/*********************************************
* 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
*
* Based on the net.h file from the AVRlib library by Pascal Stang.
* For AVRlib See http://www.procyonengineering.com/
* Used with explicit permission of Pascal Stang.
*
* Chip type : ATMEGA88 with ENC28J60
*********************************************/
/*********************************************
* Modified: nuelectronics.com -- Ethershield for Arduino
*********************************************/
// notation: _P = position of a field
// _V = value of a field
//@{
#ifndef NET_H
#define NET_H
// ******* ETH *******
#define ETH_HEADER_LEN 14
// values of certain bytes:
#define ETHTYPE_ARP_H_V 0x08
#define ETHTYPE_ARP_L_V 0x06
#define ETHTYPE_IP_V 0x0800
#define ETHTYPE_IP_H_V 0x08
#define ETHTYPE_IP_L_V 0x00
// byte positions in the ethernet frame:
//
// Ethernet type field (2bytes):
#define ETH_TYPE_H_P 12
#define ETH_TYPE_L_P 13
//
#define ETH_DST_MAC 0
#define ETH_SRC_MAC 6
// ******* ARP *******
#define ETH_ARP_OPCODE_REPLY_H_V 0x0
#define ETH_ARP_OPCODE_REPLY_L_V 0x02
//
#define ETHTYPE_ARP_L_V 0x06
// arp.dst.ip
#define ETH_ARP_DST_IP_P 0x26
// arp.opcode
#define ETH_ARP_OPCODE_H_P 0x14
#define ETH_ARP_OPCODE_L_P 0x15
// arp.src.mac
#define ETH_ARP_SRC_MAC_P 0x16
#define ETH_ARP_SRC_IP_P 0x1c
#define ETH_ARP_DST_MAC_P 0x20
#define ETH_ARP_DST_IP_P 0x26
#define ARP_OPCODE_REQUEST_H_V 0x00
#define ARP_OPCODE_REQUEST_L_V 0x01
#define ARP_OPCODE_REPLY_H_V 0x00
#define ARP_OPCODE_REPLY_L_V 0x02
#define ARP_HARDWARE_TYPE_H_V 0x00
#define ARP_HARDWARE_TYPE_L_V 0x01
#define ARP_PROTOCOL_H_V 0x08
#define ARP_PROTOCOL_L_V 0x00
#define ARP_HARDWARE_SIZE_V 0x06
#define ARP_PROTOCOL_SIZE_V 0x04
#define ARP_HARDWARE_TYPE_H_P 0x0E
#define ARP_HARDWARE_TYPE_L_P 0x0F
#define ARP_PROTOCOL_H_P 0x10
#define ARP_PROTOCOL_L_P 0x11
#define ARP_HARDWARE_SIZE_P 0x12
#define ARP_PROTOCOL_SIZE_P 0x13
#define ARP_OPCODE_H_P 0x14
#define ARP_OPCODE_L_P 0x15
#define ARP_SRC_MAC_P 0x16
#define ARP_SRC_IP_P 0x1C
#define ARP_DST_MAC_P 0x20
#define ARP_DST_IP_P 0x26
// ******* IP *******
#define IP_HEADER_LEN 20
#define IP_PROTO_ICMP_V 0x01
#define IP_PROTO_TCP_V 0x06
#define IP_PROTO_UDP_V 0x11
#define IP_V4_V 0x40
#define IP_HEADER_LENGTH_V 0x05
#define IP_P 0x0E
#define IP_HEADER_VER_LEN_P 0x0E
#define IP_TOS_P 0x0F
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11
#define IP_ID_H_P 0x12
#define IP_ID_L_P 0x13
#define IP_FLAGS_P 0x14
#define IP_FLAGS_H_P 0x14
#define IP_FLAGS_L_P 0x15
#define IP_TTL_P 0x16
#define IP_PROTO_P 0x17
#define IP_CHECKSUM_P 0x18
#define IP_CHECKSUM_H_P 0x18
#define IP_CHECKSUM_L_P 0x19
#define IP_SRC_IP_P 0x1A
#define IP_DST_IP_P 0x1E
#define IP_SRC_P 0x1a
#define IP_DST_P 0x1e
#define IP_HEADER_LEN_VER_P 0xe
// ******* ICMP *******
#define ICMP_TYPE_ECHOREPLY_V 0
#define ICMP_TYPE_ECHOREQUEST_V 8
//
#define ICMP_TYPE_P 0x22
#define ICMP_CHECKSUM_P 0x24
// ******* UDP *******
#define UDP_HEADER_LEN 8
//
#define UDP_SRC_PORT_H_P 0x22
#define UDP_SRC_PORT_L_P 0x23
#define UDP_DST_PORT_H_P 0x24
#define UDP_DST_PORT_L_P 0x25
//
#define UDP_LEN_H_P 0x26
#define UDP_LEN_L_P 0x27
#define UDP_CHECKSUM_H_P 0x28
#define UDP_CHECKSUM_L_P 0x29
#define UDP_DATA_P 0x2a
// ******* TCP *******
// plain len without the options:
#define TCP_HEADER_LEN_PLAIN 20
#define TCP_FLAG_FIN_V 0x01
#define TCP_FLAGS_FIN_V 0x01
#define TCP_FLAGS_SYN_V 0x02
#define TCP_FLAG_SYN_V 0x02
#define TCP_FLAG_RST_V 0x04
#define TCP_FLAG_PUSH_V 0x08
#define TCP_FLAGS_ACK_V 0x10
#define TCP_FLAG_ACK_V 0x10
#define TCP_FLAG_URG_V 0x20
#define TCP_FLAG_ECE_V 0x40
#define TCP_FLAG_CWR_V 0x80
#define TCP_FLAGS_SYNACK_V 0x12
#define TCP_SRC_PORT_H_P 0x22
#define TCP_SRC_PORT_L_P 0x23
#define TCP_DST_PORT_H_P 0x24
#define TCP_DST_PORT_L_P 0x25
#define TCP_SEQ_P 0x26 // the tcp seq number is 4 bytes 0x26-0x29
#define TCP_SEQ_H_P 0x26
#define TCP_SEQACK_P 0x2A // 4 bytes
#define TCP_SEQACK_H_P 0x2A
#define TCP_HEADER_LEN_P 0x2E
#define TCP_FLAGS_P 0x2F
#define TCP_FLAG_P 0x2F
#define TCP_WINDOWSIZE_H_P 0x30 // 2 bytes
#define TCP_WINDOWSIZE_L_P 0x31
#define TCP_CHECKSUM_H_P 0x32
#define TCP_CHECKSUM_L_P 0x33
#define TCP_URGENT_PTR_H_P 0x34 // 2 bytes
#define TCP_URGENT_PTR_L_P 0x35
#define TCP_OPTIONS_P 0x36
#define TCP_DATA_P 0x36
//
#endif
//@}

1
libraries/readme.txt Normal file
View file

@ -0,0 +1 @@
For information on installing libraries, see: http://arduino.cc/en/Guide/Libraries