1
0
Fork 0

initial import of the ENC28J60 soft for the Arduino :: Ethduino

git-svn-id: svn+ssh://oldsvn/home/mlalondesvn/svn/Ethduino@1 b05466c9-153a-0410-ad00-ea1d4d8a27b5
master
mlalondesvn 17 years ago
commit cff122808a

@ -0,0 +1,375 @@
# Arduino makefile
#
# This makefile allows you to build sketches from the command line
# without the Arduino environment (or Java).
# Previous work on this file was done by mellis, eighthave and probably
# many others.
#
# Last State: 28.08.2007 | 15:00 CEST
# -- oli.keller ][ gmail.com
#
# This is a fork of the original makefiles shipped with Arduino 0009.
# It tries to reassemble the preprocessing which the Arduino IDE does.
# This makefile even allows to create an automatic reset,
# like the Arduino IDE does on an Arduino Diecimila board!
# No no, you don't have to push that tiny button again and again... ;)
#
# You should only have to check the first six variables below for
# propper settings. That's it.
#
#
# Detailed instructions for using the makefile:
#
# 1. Copy this file into the folder with your sketch. There should be a
# file with the ending .pde (e.g. foo.pde)
#
# 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 "INSTALL_DIR" to point to the directory that
# contains the Arduino installation (for Arduino installations in
# Mac OSX, this could be /Applications/arduino-0009 ).
#
# 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. Set the line containing "MCU" to match your board's processor.
# Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth
# or Diecimila have the atmega168.
#
# 6. At the command line, change to the directory containing your
# program's file and the makefile.
#
# 7. Type "make" and press enter to compile/verify your program.
# In TextMate you can just hit Command-R to trigger make.
#
# 8. Type "make upload", reset your Arduino board, and press enter to
# upload your program to the Arduino board.
#
# $Id$
###############################################################################
#
# project specific settings
#
TARGET = main
ARDUINO_VERSION = 0009
INSTALL_DIR = /Applications/arduino-$(ARDUINO_VERSION)
###############################################################################
###############################################################################
#
# serial uploader settings
#
PORT = /dev/tty.usbserial-A*
UPLOAD_RATE = 19200
AVRDUDE_PROGRAMMER = stk500
# HINT: If you want to use the automatic reset feature which comes with Arduino
# Diecimila, put the follwoing in your avrdude.conf:
# (Use the systemwide $(INSTALL_DIR)/tools/avr/etc/avrdude.conf or create a
# local $HOME/.avrduderc file)
#
# programmer
# id = "arduino";
# desc = "Arduino Serial Bootloader";
# type = stk500;
# reset = 7;
# # since Arduino Diecimila the serial DTR line can be used to trigger a reset!
# ;
#
# After this you can specify AVRDUDE_PROGRAMMER = arduino, above.
# On older boards you can manually ad this reset feature. Wire a cable from the
# FTDI 232 Chip's DTR pin (the number differs from package to package, see datasheet)
# to the RESET line of the ATmega. Inbetween this connection must be a 100nF capacitor.
#####################################################################################
#####################################################################################
#
# hardware dependent settings
#
MCU = atmega168
F_CPU = 16000000
# F_CPU sets the clock speed in Hz. So far its 16MHz on all standard boards.
#####################################################################################
#####################################################################################
#
# Below here nothing should be changed...
#
#####################################################################################
ARDUINO = $(INSTALL_DIR)/lib/targets/arduino
#AVR_TOOLS_PATH = $(INSTALL_DIR)/tools/avr/bin
AVR_TOOLS_PATH = /usr/local/bin
#
# Arduino & Wiring libraries
############################
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
CXXSRC+= programStrings.cpp
#
# Procyon AVRLib libraries
##########################
# Base
CXXSRC+= debug.cpp
#CXXSRC+= buffer.cpp
#CXXSRC+= timer.cpp
#CXXSRC+= timerx8.cpp
#CXXSRC+= timer128.cpp
# Net
CXXSRC+= netstack.cpp
CXXSRC+= ip.cpp
CXXSRC+= arp.cpp
CXXSRC+= icmp.cpp
CXXSRC+= net.cpp
# CXXSRC+= dhcp.cpp
# Driver
CXXSRC+=enc28j60.cpp
##################
# End of libraries
FORMAT = ihex
# 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_PORT = $(PORT)
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
#AVRDUDE_FLAGS = -V -F -C $(INSTALL_DIR)/tools/avr/etc/avrdude.conf -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
AVRDUDE_FLAGS = -F -C $(INSTALL_DIR)/tools/avr/etc/avrdude.conf -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
# Program settings
CC = $(AVR_TOOLS_PATH)/avr-gcc
CXX = $(AVR_TOOLS_PATH)/avr-g++
OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy
OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump
AR = $(AVR_TOOLS_PATH)/avr-ar
SIZE = $(AVR_TOOLS_PATH)/avr-size
NM = $(AVR_TOOLS_PATH)/avr-nm
# AVRDUDE = $(AVR_TOOLS_PATH)/avrdude
#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: applet_files build sizeafter
build: elf hex bin s
applet_files: $(TARGET).pde
#
# Here is the "preprocessing".
# It creates a .cpp file based with the same name as the .pde file.
# On top of the new .cpp file comes the WProgram.h header.
# At the end there is a generic main() function attached.
# The ne .cpp file will be compiled. Errors during compile will
# refer to this new, automatically generated, file.
# Not the original .pde file you actually edit...
#
test -d applet || mkdir applet
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
echo '#include "HardwareSerial.h"' >> applet/$(TARGET).cpp
cat $(TARGET).pde >> applet/$(TARGET).cpp
echo >> applet/$(TARGET).cpp
echo >> applet/$(TARGET).cpp
echo '/**' >> applet/$(TARGET).cpp
echo ' * Main program function' >> applet/$(TARGET).cpp
echo ' * (Autogenerated!)' >> applet/$(TARGET).cpp
echo '**/' >> applet/$(TARGET).cpp
echo 'int main(void)' >> applet/$(TARGET).cpp
echo '{' >> applet/$(TARGET).cpp
echo ' init();' >> applet/$(TARGET).cpp
echo >> applet/$(TARGET).cpp
echo ' // Call user setup' >> applet/$(TARGET).cpp
echo ' setup();' >> applet/$(TARGET).cpp
echo >> applet/$(TARGET).cpp
echo ' // Call user main loop' >> applet/$(TARGET).cpp
echo ' for (;;)' >> applet/$(TARGET).cpp
echo ' loop();' >> applet/$(TARGET).cpp
echo ' init();' >> applet/$(TARGET).cpp
echo ' return 0;' >> applet/$(TARGET).cpp
echo '}' >> applet/$(TARGET).cpp
elf: applet/$(TARGET).elf
hex: applet/$(TARGET).hex
bin: applet/$(TARGET).bin
eep: applet/$(TARGET).eep
lss: applet/$(TARGET).lss
s: applet/$(TARGET).s
# Program the device.
upload: applet/$(TARGET).hex
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex
ELFSIZE = $(SIZE) applet/$(TARGET).elf
sizebefore:
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi
sizeafter:
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi
# 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: applet/$(TARGET).elf
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym .bin .s
.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 $< > $@
.elf.bin:
$(OBJCOPY) -O $(FORMAT) applet/$(TARGET).elf applet/$(TARGET).bin
# Link: create ELF output file from library.
applet/$(TARGET).elf: $(TARGET).pde applet/core.a
$(CC) $(ALL_CFLAGS) -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS)
applet/core.a: $(OBJ)
@for i in $(OBJ); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done
# 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.
.cpp.s:
$(CXX) -S $(ALL_CXXFLAGS) $< -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) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \
applet/$(TARGET).s applet/$(TARGET).cpp applet/$(TARGET).bin \
applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/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 applet_files sizebefore sizeafter

@ -0,0 +1,235 @@
/*! \file arp.c \brief ARP Protocol Library. */
//*****************************************************************************
//
// File Name : 'arp.c'
// Title : ARP Protocol Library
// Author : Pascal Stang
// Created : 9/7/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include "net.h"
#include "nic.h"
#include "arp.h"
#include "HardwareSerial.h"
#ifdef ARP_DEBUG_PRINT
#include "debug.h"
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "HardwareSerial.h"
#endif
// global variables
/// Single ARP table entry/record
struct ArpEntry
{
uint32_t ipaddr; ///< remote-note IP address
struct netEthAddr ethaddr; ///< remote-node ethernet (hardware/mac) address
uint8_t time; ///< time to live (in ARP table); this is decremented by arpTimer()
};
struct ArpEntry ArpMyAddr; ///< my local interface information (IP and MAC address)
struct ArpEntry ArpTable[ARP_TABLE_SIZE]; ///< ARP table of matched IP<->MAC associations
void arpInit(void)
{
u08 i;
// initialize all ArpTable elements to unused
for(i=0; i<ARP_TABLE_SIZE; i++)
{
ArpTable[i].ipaddr = 0;
ArpTable[i].time = 0;
}
}
void arpSetAddress(struct netEthAddr* myeth, uint32_t myip)
{
// set local address record
ArpMyAddr.ethaddr = *myeth;
ArpMyAddr.ipaddr = myip;
}
void arpArpIn(unsigned int len, struct netEthArpHeader* packet)
{
#ifdef ARP_DEBUG
SPrint_P(PSTR("Received ARP Request\r\n"));
arpPrintHeader( &packet->arp );
#endif
// for now, we just reply to requests
// need to add ARP cache
if( (packet->arp.dipaddr == HTONL(ArpMyAddr.ipaddr)) &&
(packet->arp.opcode == htons(ARP_OPCODE_REQUEST)) )
{
// in ARP header
// copy sender's address info to dest. fields
packet->arp.dhwaddr = packet->arp.shwaddr;
packet->arp.dipaddr = packet->arp.sipaddr;
// fill in our information
packet->arp.shwaddr = ArpMyAddr.ethaddr;
packet->arp.sipaddr = HTONL(ArpMyAddr.ipaddr);
// change op to reply
packet->arp.opcode = htons(ARP_OPCODE_REPLY);
// in ethernet header
packet->eth.dest = packet->eth.src;
packet->eth.src = ArpMyAddr.ethaddr;
#ifdef ARP_DEBUG
SPrint_P(PSTR("Sending ARP Reply\r\n"));
arpPrintHeader( &packet->arp );
#endif
// send reply!
nicSend(len, (unsigned char*)packet);
}
}
void arpIpIn(struct netEthIpHeader* packet)
{
int8_t index;
// check if sender is already present in arp table
index = arpMatchIp(HTONL(packet->ip.srcipaddr));
if(index != -1)
{
// sender's IP address found, update ARP entry
ArpTable[index].ethaddr = packet->eth.src;
// and we're done
return;
}
// sender was not present in table,
// must add in empty/expired slot
for(index=0; index<ARP_TABLE_SIZE; index++)
{
if(!ArpTable[index].time)
{
// write entry
ArpTable[index].ethaddr = packet->eth.src;
ArpTable[index].ipaddr = HTONL(packet->ip.srcipaddr);
ArpTable[index].time = ARP_CACHE_TIME_TO_LIVE;
// and we're done
return;
}
}
// no space in table, we give up
}
void arpIpOut(struct netEthIpHeader* packet, uint32_t phyDstIp)
{
int index;
// check if destination is already present in arp table
// use the physical dstIp if it's provided, otherwise the dstIp in packet
if(phyDstIp)
index = arpMatchIp(phyDstIp);
else
index = arpMatchIp(HTONL(packet->ip.destipaddr));
// fill in ethernet info
if(index != -1)
{
// ARP entry present, fill eth address(es)
packet->eth.src = ArpMyAddr.ethaddr;
packet->eth.dest = ArpTable[index].ethaddr;
packet->eth.type = HTONS(ETHTYPE_IP);
}
else
{
// not in table, must send ARP request
packet->eth.src = ArpMyAddr.ethaddr;
// MUST CHANGE, but for now, send this one broadcast
packet->eth.dest.addr[0] = 0xFF;
packet->eth.dest.addr[1] = 0xFF;
packet->eth.dest.addr[2] = 0xFF;
packet->eth.dest.addr[3] = 0xFF;
packet->eth.dest.addr[4] = 0xFF;
packet->eth.dest.addr[5] = 0xFF;
packet->eth.type = HTONS(ETHTYPE_IP);
}
}
void arpTimer(void)
{
int index;
// this function meant to be called on a regular time interval
// decrement time-to-live for all entries
for(index=0; index<ARP_TABLE_SIZE; index++)
{
if(ArpTable[index].time)
ArpTable[index].time--;
}
}
int arpMatchIp(uint32_t ipaddr)
{
uint8_t i;
// check if IP address is present in arp table
for(i=0; i<ARP_TABLE_SIZE; i++)
{
if(ArpTable[i].ipaddr == ipaddr)
{
// IP address found
return i;
}
}
// no match
return -1;
}
#ifdef ARP_DEBUG_PRINT
void arpPrintHeader(struct netArpHeader* packet)
{
SPrint_P(PSTR("ARP Packet:\r\n"));
#if NET_DEBUG > 6
debugPrintHexTable(60, (unsigned char*)&packet);
#endif
// print operation type
SPrint_P(PSTR("Operation : "));
if(packet->opcode == htons(ARP_OPCODE_REQUEST))
SPrint_P(PSTR("REQUEST"));
else if(packet->opcode == htons(ARP_OPCODE_REPLY))
SPrint_P(PSTR("REPLY"));
else
SPrint_P(PSTR("UNKNOWN"));
Serial.println();
// print source hardware address
SPrint_P(PSTR("SrcHwAddr : ")); netPrintEthAddr(&packet->shwaddr); Serial.println();
// print source protocol address
SPrint_P(PSTR("SrcProtoAddr: ")); netPrintIPAddr(HTONL(packet->sipaddr)); Serial.println();
// print target hardware address
SPrint_P(PSTR("DstHwAddr : ")); netPrintEthAddr(&packet->dhwaddr); Serial.println();
// print target protocol address
SPrint_P(PSTR("DstProtoAddr: ")); netPrintIPAddr(HTONL(packet->dipaddr)); Serial.println();
}
void arpPrintTable(void)
{
uint8_t i;
// print ARP table
SPrint_P(PSTR("Time Eth Address IP Address\r\n"));
SPrint_P(PSTR("---------------------------------------\r\n"));
for(i=0; i<ARP_TABLE_SIZE; i++)
{
Serial.print(ArpTable[i].time);
SPrint_P(PSTR(" "));
netPrintEthAddr(&ArpTable[i].ethaddr);
SPrint_P(PSTR(" "));
netPrintIPAddr(ArpTable[i].ipaddr);
Serial.println();
}
}
#endif

125
arp.h

@ -0,0 +1,125 @@
/*! \file arp.h \brief ARP Protocol Library. */
//*****************************************************************************
//
// File Name : 'arp.h'
// Title : ARP Protocol Library
// Author : Pascal Stang
// Created : 9/7/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup arp ARP Protocol Library (arp.c)
/// \code #include "net/arp.h" \endcode
/// \par Description
/// To send anything over ethernet (or most any other physical network)
/// a packet must be addressed to a physical network node address, often
/// called a MAC/hardware/ethernet address. This MAC address identifies
/// a specific interface (like the ethernet card in your computer) on the
/// network.
/// ARP (Address Resolution Protocol) assists in mapping IP addresses to
/// the MAC addresses required to actually get data to its destination.
/// In other words, an IP address is not enough to send information over
/// ethernet. You need the MAC address of the network interface/card that
/// "owns" that IP address. ARP maintains a table mapping IP addresses to
/// MAC addresses. This table can be filled by both listening to
/// traffic on the network, as well as making specific ARP requests if
/// an IP<->MAC mapping is not in the table.
///
/// \note This code is currently below version 1.0, and therefore is considered
/// to be lacking in some functionality or documentation, or may not be fully
/// tested. Nonetheless, you can expect most functions to work.
///
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef ARP_H
#define ARP_H
#include "net.h"
#ifndef ARP_TABLE_SIZE
#define ARP_TABLE_SIZE 8
#endif
#ifndef ARP_CACHE_TIME_TO_LIVE
#define ARP_CACHE_TIME_TO_LIVE 100
#endif
#define ARP_DEBUG
#define ARP_DEBUG_PRINT
/*! Initialize ARP system.
Clears ARP table and prepares it for use. This is typically done
once at program initialization. */
void arpInit(void);
/*! Set IP and Ethernet hardware/MAC address.
This must be done before valid replies can be generated for ARP
requests. Typically done once at program initialization. */
void arpSetAddress(struct netEthAddr* myeth, uint32_t myip);
/*! Processes incoming ARP packets.
This function is to be called when an ARP type packet has arrived
over the network. If the packet type is an ARP request for us,
an ARP reply will be generated and sent. */
void arpArpIn(unsigned int len, struct netEthArpHeader* packet);
/*! Process incoming IP packets to harvest IP<->MAC relationships.
This function should be called when IP packets are received over the
network. It does nothing more than harvest the IP<->MAC address
relationships from the ethernet and IP header of the packet. The
packet is not changed nor processed. Nothing is sent on the network.
Use of this command is not required, but it is a good way to
automatically fill the ARP table with information about nodes that are
active on the network.
\warning On very busy or heavily populated netorks, this can quickly
fill the ARP table with unnecessary entries, and/or cause some CPU load.
*/
void arpIpIn(struct netEthIpHeader* packet);
/*! Process outgoing IP packet to fill in ethernet header information.
To be sent on a network, an IP packet must have the correct ethernet
header information appended to the front. This function will fill
in this information.
A physical destination IP address argument is needed to support
sending to a gateway (i.e. when a packet is destined for a node that
is not on this network, IP addressing is as usual, but we phyiscally
send the packet to the gateway's ethernet address/interface).
\warning Technically, if an IP<->MAC address mapping is not in the
ARP table, then the IP packet should be held while an ARP request is
made, and the reply received. However, in single-threaded ram-limited
embedded systems, such a holdup is unacceptable. This function instead
sends the packet as an ethernet broadcast if a mapping cannot be found.
\todo Send the packet broadcast AND send an ARP request, if a mapping
is not found.
*/
void arpIpOut(struct netEthIpHeader* packet, uint32_t phyDstIp);
/*! Periodic ARP cache maintenance.
This function is to be called once per second and will slowly
expire old ARP cache entries. */
void arpTimer(void);
/*! Check if this IP address is present in the ARP cache. Internal function.
If IP address is found, function returns index of entry. If not found,
returns -1. */
int arpMatchIp(uint32_t ipaddr);
//! Print diagnotic information about ARP packet.
void arpPrintHeader(struct netArpHeader* packet);
//! Print diagnotic information about ARP cache.
void arpPrintTable(void);
#endif
//@}

@ -0,0 +1,81 @@
/*! \file avrlibdefs.h \brief AVRlib global defines and macros. */
//*****************************************************************************
//
// File Name : 'avrlibdefs.h'
// Title : AVRlib global defines and macros include file
// Author : Pascal Stang
// Created : 7/12/2001
// Revised : 9/30/2002
// Version : 1.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// Description : This include file is designed to contain items useful to all
// code files and projects, regardless of specific implementation.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#ifndef AVRLIBDEFS_H
#define AVRLIBDEFS_H
#include "wiring.h"
#include "wiring_private.h"
// Code compatibility to new AVR-libc
// outb(), inb(), inw(), outw(), BV(), sbi(), cbi(), sei(), cli()
#ifndef outb
#define outb(addr, data) addr = (data)
#endif
#ifndef inb
#define inb(addr) (addr)
#endif
#ifndef outw
#define outw(addr, data) addr = (data)
#endif
#ifndef inw
#define inw(addr) (addr)
#endif
#ifndef BV
#define BV(bit) (1<<(bit))
#endif
#ifndef cbi
#define cbi(reg,bit) reg &= ~(BV(bit))
#endif
#ifndef sbi
#define sbi(reg,bit) reg |= (BV(bit))
#endif
#ifndef cli
#define cli() __asm__ __volatile__ ("cli" ::)
#endif
#ifndef sei
#define sei() __asm__ __volatile__ ("sei" ::)
#endif
// use this for packed structures
// (this is seldom necessary on an 8-bit architecture like AVR,
// but can assist in code portability to AVR)
#ifndef GNUC_PACKED
#define GNUC_PACKED __attribute__((packed))
#endif
// port address helpers
#ifndef DDR
#define DDR(x) ((x)-1) // address of data direction register of port x
#endif
#ifndef PIN
#define PIN(x) ((x)-2) // address of input register of port x
#endif
#ifndef MIN
#define MIN min
#endif
#ifndef MAX
#define MAX max
#endif
#endif

@ -0,0 +1,88 @@
/*! \file avrlibtypes.h \brief AVRlib global types and typedefines. */
//*****************************************************************************
//
// File Name : 'avrlibtypes.h'
// Title : AVRlib global types and typedefines include file
// Author : Pascal Stang
// Created : 7/12/2001
// Revised : 9/30/2002
// Version : 1.0
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// Description : Type-defines required and used by AVRlib. Most types are also
// generally useful.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#ifndef AVRLIBTYPES_H
#define AVRLIBTYPES_H
#ifndef Wiring_h
#include "wiring.h"
#endif
#ifndef WIN32
// true/false defines
#define FALSE 0
#define TRUE -1
#endif
// datatype definitions macros
typedef unsigned char u08;
typedef signed char s08;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned long long u64;
typedef signed long long s64;
/* use inttypes.h instead
// C99 standard integer type definitions
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned long uint32_t;
typedef signed long int32_t;
typedef unsigned long uint64_t;
typedef signed long int64_t;
*/
// maximum value that can be held
// by unsigned data types (8,16,32bits)
#define MAX_U08 255
#define MAX_U16 65535
#define MAX_U32 4294967295
// maximum values that can be held
// by signed data types (8,16,32bits)
#define MIN_S08 -128
#define MAX_S08 127
#define MIN_S16 -32768
#define MAX_S16 32767
#define MIN_S32 -2147483648
#define MAX_S32 2147483647
#ifndef WIN32
// more type redefinitions
typedef unsigned char BOOL;
// typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
typedef unsigned char UCHAR;
typedef unsigned int UINT;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
typedef char CHAR;
typedef int INT;
typedef long LONG;
#endif
#endif

@ -0,0 +1,148 @@
/*! \file buffer.c \brief Multipurpose byte buffer structure and methods. */
//*****************************************************************************
//
// File Name : 'buffer.c'
// Title : Multipurpose byte buffer structure and methods
// Author : Pascal Stang - Copyright (C) 2001-2002
// Created : 9/23/2001
// Revised : 9/23/2001
// Version : 1.0
// Target MCU : any
// Editor Tabs : 4
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#include "buffer.h"
#include "avr/io.h"
#ifndef CRITICAL_SECTION_START
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli()
#define CRITICAL_SECTION_END SREG = _sreg
#endif
// global variables
// initialization
void bufferInit(cBuffer* buffer, unsigned char *start, unsigned short size)
{
// begin critical section
CRITICAL_SECTION_START;
// set start pointer of the buffer
buffer->dataptr = start;
buffer->size = size;
// initialize index and length
buffer->dataindex = 0;
buffer->datalength = 0;
// end critical section
CRITICAL_SECTION_END;
}
// access routines
unsigned char bufferGetFromFront(cBuffer* buffer)
{
unsigned char data = 0;
// begin critical section
CRITICAL_SECTION_START;
// check to see if there's data in the buffer
if(buffer->datalength)
{
// get the first character from buffer
data = buffer->dataptr[buffer->dataindex];
// move index down and decrement length
buffer->dataindex++;
if(buffer->dataindex >= buffer->size)
{
buffer->dataindex -= buffer->size;
}
buffer->datalength--;
}
// end critical section
CRITICAL_SECTION_END;
// return
return data;
}
void bufferDumpFromFront(cBuffer* buffer, unsigned short numbytes)
{
// begin critical section
CRITICAL_SECTION_START;
// dump numbytes from the front of the buffer
// are we dumping less than the entire buffer?
if(numbytes < buffer->datalength)
{
// move index down by numbytes and decrement length by numbytes
buffer->dataindex += numbytes;
if(buffer->dataindex >= buffer->size)
{
buffer->dataindex -= buffer->size;
}
buffer->datalength -= numbytes;
}
else
{
// flush the whole buffer
buffer->datalength = 0;
}
// end critical section
CRITICAL_SECTION_END;
}
unsigned char bufferGetAtIndex(cBuffer* buffer, unsigned short index)
{
// begin critical section
CRITICAL_SECTION_START;
// return character at index in buffer
unsigned char data = buffer->dataptr[(buffer->dataindex+index)%(buffer->size)];
// end critical section
CRITICAL_SECTION_END;
return data;
}
unsigned char bufferAddToEnd(cBuffer* buffer, unsigned char data)
{
// begin critical section
CRITICAL_SECTION_START;
// make sure the buffer has room
if(buffer->datalength < buffer->size)
{
// save data byte at end of buffer
buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = data;
// increment the length
buffer->datalength++;
// end critical section
CRITICAL_SECTION_END;
// return success
return -1;
}
// end critical section
CRITICAL_SECTION_END;
// return failure
return 0;
}
unsigned short bufferIsNotFull(cBuffer* buffer)
{
// begin critical section
CRITICAL_SECTION_START;
// check to see if the buffer has room
// return true if there is room
unsigned short bytesleft = (buffer->size - buffer->datalength);
// end critical section
CRITICAL_SECTION_END;
return bytesleft;
}
void bufferFlush(cBuffer* buffer)
{
// begin critical section
CRITICAL_SECTION_START;
// flush contents of the buffer
buffer->datalength = 0;
// end critical section
CRITICAL_SECTION_END;
}

@ -0,0 +1,74 @@
/*! \file buffer.h \brief Multipurpose byte buffer structure and methods. */
//*****************************************************************************
//
// File Name : 'buffer.h'
// Title : Multipurpose byte buffer structure and methods
// Author : Pascal Stang - Copyright (C) 2001-2002
// Created : 9/23/2001
// Revised : 11/16/2002
// Version : 1.1
// Target MCU : any
// Editor Tabs : 4
//
/// \ingroup general
/// \defgroup buffer Circular Byte-Buffer Structure and Function Library (buffer.c)
/// \code #include "buffer.h" \endcode
/// \par Overview
/// This byte-buffer structure provides an easy and efficient way to store
/// and process a stream of bytes.  You can create as many buffers as you
/// like (within memory limits), and then use this common set of functions to
/// access each buffer.  The buffers are designed for FIFO operation (first
/// in, first out).  This means that the first byte you put in the buffer
/// will be the first one you get when you read out the buffer.  Supported
/// functions include buffer initialize, get byte from front of buffer, add
/// byte to end of buffer, check if buffer is full, and flush buffer.  The
/// buffer uses a circular design so no copying of data is ever necessary.
/// This buffer is not dynamically allocated, it has a user-defined fixed
/// maximum size.  This buffer is used in many places in the avrlib code.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
//@{
#ifndef BUFFER_H
#define BUFFER_H
// structure/typdefs
//! cBuffer structure
typedef struct struct_cBuffer
{
unsigned char *dataptr; ///< the physical memory address where the buffer is stored
unsigned short size; ///< the allocated size of the buffer
unsigned short datalength; ///< the length of the data currently in the buffer
unsigned short dataindex; ///< the index into the buffer where the data starts
} cBuffer;
// function prototypes
//! initialize a buffer to start at a given address and have given size
void bufferInit(cBuffer* buffer, unsigned char *start, unsigned short size);
//! get the first byte from the front of the buffer
unsigned char bufferGetFromFront(cBuffer* buffer);
//! dump (discard) the first numbytes from the front of the buffer
void bufferDumpFromFront(cBuffer* buffer, unsigned short numbytes);
//! get a byte at the specified index in the buffer (kind of like array access)
// ** note: this does not remove the byte that was read from the buffer
unsigned char bufferGetAtIndex(cBuffer* buffer, unsigned short index);
//! add a byte to the end of the buffer
unsigned char bufferAddToEnd(cBuffer* buffer, unsigned char data);
//! check if the buffer is full/not full (returns zero value if full)
unsigned short bufferIsNotFull(cBuffer* buffer);
//! flush (clear) the contents of the buffer
void bufferFlush(cBuffer* buffer);
#endif
//@}

@ -0,0 +1,99 @@
/*! \file debug.c \brief Debugging function library. */
//*****************************************************************************
//
// File Name : 'debug.c'
// Title : Helpful debugging functions
// Author : Pascal Stang - Copyright (C) 2003
// Created : 2003-03-13
// Revised : 2003-03-13
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// Description : This file contains a set of functions which may be useful
// for general debugging.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include "debug.h"
#include "HardwareSerial.h"
#include <avr/pgmspace.h>
#include "programStrings.h"
// global variables
// functions
// Print a part of memory as a formatted hex table with ascii translation
void debugPrintHexTable(u16 length, u08 *buffer)
{
u08 i;
u16 j;
u08 *buf;
u08 s;
buf = buffer;
// print the low order address indicies and ASCII header
SPrint_P(PSTR(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF\r\n"));
SPrint_P(PSTR(" ----------------------------------------------- ---- ASCII -----\r\n"));
// print the data
for(j=0; j<((length+15)>>4); j++)
{
// print the high order address index for this line
Serial.print(j<<4);
Serial.print(' ');
// print the hex data
for(i=0; i<0x10; i++)
{
// be nice and print only up to the exact end of the data
if( ((j<<4)+i) < length)
{
// print hex byte
Serial.print(buf[(j<<4)+i], HEX);
Serial.print(' ');
}
else
{
// we're past the end of the data's length
// print spaces
SPrint_P(PSTR(" "));
}
}
// leave some space
Serial.print(' ');
// print the ascii data
for(i=0; i<0x10; i++)
{
// be nice and print only up to the exact end of the data
if( ((j<<4)+i) < length)
{
// get the character
s = buf[(j<<4)+i];
// make sure character is printable
if(s >= 0x20)
Serial.print(s, HEX);
else
Serial.print('.');
}
else
{
// we're past the end of the data's length
// print a space
Serial.print(' ');
}
}
Serial.println();
}
}

@ -0,0 +1,35 @@
/*! \file debug.h \brief Debugging function library. */
//*****************************************************************************
//
// File Name : 'debug.h'
// Title : Helpful debugging functions
// Author : Pascal Stang - Copyright (C) 2003
// Created : 2003-03-13
// Revised : 2003-03-13
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// Description : This file contains a set of functions which may be useful
// for general debugging.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#ifndef DEBUG_H
#define DEBUG_H
#include "avrlibdefs.h"
#include "avrlibtypes.h"
// defines
// function prototypes
//! Print a part of memory as a formatted hex table with ascii translation
void debugPrintHexTable(u16 length, u08 *buffer);
#endif

@ -0,0 +1,300 @@
/*! \file dhcp.c \brief DHCP Protocol Library. */
//*****************************************************************************
//
// File Name : 'dhcp.c'
// Title : DHCP Protocol Library
// Author : Pascal Stang
// Created : 9/17/2005
// Revised : 9/17/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include "net.h"
#include "nic.h"
#include "ip.h"
#include "netstack.h"
#include "dhcp.h"
#include "HardwareSerial.h"
// global variables
uint32_t DhcpServerIP; ///< IP address of the DHCP server that offered lease
uint32_t DhcpTransactID; ///< Unique transaction ID that identifies DHCP request/replies
uint32_t DhcpLeaseTime; ///< Number of seconds left in DHCP lease
void dhcpInit(void)
{
uint8_t macaddr[6];
// get interface mac address
nicGetMacAddress(macaddr);
// set transaction ID based on mac address
DhcpTransactID = *((uint32_t*)&macaddr);
// reset lease time
DhcpLeaseTime = 0;
}
void dhcpIn(unsigned int len, struct netDhcpHeader* packet)
{
uint8_t msgtype;
uint32_t sid;
uint8_t* optptr;
uint32_t val;
uint32_t netmask;
uint32_t gateway;
#if NET_DEBUG >= 3
dhcpPrintHeader(packet);
#endif
// check that this is a reply, and for me
if((packet->bootp.op != BOOTP_OP_BOOTREPLY) || (packet->bootp.xid != DhcpTransactID))
return;
// process incoming packet
// check reply type
dhcpGetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &msgtype);
#if NET_DEBUG >= 2
SPrint_P(PSTR("DHCP: Received msgtype = %d\r\n", msgtype);
#endif
if(msgtype == DHCP_MSG_DHCPOFFER)
{
// get DHCP server ID
dhcpGetOption(packet->options, DHCP_OPT_SERVERID, 4, &sid);
#ifdef DHCP_DEBUG
SPrint_P(PSTR("DHCP: Got offer from server ")); netPrintIPAddr(htonl(sid)); Serial.println();
#endif
// build DHCP request (on top of this reply)
packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type
// set operation
val = DHCP_MSG_DHCPREQUEST;
optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
// set the server ID
optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &sid);
// request the IP previously offered
optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.yiaddr);
// request additional information
((uint8_t*)&val)[0] = DHCP_OPT_NETMASK;
((uint8_t*)&val)[1] = DHCP_OPT_ROUTERS;
((uint8_t*)&val)[2] = DHCP_OPT_DNSSERVERS;
((uint8_t*)&val)[3] = DHCP_OPT_DOMAINNAME;
optptr = dhcpSetOption(optptr, DHCP_OPT_PARAMREQLIST, 4, &val);
#ifdef DHCP_DEBUG
SPrint_P(PSTR("DHCP: Sending request in response to offer\r\n"));
#endif
// send DHCP request
DhcpServerIP = htonl(sid);
udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+6+1, (uint8_t*)packet);
}
else if(msgtype == DHCP_MSG_DHCPACK)
{
// get netmask
dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val);
netmask = htonl(val);
// get gateway
dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val);
gateway = htonl(val);
// get gateway
dhcpGetOption(packet->options, DHCP_OPT_LEASETIME, 4, &val);
DhcpLeaseTime = htonl(val);
// assign new network info
ipSetConfig(htonl(packet->bootp.yiaddr), netmask, gateway);
#ifdef DHCP_DEBUG
SPrint_P(PSTR("DHCP: Got request ACK, bind complete\r\n"));
//debugPrintHexTable(len-DHCP_HEADER_LEN, (packet->options));
// print info
ipPrintConfig(ipGetConfig());
SPrint_P(PSTR("LeaseTm : ")); Serial.print(DhcpLeaseTime); Serial.println();
#endif
}
}
void dhcpRequest(void)
{
struct netDhcpHeader* packet;
uint32_t val;
packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
// build BOOTP/DHCP header
packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type
packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
packet->bootp.ciaddr = htonl(ipGetConfig()->ip);
packet->bootp.yiaddr = HTONL(0l);
packet->bootp.siaddr = HTONL(0l);
packet->bootp.giaddr = HTONL(0l);
nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address
packet->bootp.xid = DhcpTransactID;
packet->bootp.flags = HTONS(1);
// build DHCP request
// begin with magic cookie
packet->cookie = 0x63538263;
// set operation
val = DHCP_MSG_DHCPDISCOVER;
dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
#ifdef DHCP_DEBUG
SPrint_P(PSTR("DHCP: Sending Query\r\n"));
//dhcpPrintHeader(packet);
#endif
// send request
udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+1, (uint8_t*)packet);
}
void dhcpRelease(void)
{
struct netDhcpHeader* packet;
uint32_t val;
uint8_t* optptr;
packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
// build BOOTP/DHCP header
packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type
packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
packet->bootp.ciaddr = htonl(ipGetConfig()->ip);
packet->bootp.yiaddr = HTONL(0l);
packet->bootp.siaddr = HTONL(0l);
packet->bootp.giaddr = HTONL(0l);
nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address
packet->bootp.xid = DhcpTransactID; // set trans ID (use part of MAC address)
packet->bootp.flags = HTONS(1);
// build DHCP request
// begin with magic cookie
packet->cookie = 0x63538263;
// set operation
val = DHCP_MSG_DHCPRELEASE;
optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
// set the server ID
val = htonl(DhcpServerIP);
optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &val);
// request the IP previously offered
optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.ciaddr);
#ifdef DHCP_DEBUG
SPrint_P(PSTR("DHCP: Sending Release to ")); netPrintIPAddr(DhcpServerIP); Serial.println();
//dhcpPrintHeader(packet);
#endif
// send release
udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+1, (uint8_t*)packet);
// deconfigure ip addressing
ipSetConfig(0,0,0);
DhcpLeaseTime = 0;
}
void dhcpTimer(void)
{
// this function to be called once per second
// decrement lease time
if(DhcpLeaseTime)
DhcpLeaseTime--;
}
uint8_t dhcpGetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
{
uint8_t i;
// parse for desired option
for (;;)
{
// skip pad characters
if(*options == DHCP_OPT_PAD)
options++;
// break if end reached
else if(*options == DHCP_OPT_END)
break;
// check for desired option
else if(*options == optcode)
{
// found desired option
// limit size to actual option length
optlen = MIN(optlen, *(options+1));
//if(*(options+1) < optlen)
// optlen = *(options+1);
// copy contents of option
for(i=0; i<optlen; i++)
*(((uint8_t*)optvalptr)+i) = *(options+i+2);
// return length of option
return *(options+1);
}
else
{
// skip to next option
options++;
options+=*options;
options++;
}
}
// failed to find desired option
return 0;
}
uint8_t* dhcpSetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, uint32_t* optvalptr)
{
// use current options address as write point
// set optcode
*options++ = optcode;
// set optlen
*options++ = optlen;
// copy in argument/data
while(optlen--)
{
*options++ = *(uint8_t*)optvalptr++;
}
// write end marker
*options = DHCP_OPT_END;
// return address of end marker, to be used as a future write point
return options;
}
#ifdef DHCP_DEBUG_PRINT
void dhcpPrintHeader(struct netDhcpHeader* packet)
{
SPrint_P(PSTR("DHCP Packet:\r\n"));
// print op
SPrint_P(PSTR("Op : "));
switch(packet->bootp.op)
{
case BOOTP_OP_BOOTREQUEST: SPrint_P(PSTR("BOOTREQUEST")); break;
case BOOTP_OP_BOOTREPLY: SPrint_P(PSTR("BOOTREPLY")); break;
default: SPrint_P(PSTR("UNKNOWN")); break;
}
Serial.println();
// print transaction ID
SPrint_P(PSTR("XID : 0x")); Serial.printu32(packet->bootp.xid); Serial.println();
// print client IP address
SPrint_P(PSTR("ClIpAddr: ")); netPrintIPAddr(htonl(packet->bootp.ciaddr)); Serial.println();
// print 'your' IP address
SPrint_P(PSTR("YrIpAddr: ")); netPrintIPAddr(htonl(packet->bootp.yiaddr)); Serial.println();
// print server IP address
SPrint_P(PSTR("SvIpAddr: ")); netPrintIPAddr(htonl(packet->bootp.siaddr)); Serial.println();
// print gateway IP address
SPrint_P(PSTR("GwIpAddr: ")); netPrintIPAddr(htonl(packet->bootp.giaddr)); Serial.println();
// print client hardware address
SPrint_P(PSTR("ClHwAddr: ")); netPrintEthAddr((struct netEthAddr*)packet->bootp.chaddr); Serial.println();
}
#endif

155
dhcp.h

@ -0,0 +1,155 @@
/*! \file dhcp.h \brief DHCP Protocol Library. */
//*****************************************************************************
//
// File Name : 'dhcp.h'
// Title : DHCP Protocol Library
// Author : Pascal Stang
// Created : 9/17/2005
// Revised : 9/17/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup dhcp DHCP Protocol Library (dhcp.c)
/// \code #include "net/dhcp.h" \endcode
/// \par Description
/// This library provides a limited implementation of DHCP (Dynamic Host
/// Configuration Protocol) as described in RFC2131. DHCP allows a
/// network device to automatically obtain an IP address and other network
/// configuration settings from a DHCP server.
///
/// \note This code is currently below version 1.0, and therefore is considered
/// to be lacking in some functionality or documentation, or may not be fully
/// tested. Nonetheless, you can expect most functions to work.
///
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef DHCP_H
#define DHCP_H
#include "net.h"
//#define DHCP_DEBUG_PRINT
//#define DHCP_DEBUG
/// Bootp Header (DHCP is transported by BOOTP/UDP/IP)
struct netBootpHeader
{
uint8_t op; ///< Message op-code / message type
uint8_t htype; ///< Hardware address type (Ethernet=1)
uint8_t hlen; ///< Hardware address length (Ethernet=6 byte MAC addr)
uint8_t hops; ///< hop count (client set to zero)
uint32_t xid; ///< Transaction ID (randomly chosen by client, must remain same)
uint16_t secs; ///< Seconds elapsed since DHCP negotiation began (filled by client)
uint16_t flags; ///< Flags
uint32_t ciaddr; ///< Client IP address (filled only if already bound, renewing, or rebinding)
uint32_t yiaddr; ///< 'Your' IP address (client)
uint32_t siaddr; ///< Server IP address
uint32_t giaddr; ///< Gateway IP address
uint8_t chaddr[16]; ///< Client Hardware Address
uint8_t sname[64]; ///< Server Host Name
uint8_t file[128]; ///< Boot file name (null-term string)
} GNUC_PACKED;
#define BOOTP_HEADER_LEN 236 ///< length of BOOTP header not including options
#define BOOTP_OP_BOOTREQUEST 1 ///< BOOTP Request operation (message from client to server)
#define BOOTP_OP_BOOTREPLY 2 ///< BOOTP Reply operation (message from server to client)
#define BOOTP_HTYPE_ETHERNET 1
#define BOOTP_HLEN_ETHERNET 6
/// DHCP Header
struct netDhcpHeader
{
struct netBootpHeader bootp; ///< BOOTP header
uint32_t cookie; ///< magic cookie value
uint8_t options[]; ///< DHCP options
} GNUC_PACKED;
#define DHCP_HEADER_LEN 240 ///< length of DHCP header not including options
#define DHCP_UDP_SERVER_PORT 67 ///< UDP port where DHCP requests should be sent
#define DHCP_UDP_CLIENT_PORT 68 ///< UDP port clients will receive DHCP replies
#define DHCP_OPT_PAD 0 ///< token padding value (make be skipped)
#define DHCP_OPT_NETMASK 1 ///< subnet mask client should use (4 byte mask)
#define DHCP_OPT_ROUTERS 3 ///< routers client should use (IP addr list)
#define DHCP_OPT_TIMESERVERS 4 ///< time servers client should use (IP addr list)
#define DHCP_OPT_NAMESERVERS 5 ///< name servers client should use (IP addr list)
#define DHCP_OPT_DNSSERVERS 6 ///< DNS servers client should use (IP addr list)
#define DHCP_OPT_HOSTNAME 12 ///< host name client should use (string)
#define DHCP_OPT_DOMAINNAME 15 ///< domain name client should use (string)
#define DHCP_OPT_REQUESTEDIP 50 ///< IP address requested by client (IP address)
#define DHCP_OPT_LEASETIME 51 ///< DHCP Lease Time (uint32 seconds)
#define DHCP_OPT_DHCPMSGTYPE 53 ///< DHCP message type (1 byte)
#define DHCP_OPT_SERVERID 54 ///< Server Identifier (IP address)
#define DHCP_OPT_PARAMREQLIST 55 ///< Paramerter Request List (n OPT codes)
#define DHCP_OPT_RENEWALTIME 58 ///< DHCP Lease Renewal Time (uint32 seconds)
#define DHCP_OPT_REBINDTIME 59 ///< DHCP Lease Rebinding Time (uint32 seconds)
#define DHCP_OPT_END 255 ///< token end value (marks end of options list)
#define DHCP_MSG_DHCPDISCOVER 1 ///< DISCOVER is broadcast by client to solicit OFFER from any/all DHCP servers.
#define DHCP_MSG_DHCPOFFER 2 ///< OFFER(s) are made to client by server to offer IP address and config info.
#define DHCP_MSG_DHCPREQUEST 3 ///< REQUEST is made my client in response to best/favorite OFFER message.
#define DHCP_MSG_DHCPDECLINE 4 ///< DECLINE may be sent by client to server to indicate IP already in use.
#define DHCP_MSG_DHCPACK 5 ///< ACK is sent to client by server in confirmation of REQUEST, contains config and IP.
#define DHCP_MSG_DHCPNAK 6 ///< NAK is sent to client by server to indicate problem with REQUEST.
#define DHCP_MSG_DHCPRELEASE 7 ///< RELEASE is sent by client to server to relinquish DHCP lease on IP address, etc.
#define DHCP_MSG_DHCPINFORM 8 ///< INFORM is sent by client to server to request config info, IP address configured locally.
/*! Initialize DHCP system.
Prepares DHCP for use and initializes lease time to zero. */
void dhcpInit(void);
/*! Processes incoming DHCP packets from UDP port 68.
This function is to be called by the stack when a DHCP packet
arrives over the network. The DHCP packet will be parsed, handled,
and a response will be generated and sent if needed. When the DHCP
process completes, the IP addressing will be automatically updated. */
void dhcpIn(unsigned int len, struct netDhcpHeader* packet);
/*! Request DHCP assigned network parameters.
This function begins the DHCP process. The remainder of operations
are handled in dhcpIn(). */
void dhcpRequest(void);
/*! Release DHCP lease and assigned network parameters.
This function releases the DHCP assigned address and allows the
DHCP server to reallocate it. */
void dhcpRelease(void);
/*! Periodic DHCP maintenance.
This function is to be called once per second and will
expire the DHCP lease. */
void dhcpTimer(void);
/*! Get a DHCP option from the option list.
\param options is a pointer to the options field of a DHCP packet.
\param optcode is the desired option number to retrieve.
\param optlen is the maximum data length that should be retrieved (less data will be retrieved if option is shorter).
\param optvalptr is a pointer to where the option value will be stored.
\return actual length of the option data, as stored in the options list. */
uint8_t dhcpGetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr);
/*! Set a DHCP option in the option list.
\param options is a pointer to the options field of a DHCP packet.
\param optcode is the option number to write.
\param optlen is the data length of the option value.
\param optvalptr is a pointer to the option data to be read.
\return pointer to write location of the next option. */
uint8_t* dhcpSetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, uint32_t* optvalptr);
/*! Print diagnotic information about BOOTP/DHCP packet.
*/
void dhcpPrintHeader(struct netDhcpHeader* packet);
#endif
//@}

@ -0,0 +1,713 @@
/*! \file enc28j60.c \brief Microchip ENC28J60 Ethernet Interface Driver. */
//*****************************************************************************
//
// File Name : 'enc28j60.c'
// Title : Microchip ENC28J60 Ethernet Interface Driver
// Author : Pascal Stang (c)2005
// Created : 9/22/2005
// Revised : 9/22/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// Description : 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.
//
//*****************************************************************************
#include "wiring.h"
#include <avr/pgmspace.h>
#include "avr/io.h"
#include "avrlibdefs.h"
#include "avrlibtypes.h"
#include "HardwareSerial.h"
#include "programStrings.h"
// include configuration
#include "enc28j60conf.h"
#include "enc28j60.h"
#ifdef SPDR0
#define SPDR SPDR0
#define SPCR SPCR0
#define SPSR SPSR0
#define SPIF SPIF0
#define MSTR MSTR0
#define CPOL CPOL0
#define DORD DORD0
#define SPR0 SPR00
#define SPR1 SPR01
#define SPI2X SPI2X0
#define SPE SPE0
#endif
u08 Enc28j60Bank;
u16 NextPacketPtr;
void nicInit(void)
{
enc28j60Init();
}
void nicSend(unsigned int len, unsigned char* packet)
{
enc28j60PacketSend(len, packet);
}
unsigned int nicPoll(unsigned int maxlen, unsigned char* packet)
{
return enc28j60PacketReceive(maxlen, packet);
}
void nicGetMacAddress(uint8_t* macaddr)
{
// read MAC address registers
// NOTE: MAC address in ENC28J60 is byte-backward
*macaddr++ = enc28j60Read(MAADR5);
*macaddr++ = enc28j60Read(MAADR4);
*macaddr++ = enc28j60Read(MAADR3);
*macaddr++ = enc28j60Read(MAADR2);
*macaddr++ = enc28j60Read(MAADR1);
*macaddr++ = enc28j60Read(MAADR0);
}
void nicSetMacAddress(uint8_t* macaddr)
{
// write MAC address
// NOTE: MAC address in ENC28J60 is byte-backward
enc28j60Write(MAADR5, *macaddr++);
enc28j60Write(MAADR4, *macaddr++);
enc28j60Write(MAADR3, *macaddr++);
enc28j60Write(MAADR2, *macaddr++);
enc28j60Write(MAADR1, *macaddr++);
enc28j60Write(MAADR0, *macaddr++);
}
void nicRegDump(void)
{
enc28j60RegDump();
}
void nicHardReset(void)
{
#ifndef ENC28J60_HARD_RESET_DISABLED
enc28j60hardReset();
#endif
}
void nicSoftReset(void)
{
enc28j60softReset();
}
void nicReboot(void)
{
enc28j60Reboot();
}
void enc28j60Reboot(void)
{
#ifndef ENC28J60_HARD_RESET_DISABLED
enc28j60hardReset();
#else
delayMicroseconds(10);
#endif
enc28j60softReset();
}
void enc28j60softReset(void)
{
// perform system reset
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
delayMicroseconds(50);
// check CLKRDY bit to see if reset is complete
//while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
// Errata workaround #1, CLKRDY check is unreliable, delay 1 mS instead
delay(1);
}
#ifndef ENC28J60_HARD_RESET_DISABLED
void enc28j60hardReset(void)
{
// HW reset
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_HRESET);
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_HRESET); // Down
delayMicroseconds(10);
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_HRESET); // Up
delay(1);
}
#endif
uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
{
uint8_t data;
// assert CS
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
// issue read command
SPDR = op | (address & ADDR_MASK);
while(!(SPSR & (1<<SPIF)));
// read data
SPDR = 0x00;
while(!(SPSR & (1<<SPIF)));
// do dummy read if needed
if(address & 0x80)
{
SPDR = 0x00;
while(!(SPSR & (1<<SPIF)));
}
data = SPDR;
// release CS
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
return data;
}
void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
{
// assert CS
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
// issue write command
SPDR = op | (address & ADDR_MASK);
while(!(SPSR & (1<<SPIF)));
// write data
SPDR = data;
while(!(SPSR & (1<<SPIF)));
// release CS
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
}
void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
{
// assert CS
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
// issue read command
SPDR = ENC28J60_READ_BUF_MEM;
while(!(SPSR & (1<<SPIF)));
while(len--)
{
// read data
SPDR = 0x00;
while(!(SPSR & (1<<SPIF)));
*data++ = SPDR;
}
// release CS
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
}
void enc28j60WriteBuffer(uint16_t len, uint8_t* data)
{
// assert CS
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
// issue write command
SPDR = ENC28J60_WRITE_BUF_MEM;
while(!(SPSR & (1<<SPIF)));
while(len--)
{
// write data
SPDR = *data++;
while(!(SPSR & (1<<SPIF)));
}
// release CS
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
}
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);
}
uint16_t enc28j60PhyRead(uint8_t address)
{
uint16_t data;
// Set the right address and start the register read operation
enc28j60Write(MIREGADR, address);
enc28j60Write(MICMD, MICMD_MIIRD);
// wait until the PHY read completes
while(enc28j60Read(MISTAT) & MISTAT_BUSY);
// quit reading
enc28j60Write(MICMD, 0x00);
// get data value
data = enc28j60Read(MIRDH);
data <<= 8;
data |= enc28j60Read(MIRDL);
// return the data
return 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);
}
void enc28j60Init(void)
{
/**
* Enable ENC28J560 Control ports
**/
// Enable CS and pull it high as CS is inverted
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_CS); // CS as output
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS); // CS high
// Enable Hard reset and pull it high as RESET is inverted
#ifndef ENC28J60_HARD_RESET_DISABLED
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_HRESET); // HR as output
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_HRESET); // HR low
#endif
/**
* setup SPI I/O pins
**/
sbi(ENC28J60_CONTROL_DDR, ENC28J60_SPI_SCK); // set SCK as output
cbi(ENC28J60_CONTROL_PORT, ENC28J60_SPI_SCK); // set SCK lo
sbi(ENC28J60_CONTROL_DDR, ENC28J60_SPI_MOSI); // set MOSI as output
cbi(ENC28J60_CONTROL_DDR, ENC28J60_SPI_MISO); // set MISO as input
sbi(ENC28J60_CONTROL_PORT, ENC28J60_SPI_SS); // SS must be output for Master mode to work
// master mode
sbi(SPCR, MSTR);
// select clock phase positive-going in middle of data
cbi(SPCR, CPOL);
// Data order MSB first
cbi(SPCR,DORD);
// switch to f/4 2X = f/2 bitrate
cbi(SPCR, SPR0);
cbi(SPCR, SPR1);
sbi(SPSR, SPI2X);
// enable SPI
sbi(SPCR, SPE);
delay(1);
#ifdef DEBUG_ENC_INIT
SPrintln_P(PSTR("SPI Enabled"));
#endif
// Reboot the ENC28J60
enc28j60Reboot();
#ifdef DEBUG_ENC_INIT
SPrintln_P(PSTR("PHY reboot done"));
#endif
#ifdef ENC28J60_LAMPS_MODE
SPrintln_P(PSTR("Custom lamps"));
enc28j60PhyWrite(PHLCON, ENC28J60_LAMPS_MODE);
#else
// Errata #9 correction
if (enc28j60Read(MACON3) & MACON3_FULDPX)
{
SPrintln_P(PSTR("Full duplex lamps"));
enc28j60PhyWrite(PHLCON, PHLCON_DEFAULT);
} else {
SPrintln_P(PSTR("Half duplex lamps"));
enc28j60PhyWrite(PHLCON, PHLCON_DEFAULT_HD);
}
#endif
#ifdef DEBUG_ENC_INIT
SPrintln_P(PSTR("Lamps set"));
#endif
// do bank 0 stuff
// initialize receive buffer
// 16-bit transfers, must write low byte first
// set receive buffer start address
NextPacketPtr = RXSTART_INIT;
enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
enc28j60Write(ERXSTH, RXSTART_INIT>>8);
// set receive pointer address
enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
// set receive buffer end
// ERXND defaults to 0x1FFF (end of ram)
enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
// set transmit buffer start
// ETXST defaults to 0x0000 (beginnging of ram)
enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
enc28j60Write(ETXSTH, TXSTART_INIT>>8);
/*
// Needs register implementation
#ifdef ENC28J60_PACKET_FILTER_ENABLED
// 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(ERXFCON, ERXFCON_UCEN|ERXFCON_PMEN);
enc28j60Write(EPMM0, 0x3f);
enc28j60Write(EPMM1, 0x30);
enc28j60Write(EPMCSL, 0xf9);
enc28j60Write(EPMCSH, 0xf7);
#endif
*/
// 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 and CRC operations
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
// enc28j60Write(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
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, ENC28J60_MAC0);
enc28j60Write(MAADR4, ENC28J60_MAC1);
enc28j60Write(MAADR3, ENC28J60_MAC2);
enc28j60Write(MAADR2, ENC28J60_MAC3);
enc28j60Write(MAADR1, ENC28J60_MAC4);
enc28j60Write(MAADR0, ENC28J60_MAC5);
// 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);
#ifdef DEBUG_ENC_INIT
SPrintln_P(PSTR("Banks robbed"));
#endif
/*
enc28j60PhyWrite(PHLCON, 0x0AA2);
// setup duplex ----------------------
// Disable receive logic and abort any packets currently being transmitted
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS|ECON1_RXEN);
{
uint16_t temp;
// Set the PHY to the proper duplex mode
temp = enc28j60PhyRead(PHCON1);
temp &= ~PHCON1_PDPXMD;
enc28j60PhyWrite(PHCON1, temp);
// Set the MAC to the proper duplex mode
temp = enc28j60Read(MACON3);
temp &= ~MACON3_FULDPX;
enc28j60Write(MACON3, temp);
}
// Set the back-to-back inter-packet gap time to IEEE specified
// requirements. The meaning of the MABBIPG value changes with the duplex
// state, so it must be updated in this function.
// In full duplex, 0x15 represents 9.6us; 0x12 is 9.6us in half duplex
//enc28j60Write(MABBIPG, DuplexState ? 0x15 : 0x12);
// Reenable receive logic
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
// setup duplex ----------------------
*/
}
#define ETHERNET_MIN_PACKET_LENGTH 0x3C
#define ETHERNET_HEADER_LENGTH 0x0E
#define IP_TCP_HEADER_LENGTH 40
#define TOTAL_HEADER_LENGTH (IP_TCP_HEADER_LENGTH+ETHERNET_HEADER_LENGTH)
void enc28j60PacketSend(uint16_t len, uint8_t* packet)
{
/*
// dump packet
int i,j;
for (i=0;i<len;i+=16)
{
printf("%04x ",i);
for (j=0;j<16;j++)
printf("%02x ",(i+j) < len ? packet[i+j] : 0);
printf(" ");
for (j=0;j<16;j++)
printf("%c", (i+j) < len ? isprint(packet[i+j]) ? packet[i+j] : '.' : '.');
printf("\n");
}
*/
// Errata workaround #10 Transmit Logic
if (enc28j60Read(EIR) & EIR_TXERIF)
{
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
}
// Set the write pointer to start of transmit buffer area
enc28j60Write(EWRPTL, TXSTART_INIT);
enc28j60Write(EWRPTH, TXSTART_INIT>>8);
// Set the TXND pointer to correspond to the packet size given
enc28j60Write(ETXNDL, (TXSTART_INIT+len));
enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
// write per-packet control byte
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
// TODO, fix this up
/*
if( uip_len <= TOTAL_HEADER_LENGTH )
{
// copy the packet into the transmit buffer
enc28j60WriteBuffer(len, packet);
}
else
{
len -= TOTAL_HEADER_LENGTH;
enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
}
*/
// 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);
// if( (enc28j60Read(EIR) & EIR_TXERIF) ){
// enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
// }
}
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) )
{
// Errata workaround #4, PKTIF is not reliable
// double check by looking at EPKTCNT
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
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
// read the receive status
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
// limit retrieve length
// (we reduce the MAC-reported length by 4 to remove the CRC)
len = MIN(len, maxlen);
// 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
// Errata workaround #11. Make sure ERXRDPT is odd
//
{
uint16_t rs,re;
rs = enc28j60Read(ERXSTH);
rs <<= 8;
rs |= enc28j60Read(ERXSTL);
re = enc28j60Read(ERXNDH);
re <<= 8;
re |= enc28j60Read(ERXNDL);
if (NextPacketPtr - 1 < rs || NextPacketPtr - 1 > re)
{
enc28j60Write(ERXRDPTL, (re));
enc28j60Write(ERXRDPTH, (re)>>8);
}
else
{
enc28j60Write(ERXRDPTL, (NextPacketPtr-1));
enc28j60Write(ERXRDPTH, (NextPacketPtr-1)>>8);
}
}
// decrement the packet counter indicate we are done with this packet
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
return len;
}
void enc28j60ReceiveOverflowRecover(void)
{
// receive buffer overflow handling procedure
// recovery completed
}
void enc28j60RegDump(void)
{
// unsigned char macaddr[6];
// result = ax88796Read(TR);
// SPrint_P(PSTR("Media State: "));
// if(!(result & AUTOD))
// SPrint_P(PSTR("Autonegotiation\r\n"));
// else if(result & RST_B)
// SPrint_P(PSTR("PHY in Reset \r\n"));
// else if(!(result & RST_10B))
// SPrint_P(PSTR("10BASE-T \r\n"));
// else if(!(result & RST_TXB))
// SPrint_P(PSTR("100BASE-T \r\n"));
SPrint_P(PSTR("RevID: ")); delay(5);
Serial.println(enc28j60Read(EREVID), HEX); delay(5);
SPrint_P(PSTR("Cntrl: ECON1 ECON2 ESTAT EIR EIE\r\n")); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ECON1), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ECON2), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ESTAT), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(EIR), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(EIE), HEX); delay(5);
Serial.println(); delay(5);
SPrint_P(PSTR("MAC : MACON1 MACON2 MACON3 MACON4 MAC-Address\r\n")); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MACON1), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MACON2), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MACON3), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MACON4), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MAADR5), HEX); delay(5);
Serial.print(enc28j60Read(MAADR4), HEX); delay(5);
Serial.print(enc28j60Read(MAADR3), HEX); delay(5);
Serial.print(enc28j60Read(MAADR2), HEX); delay(5);
Serial.print(enc28j60Read(MAADR1), HEX); delay(5);
Serial.print(enc28j60Read(MAADR0), HEX); delay(5);
Serial.println(); delay(5);
SPrint_P(PSTR("Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\r\n")); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ERXSTH), HEX); delay(5);
Serial.print(enc28j60Read(ERXSTL), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ERXNDH), HEX); delay(5);
Serial.print(enc28j60Read(ERXNDL), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ERXWRPTH), HEX); delay(5);
Serial.print(enc28j60Read(ERXWRPTL), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ERXRDPTH), HEX); delay(5);
Serial.print(enc28j60Read(ERXRDPTL), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ERXFCON), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(EPKTCNT), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MAMXFLH), HEX); delay(5);
Serial.print(enc28j60Read(MAMXFLL), HEX); delay(5);
Serial.println(); delay(5);
SPrint_P(PSTR("Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\r\n")); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ETXSTH), HEX); delay(5);
Serial.print(enc28j60Read(ETXSTL), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(ETXNDH), HEX); delay(5);
Serial.print(enc28j60Read(ETXNDL), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MACLCON1), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MACLCON2), HEX); delay(5);
SPrint_P(PSTR(" ")); delay(5);
Serial.print(enc28j60Read(MAPHSUP), HEX); delay(5);
Serial.println(); delay(5);
//delay_ms(25); delay(5);
delay(25);
}

@ -0,0 +1,338 @@
/*! \file enc28j60.h \brief Microchip ENC28J60 Ethernet Interface Driver. */
//*****************************************************************************
//
// File Name : 'enc28j60.h'
// Title : Microchip ENC28J60 Ethernet Interface Driver
// Author : Pascal Stang (c)2005
// Created : 9/22/2005
// Revised : 9/22/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup enc28j60 Microchip ENC28J60 Ethernet Interface Driver (enc28j60.c)
/// \code #include "net/enc28j60.h" \endcode
/// \par Overview
/// 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.
///
//
//*****************************************************************************
//@{
#ifndef ENC28J60_H
#define ENC28J60_H
//#define DEBUG_ENC_INIT
#include "avrlibdefs.h"
#include "avrlibtypes.h"
#ifndef nop
#define nop() asm volatile ("nop")
#endif
// 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) /* 0x312 */
#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
// Default lamps register values
// 0x3000 | 0xD00 | 0x50 |
// LEDA: Display link status and transmit/receive activity LEDB: Display duplex status
#define PHLCON_DEFAULT ((0x0C<<0x03)|(0x08<<0x0D)|(0x04<<0x05)|0x06) /* 0x3D56 */
// LEDA: Display link status and transmit/receive activity LEDB: Display collision activity
#define PHLCON_DEFAULT_HD ((0x0C<<0x03)|(0x08<<0x0D)|(0x04<<0x03)|0x06) /* 0x3D36 */
// 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
// buffer boundaries applied to internal 8K ram
// entire available packet buffer space is allocated
// Includes Errata #3 Module: Memory (Ethernet Buffer)
#define TXSTART_INIT 0x0000 // start TX buffer at 0
#define RXSTART_INIT 0x0600 // give TX buffer space for one full ethernet frame (~1500 bytes)
#define RXSTOP_INIT 0x1FFF // receive buffer gets the rest
#define MAX_FRAMELEN 1518 // maximum ethernet frame length
//#define MAX_FRAMELEN 500
// Ethernet constants
#define ETHERNET_MIN_PACKET_LENGTH 0x3C
//#define ETHERNET_HEADER_LENGTH 0x0E
// functions
#include "nic.h"
// setup ports for I/O
//! do a ENC28J60 read operation
u08 enc28j60ReadOp(u08 op, u08 address);
//! do a ENC28J60 write operation
void enc28j60WriteOp(u08 op, u08 address, u08 data);
//! read the packet buffer memory
void enc28j60ReadBuffer(u16 len, u08* data);
//! write the packet buffer memory
void enc28j60WriteBuffer(uint16_t len, uint8_t* data);
//! set the register bank for register at address
void enc28j60SetBank(uint8_t address);
//! read ax88796 register
uint8_t enc28j60Read(uint8_t address);
//! write ax88796 register
void enc28j60Write(u08 address, u08 data);
//! read a PHY register
uint16_t enc28j60PhyRead(uint8_t address);
//! write a PHY register
void enc28j60PhyWrite(uint8_t address, uint16_t data);
//! initialize the ethernet interface for transmit/receive
void enc28j60Init(void);
//! Packet transmit function.
/// Sends a packet on the network. It is assumed that the packet is headed by a valid ethernet header.
/// \param len Length of packet in bytes.
/// \param packet Pointer to packet data.
void enc28j60PacketSend(unsigned int len, unsigned char* packet);
//! Packet receive function.
/// Gets a packet from the network receive buffer, if one is available.
/// The packet will by headed by an ethernet header.
/// \param maxlen The maximum acceptable length of a retrieved packet.
/// \param packet Pointer where packet data should be stored.
/// \return Packet length in bytes if a packet was retrieved, zero otherwise.
unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet);
//! execute procedure for recovering from a receive overflow
/// this should be done when the receive memory fills up with packets
void enc28j60ReceiveOverflowRecover(void);
//! formatted print of important ENC28J60 registers
void enc28j60RegDump(void);
// ! Hard reset function
void enc28j60hardReset(void);
// ! Hard reset function
void enc28j60softReset(void);
// ! (Re)boot cycle
void enc28j60Reboot(void);
#endif
//@}

@ -0,0 +1,102 @@
/*! \file enc28j60conf.h \brief Microchip ENC28J60 Ethernet Interface Driver Configuration. */
//*****************************************************************************
//
// File Name : 'enc28j60conf.h'
// Title : Microchip ENC28J60 Ethernet Interface Driver Configuration
// Author : Pascal Stang
// Created : 10/5/2004
// Revised : 8/22/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// Description : This driver provides initialization and transmit/receive
// functions for the ENC28J60 10Mb Ethernet Controller and PHY.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#ifndef ENC28J60CONF_H
#define ENC28J60CONF_H
// Check for preference overrides
#include "main.h"
// ENC28J60 SPI port
#define ENC28J60_SPI_PORT PORTB
#define ENC28J60_SPI_DDR DDRB
// ENC28J60 control port
#define ENC28J60_CONTROL_PORT PORTB
#define ENC28J60_CONTROL_DDR DDRB
// ENC28J60 port pins
//#ifdef __AVR_ATmega8__ || __AVR_ATmega168__
#define ENC28J60_SPI_SCK 5
#define ENC28J60_SPI_MOSI 3
#define ENC28J60_SPI_MISO 4
#define ENC28J60_SPI_SS 2
#define ENC28J60_CONTROL_CS 2
#define ENC28J60_CONTROL_HRESET 1
// #elif __AVR_ATmega128__
// #define ENC28J60_SPI_SCK 1
// #define ENC28J60_SPI_MOSI 2
// #define ENC28J60_SPI_MISO 3
// #define ENC28J60_SPI_SS 0
//
// #define ENC28J60_CONTROL_CS 0
// #define ENC28J60_CONTROL_HRESET 4
// #else
// #define ENC28J60_SPI_SCK 7
// #define ENC28J60_SPI_MOSI 5
// #define ENC28J60_SPI_MISO 6
// #define ENC28J60_SPI_SS 4
//
// #define ENC28J60_CONTROL_CS 4
// #define ENC28J60_CONTROL_HRESET 3
// #endif
/**
* If commented, the ENC will receive all "loose packets",
* this can be a lot for our little µC so we will only
* accept packets that are sent to our MAC, except for ARP.
**/
#define ENC28J60_PACKET_FILTER_ENABLED /* Unimplemented */
#define ENC28J60_LAMPS_MODE 0x3476 /* Default (with Errata #9 correction) applied if this is undefied */
/**
* Lamps reference
* 0x3D56 # Default full duplex: LEDA: Display link status and transmit/receive activity LEDB: Display duplex status
* 0x3D36 # Default half duplex: LEDA: Display link status and transmit/receive activity LEDB: Display collision activity
* 0x3476 # Prefered half duplex: LEDA: Link status LEDB: Rx/Tx acitity
* 0x3996 # All lamps off
* 0x3886 # All lamps on
**/
// Use this if you want to disable the hard reset (can be useful if you your the ENC's CLKOUT)
//#define ENC28J60_HARD_RESET_DISABLED
// Use this if you will run the µC using CLKOUT
//#define ENC28J60_USE_CLKOUT /* Unimplemented */
// MAC address for this interface
#ifdef ETHADDR0
#define ENC28J60_MAC0 ETHADDR0
#define ENC28J60_MAC1 ETHADDR1
#define ENC28J60_MAC2 ETHADDR2
#define ENC28J60_MAC3 ETHADDR3
#define ENC28J60_MAC4 ETHADDR4
#define ENC28J60_MAC5 ETHADDR5
#else
#define ENC28J60_MAC0 'C'
#define ENC28J60_MAC1 '0'
#define ENC28J60_MAC2 'F'
#define ENC28J60_MAC3 'F'
#define ENC28J60_MAC4 'E'
#define ENC28J60_MAC5 'E'
#endif
#endif

@ -0,0 +1,98 @@
/*! \file icmp.c \brief ICMP Protocol Library. */
//*****************************************************************************
//
// File Name : 'icmp.c'
// Title : ICMP (Internet Control Message Protocol) Protocol Library
// Author : Pascal Stang
// Created : 9/10/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include "net.h"
#include "nic.h"
#include "arp.h"
#include "icmp.h"
#include "HardwareSerial.h"
#include "debug.h"
#ifdef ICMP_DEBUG_PRINT
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "HardwareSerial.h"
#endif
//extern void nicSend(unsigned int len, unsigned char* packet);
// global variables
// functions
void icmpInit(void)
{
}
void icmpIpIn(icmpip_hdr* packet)
{
// check ICMP type
switch(packet->icmp.type)
{
case ICMP_TYPE_ECHOREQUEST:
// echo request
icmpEchoRequest(packet);
break;
default:
break;
}
}
void icmpEchoRequest(icmpip_hdr* packet)
{
uint32_t tempIp;
// change type to reply
packet->icmp.type = ICMP_TYPE_ECHOREPLY;
// recalculate checksum
packet->icmp.icmpchksum = 0;
packet->icmp.icmpchksum = netChecksum((netIpHeader*)&packet->icmp, htons(packet->ip.len)-IP_HEADER_LEN);
// return to sender
tempIp = packet->ip.destipaddr;
packet->ip.destipaddr = packet->ip.srcipaddr;
packet->ip.srcipaddr = tempIp;
// add ethernet routing
arpIpOut((struct netEthIpHeader*)(((u08*)packet)-ETH_HEADER_LEN), 0);
// debugging
#if NET_DEBUG >= 2
icmpPrintHeader(packet);
debugPrintHexTable(htons(packet->ip.len), (u08*)packet);
#endif
// send it (packet->ip.len+ETH_HEADER_LEN
nicSend(htons(packet->ip.len)+ETH_HEADER_LEN, (((u08*)packet)-ETH_HEADER_LEN));
}
#ifdef ICMP_DEBUG_PRINT
void icmpPrintHeader(icmpip_hdr* packet)
{
SPrint_P(PSTR("ICMP Packet:\r\n"));
// print source IP address
SPrint_P(PSTR("SrcIpAddr: ")); netPrintIPAddr(htonl(packet->ip.srcipaddr)); Serial.println();
// print dest IP address
SPrint_P(PSTR("DstIpAddr: ")); netPrintIPAddr(htonl(packet->ip.destipaddr)); Serial.println();
// print type
SPrint_P(PSTR("Type : "));
switch(packet->icmp.type)
{
case ICMP_TYPE_ECHOREQUEST: SPrint_P(PSTR("ECHO REQUEST")); break;
case ICMP_TYPE_ECHOREPLY: SPrint_P(PSTR("ECHO REPLY")); break;
default: SPrint_P(PSTR("UNKNOWN")); break;
}
Serial.println();
// print code
SPrint_P(PSTR("Code : 0x")); Serial.print(packet->icmp.icode); Serial.println();
}
#endif

@ -0,0 +1,49 @@
/*! \file icmp.h \brief ICMP Protocol Library. */
//*****************************************************************************
//
// File Name : 'icmp.h'
// Title : ICMP (Internet Control Message Protocol) Protocol Library
// Author : Pascal Stang
// Created : 9/10/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup icmp ICMP Protocol Library (icmp.c)
/// \code #include "net/icmp.h" \endcode
/// \par Description
/// ICMP (Internet Control Message Protocol) has many functions on the
/// internet, including the handling of ECHO (ping) requests, relaying
/// network route status, passing connection status messages, etc.
///
/// This library currently handles only ICMP ECHO requests (ping), but
/// may be expanded to include other useful ICMP operations as needed.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef ICMP_H
#define ICMP_H
#include "net.h"
#define ICMP_DEBUG_PRINT
//! Initialize ICMP protocol library.
void icmpInit(void);
//! Incoming IP packets of protocol ICMP should be passed to this function.
void icmpIpIn(icmpip_hdr* packet);
//! Forms and sends a reply in response to an ICMP ECHO request.
void icmpEchoRequest(icmpip_hdr* packet);
//! Print ICMP packet information.
void icmpPrintHeader(icmpip_hdr* packet);
#endif
//@}

149
ip.cpp

@ -0,0 +1,149 @@
/*! \file ip.c \brief IP (Internet Protocol) Library. */
//*****************************************************************************
//
// File Name : 'ip.c'
// Title : IP (Internet Protocol) Library
// Author : Pascal Stang
// Created : 8/30/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include <inttypes.h>
#include "HardwareSerial.h"
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "debug.h"
#include "net.h"
#include "nic.h"
#include "arp.h"
#include "ip.h"
struct ipConfig IpMyConfig; ///< Local IP address/config structure
void ipSetConfig(uint32_t myIp, uint32_t netmask, uint32_t gatewayIp)
{
struct netEthAddr ethaddr;
// set local addressing
IpMyConfig.ip = myIp;
IpMyConfig.netmask = netmask;
IpMyConfig.gateway = gatewayIp;
// set ARP association
nicGetMacAddress(ethaddr.addr);
arpSetAddress(&ethaddr, myIp);
}
struct ipConfig* ipGetConfig(void)
{
return &IpMyConfig;
}
// deprecated
/*
uint32_t ipGetMyAddress(void)
{
return IpMyConfig.ip;
}
*/
void ipSend(uint32_t dstIp, uint8_t protocol, uint16_t len, uint8_t* data)
{
// make pointer to ethernet/IP header
struct netEthIpHeader* ethIpHeader;
// move data pointer to make room for headers
data -= ETH_HEADER_LEN+IP_HEADER_LEN;
ethIpHeader = (struct netEthIpHeader*)data;
#ifdef NET_BUG > 6
debugPrintHexTable(len+ETH_HEADER_LEN+IP_HEADER_LEN, data);
#endif
// adjust length to add IP header
len += IP_HEADER_LEN;
// fill IP header
ethIpHeader->ip.destipaddr = HTONL(dstIp);
ethIpHeader->ip.srcipaddr = HTONL(IpMyConfig.ip);
ethIpHeader->ip.proto = protocol;
ethIpHeader->ip.len = htons(len);
ethIpHeader->ip.vhl = 0x45;
ethIpHeader->ip.tos = 0;
ethIpHeader->ip.ipid = 0;
ethIpHeader->ip.ipoffset = 0;
ethIpHeader->ip.ttl = IP_TIME_TO_LIVE;
ethIpHeader->ip.ipchksum = 0;
// calculate and apply IP checksum
// DO THIS ONLY AFTER ALL CHANGES HAVE BEEN MADE TO IP HEADER
ethIpHeader->ip.ipchksum = netChecksum(&ethIpHeader->ip, IP_HEADER_LEN);
// add ethernet routing
// check if we need to send to gateway
if( (dstIp & IpMyConfig.netmask) == (IpMyConfig.ip & IpMyConfig.netmask) )
{
arpIpOut(ethIpHeader,0); // local send
#ifdef NET_DEBUG
SPrint_P(PSTR("Sending IP packet on local net\r\n"));
#endif
}
else
{
arpIpOut(ethIpHeader,IpMyConfig.gateway); // gateway send
#ifdef NET_DEBUG
SPrint_P(PSTR("Sending IP packet to gateway\r\n"));
#endif
}
// adjust length to add ethernet header
len += ETH_HEADER_LEN;
// debug
#if NET_DEBUG > 6
debugPrintHexTable(ETH_HEADER_LEN, &data[0]);
debugPrintHexTable(len-ETH_HEADER_LEN, &data[ETH_HEADER_LEN]);
#endif
// send it
nicSend(len, data);
}
void udpSend(uint32_t dstIp, uint16_t dstPort, uint16_t len, uint8_t* data)
{
// make pointer to UDP header
struct netUdpHeader* udpHeader;
// move data pointer to make room for UDP header
data -= UDP_HEADER_LEN;
udpHeader = (struct netUdpHeader*)data;
// adjust length to add UDP header
len += UDP_HEADER_LEN;
// fill UDP header
udpHeader->destport = HTONS(dstPort);
udpHeader->srcport = HTONS(dstPort);
udpHeader->udplen = htons(len);
udpHeader->udpchksum = 0;
#if NET_DEBUG > 6
debugPrintHexTable(UDP_HEADER_LEN, (uint8_t*)udpHeader);
#endif
ipSend(dstIp, IP_PROTO_UDP, len, (uint8_t*)udpHeader);
}
void ipPrintConfig(struct ipConfig* config)
{
SPrint_P(PSTR("IP Addr : ")); netPrintIPAddr(config->ip); Serial.println();
SPrint_P(PSTR("Netmask : ")); netPrintIPAddr(config->netmask); Serial.println();
SPrint_P(PSTR("Gateway : ")); netPrintIPAddr(config->gateway); Serial.println();
}

70
ip.h

@ -0,0 +1,70 @@
/*! \file ip.h \brief IP (Internet Protocol) Library. */
//*****************************************************************************
//
// File Name : 'ip.h'
// Title : IP (Internet Protocol) Library
// Author : Pascal Stang
// Created : 8/30/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup ip IP (Internet Protocol) Library (ip.c)
/// \code #include "net/ip.h" \endcode
/// \par Description
/// The IP (Internet Protocol) library provide support for sending IP and
/// IP-related packets. It's not clear if additional features are needed
/// or will be added, or even if this is the proper way to facilitate IP
/// packet operations.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef IP_H
#define IP_H
#include "net.h"
#include "arp.h"
#include <inttypes.h>
struct ipConfig ///< IP addressing/configuration structure
{
uint32_t ip; ///< IP address
uint32_t netmask; ///< netmask
uint32_t gateway; ///< gateway IP address
};
#define IP_TIME_TO_LIVE 128 ///< default Time-To-Live (TTL) value to use in IP headers
//! Set our IP address and routing information.
/// The myIp value will be used in the source field of IP packets.
/// Use this function to set and reset the system IP address.
void ipSetConfig(uint32_t myIp, uint32_t netmask, uint32_t gatewayIp);
//! Get our local IP address.
/// Returns current IP address value.
//uint32_t ipGetMyAddress(void);
//! Get our local IP configuration.
/// Returns pointer to current IP address/configuration.
struct ipConfig* ipGetConfig(void);
//! Print IP configuration
///
void ipPrintConfig(struct ipConfig* config);
//! Send an IP packet.
void ipSend(uint32_t dstIp, uint8_t protocol, uint16_t len, uint8_t* data);
//! Send a UDP/IP packet.
void udpSend(uint32_t dstIp, uint16_t dstPort, uint16_t len, uint8_t* data);
#endif
//@}

@ -0,0 +1,76 @@
/**
* Arduino adaptation of AVRLib's netstack test and ENC28J60 driver.
* Cleft under a CC BY-SA-NC 2.5 (Matthieu Lalonde)
* Go to creativecommons.org for the full license.
**/
#ifndef Main_H
#define Main_H
/**
* Libraries
**/
// Program strings support
#include <avr/pgmspace.h>
#include "programStrings.h"
// AVRLib defs & types compatibility
#include "avrlibdefs.h"
#include "avrlibtypes.h"
/**
* Network support
**/
// PHY level
#include "nic.h"
#include "enc28j60.h"
// Net Stack
#include "net.h"
#include "netstack.h"
#include "arp.h"
#include "ip.h"
#include "icmp.h"
/**
* Definitions
**/
#define pinLED 7
// Network options
#define IPADDRESS IPDOT(192l,168l,0l,126l)
#define NETMASK IPDOT(255l,255l,0l,0l)
#define GATEWAY IPDOT(192l,168l,0l,1l)
#define ETHADDR0 0xCC /*'78'*/
#define ETHADDR1 0x00 /*'53'*/
#define ETHADDR2 0xFF /*'6D'*/
#define ETHADDR3 0xFF /*'75'*/
#define ETHADDR4 0xEE /*'72'*/
#define ETHADDR5 0xEE /*'66'*/
#define LOOPBACK_PORT 7 // UDP packets sent to this port will be returned to sender
#define CONTROL_PORT 4950 // UDP packets sent to this port will be used for control
#define SERIAL_PORT 4951 // UDP packets sent to this port will be printed via serial
/**
* Macros
**/
#ifndef nop
#define nop() __asm__ __volatile__ ("nop")
#endif
#ifndef __AVR_ATmega168__
#define __AVR_ATmega168__
#endif
/**
* Function prototypes
**/
void processCommand(u16 len, u08* data);
void serviceLocal(void);
void setup(void);
void loop(void);
#endif

@ -0,0 +1,233 @@
/**
* Arduino adaptation of AVRLib's netstack test and ENC28J60 driver.
* Cleft under a CC BY-SA-NC 2.5 (Matthieu Lalonde)
* Go to creativecommons.org for the full license.
**/
#include "main.h"
struct netEthAddr myEthAddress;
// prototypes
void netstackUDPIPProcess(unsigned int len, udpip_hdr* packet)
{
SPrint_P(PSTR("-1"));
u16 payloadlen=0;
SPrint_P(PSTR("0"));
u08* payloaddata=0;
SPrint_P(PSTR("1"));
u16 i;
SPrint_P(PSTR("2"));
// get UDP payload length
payloadlen = htons(packet->udp.udplen);
payloadlen -= 8; // subtract header
// get UDP payload data
payloaddata = &((unsigned char*)packet)[IP_HEADER_LEN+UDP_HEADER_LEN];
SPrint_P(PSTR("UDP packet, len: "));
Serial.println((unsigned int)len, DEC);
// debugPrintHexTable(len, (unsigned char*)packet);
if(packet->udp.destport == HTONS(CONTROL_PORT))
{
// command packet
processCommand(payloadlen, payloaddata);
}
else if(packet->udp.destport == HTONS(SERIAL_PORT))
{
// serial output
for(i=0; i<payloadlen; i++)
Serial.print(payloaddata[i]);
}
else if(packet->udp.destport == HTONS(LOOPBACK_PORT))
{
// loopback - return packet to sender
udpSend(htonl(packet->ip.srcipaddr), LOOPBACK_PORT, payloadlen, payloaddata);
}
}
void netstackTCPIPProcess(unsigned int len, tcpip_hdr* packet)
{
SPrint_P(PSTR("Rvd tcp Packet: len="));
Serial.println((unsigned int)len, DEC);
}
void processCommand(u16 len, u08* data)
{
SPrint_P(PSTR("Rvd UDP : CMD="));
Serial.print(data[0], HEX);
SPrint_P(PSTR(" ARG0="));
Serial.println(data[1], HEX);
// do something based on command
switch(data[0])
{
case 'C': // set PORTC
PORTC = data[1];
break; // set DDRC
case 'c':
PORTC = data[1];
break;
default:
SPrintln_P(PSTR("Unkown UDP command"));
break;
}
}
void serviceLocal(void)
{
byte c;
char* buffer[100];
if(Serial.available())
{
c = Serial.read();
Serial.println(c);
// process command
switch(c)
{
/*
case 'a': // Assert CS
{
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
} break;
case 's': // reSet CS
{
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
} break;
*/
case 'a' :
{
arpPrintTable();
} break;
case 'd':
{
nicRegDump();
} break;
case 'i':
{
nicInit();
} break;
case 'n': // Netstack init
{
nicSoftReset();
netstackInit(IPADDRESS, NETMASK, GATEWAY);
} break;
case 'b': // reBoot
{
nicReboot();
} break;
case 'v': // reVision
{
SPrint_P(PSTR("RevID: "));
Serial.println((byte)(enc28j60Read(EREVID)), BIN);
} break;
case 'p':
{
SPrintln_P(PSTR("IP Configs"));
SPrint_P(PSTR("IP:"));
Serial.println(ipGetConfig()->ip);
SPrint_P(PSTR("Gateway:"));
Serial.println(ipGetConfig()->gateway);
SPrint_P(PSTR("Netmask:"));
Serial.println(ipGetConfig()->netmask);
} break;
/*
case 'x':
{
char b[2048] = "a";
unsigned int i = 0;
Serial.println();
for (i = 1; 1; i++) {
SPrint_P(PSTR(".")); delay(250);
b[i] = 255;
}
}
break;
*/
case '1':
enc28j60PhyWrite(PHLCON, 0x3992); // Off/On
break;
case '2':
enc28j60PhyWrite(PHLCON, 0x3882); // On/On
break;
case '3':
// A: Display link status and transmit/receive activity B: Display link status and receive activity
enc28j60PhyWrite(PHLCON, 0x3DC2);
break;
case '4':
enc28j60PhyWrite(PHLCON, 0x3DE2); // Default(?)
break;
case 'l': // read LED
SPrint_P(PSTR("PHLCON: 00"));
Serial.println((long int)(enc28j60PhyRead(PHLCON)), BIN);
break;
case 'u':
{
SPrintln_P(PSTR("Sending UDP packet"));
strcpy(buffer[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN], "hello");
SPrintln_P(PSTR("Buffered string"));
udpSend(IPDOT(192l,168l,0l,12l), CONTROL_PORT, 6, (uint8_t*)buffer[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN]);
SPrintln_P(PSTR("UDP Sent"));
} break;
case '?':
{
SPrintln_P(PSTR("Usage:"));
SPrintln_P(PSTR("(a) Print ARP table"));
SPrintln_P(PSTR("(d) Dump nic registers"));
SPrintln_P(PSTR("(i) Nic initialization"));
SPrintln_P(PSTR("(n) Netstack initialization"));
SPrintln_P(PSTR("(b) Reboot NIC"));
SPrintln_P(PSTR("(v) Display NIC revision"));
SPrintln_P(PSTR("(p) Print IP configuration"));
SPrintln_P(PSTR("(l) Display lamps register"));
SPrintln_P(PSTR("(1-4) Set lamps register"));
SPrintln_P(PSTR("(u) Send UDP packet"));
SPrintln_P(PSTR("(?) Print this help"));
} break;
case '\n':
default:
break;
}
delay(10);
// print new prompt
SPrint_P(PSTR("cmd> "));
}
}
void setup(void)
{
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, HIGH);
Serial.begin(115200);
delay(100);
// init network stack
SPrintln_P(PSTR("Initializing Network Stack!"));
netstackInit(IPADDRESS, NETMASK, GATEWAY);
SPrint_P(PSTR("Net Stack is up!"));
SPrint_P(PSTR("\r\ncmd> "));
}
void loop(void)
{
// service local stuff
serviceLocal();
netstackService();
}

@ -0,0 +1,138 @@
/*! \file net.c \brief Network support library. */
//*****************************************************************************
//
// File Name : 'net.c'
// Title : Network support library
// Author : Pascal Stang
// Created : 8/30/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include <inttypes.h>
#include "HardwareSerial.h"
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "net.h"
uint16_t htons(uint16_t val)
{
return (val<<8) | (val>>8);
}
uint32_t htonl(uint32_t val)
{
return (htons(val>>16) | (uint32_t)htons(val&0x0000FFFF)<<16);
}
uint16_t netChecksum(netIpHeader *data, uint16_t len)
{
register uint32_t sum = 0;
for (;;) {
if (len < 2)
break;
//sum += *((uint16_t *)data)++;
sum += *((uint16_t *)data);
data+=2;
len -= 2;
}
if (len)
sum += *(uint8_t *) data;
while ((len = (uint16_t) (sum >> 16)) != 0)
sum = (uint16_t) sum + len;
Serial.print("Checksum: ");
Serial.println((uint16_t) sum ^ 0xFFFF, HEX);
return (uint16_t) sum ^ 0xFFFF;
}
void netPrintEthAddr(struct netEthAddr* ethaddr)
{
Serial.print(ethaddr->addr[0], HEX);
Serial.print(':');
Serial.print(ethaddr->addr[1], HEX);
Serial.print(':');
Serial.print(ethaddr->addr[2], HEX);
Serial.print(':');
Serial.print(ethaddr->addr[3], HEX);
Serial.print(':');
Serial.print(ethaddr->addr[4], HEX);
Serial.print(':');
Serial.print(ethaddr->addr[5], HEX);
}
void netPrintIPAddr(uint32_t ipaddr)
{
Serial.print(((unsigned char*)&ipaddr)[3], DEC);
SPrint_P(PSTR("."));
Serial.print(((unsigned char*)&ipaddr)[2], DEC);
SPrint_P(PSTR("."));
Serial.print(((unsigned char*)&ipaddr)[1], DEC);
SPrint_P(PSTR("."));
Serial.print(((unsigned char*)&ipaddr)[0], DEC);
}
/*
void netPrintEthHeader(struct netEthHeader* eth_hdr)
{
SPrint_P(PSTR("Eth Packet Type: 0x"));
Serial.print(eth_hdr->type);
SPrint_P(PSTR(" SRC:"));
netPrintEthAddr(&eth_hdr->src);
SPrint_P(PSTR("->DST:"));
netPrintEthAddr(&eth_hdr->dest);
Serial.println();
}
void netPrintIpHeader(struct netIpHeader* ipheader)
{
SPrint_P(PSTR("IP Header\r\n"));
SPrint_P(PSTR("Ver : %d\r\n", (ipheader->vhl)>>4);
SPrint_P(PSTR("Length : %d\r\n", htons(ipheader->len));
if(ipheader->proto == IP_PROTO_ICMP)
SPrint_P(PSTR("Protocol: ICMP\r\n"));
else if(ipheader->proto == IP_PROTO_TCP)
SPrint_P(PSTR("Protocol: TCP\r\n"));
else if(ipheader->proto == IP_PROTO_UDP)
SPrint_P(PSTR("Protocol: UDP\r\n"));
else
SPrint_P(PSTR("Protocol: %d\r\n", ipheader->proto);
SPrint_P(PSTR("SourceIP: ")); netPrintIPAddr(htonl(ipheader->srcipaddr)); Serial.println();
SPrint_P(PSTR("Dest IP: ")); netPrintIPAddr(htonl(ipheader->destipaddr)); Serial.println();
}
void netPrintTcpHeader(struct netTcpHeader* tcpheader)
{
SPrint_P(PSTR("TCP Header\r\n"));
SPrint_P(PSTR("Src Port: %d\r\n", htons(tcpheader->srcport));
SPrint_P(PSTR("Dst Port: %d\r\n", htons(tcpheader->destport));
SPrint_P(PSTR("Seq Num : 0x")); Serial.printu32(htonl(tcpheader->seqno)); Serial.println();
SPrint_P(PSTR("Ack Num : 0x")); Serial.printu32(htonl(tcpheader->ackno)); Serial.println();
SPrint_P(PSTR("Flags : "));
if(tcpheader->flags & TCP_FLAGS_FIN)
SPrint_P(PSTR("FIN "));
if(tcpheader->flags & TCP_FLAGS_SYN)
SPrint_P(PSTR("SYN "));
if(tcpheader->flags & TCP_FLAGS_RST)
SPrint_P(PSTR("RST "));
if(tcpheader->flags & TCP_FLAGS_PSH)
SPrint_P(PSTR("PSH "));
if(tcpheader->flags & TCP_FLAGS_ACK)
SPrint_P(PSTR("ACK "));
if(tcpheader->flags & TCP_FLAGS_URG)
SPrint_P(PSTR("URG "));
Serial.println();
}
*/

208
net.h

@ -0,0 +1,208 @@
/*! \file net.h \brief Network support library. */
//*****************************************************************************
//
// File Name : 'net.h'
// Title : Network support library
// Author : Pascal Stang
// Created : 8/30/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup net Network support library (net.c)
/// \code #include "net/net.h" \endcode
/// \par Description
/// This is a general network support library including a multitude of
/// structure definitions for various types of network packets, functions
/// and macros for switching byte order, and an RFC-compliant function
/// for calculating checksums.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef NET_H
#define NET_H
#define NET_DEBUG 7
#include "avrlibdefs.h"
#include "avrlibtypes.h"
#include <inttypes.h>
// Representation of a 48-bit Ethernet address.
struct netEthAddr
{
uint8_t addr[6];
} GNUC_PACKED;
// The Ethernet header
struct netEthHeader
{
struct netEthAddr dest;
struct netEthAddr src;
uint16_t type;
} GNUC_PACKED;
#define ETH_HEADER_LEN 14
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
#define ETHTYPE_IP6 0x86dd
// The ARP header
struct netArpHeader
{
uint16_t hwtype;
uint16_t protocol;
uint8_t hwlen;
uint8_t protolen;
uint16_t opcode;
struct netEthAddr shwaddr;
uint32_t sipaddr;
struct netEthAddr dhwaddr;
uint32_t dipaddr;
} GNUC_PACKED;
#define ARP_OPCODE_REQUEST 1
#define ARP_OPCODE_REPLY 2
#define ARP_HWTYPE_ETH 1
// The IP header
struct netIpHeader
{
uint8_t vhl;
uint8_t tos;
uint16_t len;
uint16_t ipid;
uint16_t ipoffset;
uint8_t ttl;
uint8_t proto;
uint16_t ipchksum;
uint32_t srcipaddr;
uint32_t destipaddr;
} GNUC_PACKED;
#define IP_HEADER_LEN 20
#define IP_PROTO_ICMP 1
#define IP_PROTO_TCP 6
#define IP_PROTO_UDP 17
// The ICMP header
struct netIcmpHeader
{
uint8_t type;
uint8_t icode;
uint16_t icmpchksum;
uint16_t id;
uint16_t seqno;
} GNUC_PACKED;
#define ICMP_HEADER_LEN 8
#define ICMP_TYPE_ECHOREPLY 0
#define ICMP_TYPE_ECHOREQUEST 8
// The UDP header
struct netUdpHeader
{
uint16_t srcport;
uint16_t destport;
uint16_t udplen;
uint16_t udpchksum;
} GNUC_PACKED;
#define UDP_HEADER_LEN 8
// The TCP header
struct netTcpHeader
{
uint16_t srcport;
uint16_t destport;
uint32_t seqno;
uint32_t ackno;
uint8_t tcpoffset;
uint8_t flags;
uint16_t wnd;
uint16_t tcpchksum;
uint16_t urgp;
// uint8_t optdata[4];
} GNUC_PACKED;
#define TCP_HEADER_LEN 20
#define TCP_FLAGS_FIN 0x01
#define TCP_FLAGS_SYN 0x02
#define TCP_FLAGS_RST 0x04
#define TCP_FLAGS_PSH 0x08
#define TCP_FLAGS_ACK 0x10
#define TCP_FLAGS_URG 0x20
// Ethernet/ARP header
struct netEthArpHeader
{
struct netEthHeader eth;
struct netArpHeader arp;
} GNUC_PACKED;
// Ethernet/IP header
struct netEthIpHeader
{
struct netEthHeader eth;
struct netIpHeader ip;
} GNUC_PACKED;
// The IP header
typedef struct netIpHeader ip_hdr;
// The IP/TCP headers
typedef struct
{
struct netIpHeader ip;
struct netTcpHeader tcp;
} tcpip_hdr;
// The IP/ICMP headers
typedef struct {
struct netIpHeader ip;
struct netIcmpHeader icmp;
} icmpip_hdr;
// The UDP and IP headers
typedef struct {
struct netIpHeader ip;
struct netUdpHeader udp;
} udpip_hdr;
//! Convert dot-notation IP address into 32-bit word.
/// Example: IPDOT(192l,168l,1l,1l)
#define IPDOT(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|(d))
//! Host-to-Network SHORT (16-bit) byte-order swap (macro).
#define HTONS(s) ((s<<8) | (s>>8))
//! Host-to-Network LONG (32-bit) byte-order swap (macro).
#define HTONL(l) ((l<<24) | ((l&0x00FF0000l)>>8) | ((l&0x0000FF00l)<<8) | (l>>24))
//! Host-to-Network SHORT (16-bit) byte-order swap (function).
uint16_t htons(uint16_t val);
//! Host-to-Network LONG (32-bit) byte-order swap (function).
uint32_t htonl(uint32_t val);
//! Calculate IP-style checksum from data.
uint16_t netChecksum(netIpHeader *data, uint16_t len);
//! Print Ethernet address in XX:XX:XX:XX:XX:XX format.
void netPrintEthAddr(struct netEthAddr* ethaddr);
//! Print IP address in dot notation.
void netPrintIPAddr(uint32_t ipaddr);
//! Print Ethernet header information.
void netPrintEthHeader(struct netEthHeader* eth_hdr);
//! Print IP header information.
void netPrintIpHeader(struct netIpHeader* ipheader);
//! Print TCP header information.
void netPrintTcpHeader(struct netTcpHeader* tcpheader);
#endif
//@}

@ -0,0 +1,161 @@
/*! \file netstack.c \brief Network Stack. */
//*****************************************************************************
//
// File Name : 'netstack.c'
// Title : Network Stack
// Author : Pascal Stang
// Created : 6/28/2005
// Revised : 9/20/2005
// Version : 0.3
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include "debug.h"
#include "netstack.h"
#ifdef NETSTACK_DEBUG
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "HardwareSerial.h"
#endif
unsigned char NetBuffer[NETSTACK_BUFFERSIZE];
void netstackInit(uint32_t ipaddress, uint32_t netmask, uint32_t gatewayip)
{
// init network device driver
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("Initializing Network Device\r\n"));
#endif
nicInit();
// init ARP
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("Initializing ARP cache\r\n"));
#endif
arpInit();
// init addressing
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("Initializing Addressing\r\n"));
#endif
ipSetConfig(ipaddress, netmask, gatewayip);
}
u08* netstackGetBuffer(void)
{
return NetBuffer;
}
int netstackService(void)
{
int len;
struct netEthHeader* ethPacket;
// look for a packet
len = nicPoll(NETSTACK_BUFFERSIZE, NetBuffer);
if(len)
{
ethPacket = (struct netEthHeader*)&NetBuffer[0];
#if NET_DEBUG >= 5
SPrint_P(PSTR("Received packet len: "));
Serial.print((unsigned int)len);
SPrint_P(PSTR(", type:"));
if(ethPacket->type == htons(ETHTYPE_IP))
{
SPrint_P(PSTR("IP"));
}
else if(ethPacket->type == htons(ETHTYPE_ARP))
{
SPrint_P(PSTR("ARP"));
}
SPrint_P(PSTR("Packet Contents\r\n"));
debugPrintHexTable(len, NetBuffer);
#endif
if(ethPacket->type == htons(ETHTYPE_IP))
{
// process an IP packet
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NET Rx: IP packet\r\n"));
#endif
// add the source to the ARP cache
// also correctly set the ethernet packet length before processing?
arpIpIn((struct netEthIpHeader*)&NetBuffer[0]);
arpPrintTable();
netstackIPProcess( len-ETH_HEADER_LEN, (ip_hdr*)&NetBuffer[ETH_HEADER_LEN] );
}
else if(ethPacket->type == htons(ETHTYPE_ARP))
{
// process an ARP packet
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NET Rx: ARP packet\r\n"));
#endif
arpPrintTable();
arpArpIn(len, ((struct netEthArpHeader*)&NetBuffer[0]) );
}
}
return len;
}
void netstackIPProcess(unsigned int len, ip_hdr* packet)
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("entering netstackIPProcess\r\n"));
//icmpPrintHeader((icmpip_hdr*)packet);
#endif
// check IP addressing, stop processing if not for me and not a broadcast
if( (htonl(packet->destipaddr) != ipGetConfig()->ip) &&
(htonl(packet->destipaddr) != (ipGetConfig()->ip|ipGetConfig()->netmask)) &&
(htonl(packet->destipaddr) != 0xFFFFFFFF) )
return;
// handle ICMP packet
if( packet->proto == IP_PROTO_ICMP )
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NET Rx: ICMP/IP packet\r\n"));
//icmpPrintHeader((icmpip_hdr*)packet);
#endif
icmpIpIn((icmpip_hdr*)packet);
}
else if( packet->proto == IP_PROTO_UDP )
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NET Rx: UDP/IP packet\r\n"));
//debugPrintHexTable(NetBufferLen-14, &NetBuffer[14]);
#endif
netstackUDPIPProcess(len, ((udpip_hdr*)packet) );
}
else if( packet->proto == IP_PROTO_TCP )
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NET Rx: TCP/IP packet\r\n"));
#endif
netstackTCPIPProcess(len, ((tcpip_hdr*)packet) );
}
else
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NET Rx: IP packet\r\n"));
#endif
}
}
void netstackUDPIPProcess(unsigned int len, udpip_hdr* packet)
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NetStack UDP/IP Rx Dummy Handler\r\n"));
#endif
}
void netstackTCPIPProcess(unsigned int len, tcpip_hdr* packet)
{
#ifdef NETSTACK_DEBUG
SPrint_P(PSTR("NetStack TCP/IP Rx Dummy Handler\r\n"));
#endif
}

@ -0,0 +1,85 @@
/*! \file netstack.h \brief Network Stack. */
//*****************************************************************************
//
// File Name : 'netstack.h'
// Title : Network Stack
// Author : Pascal Stang
// Created : 6/28/2005
// Revised : 9/20/2005
// Version : 0.3
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup netstack Network Stack (netstack.c)
/// \code #include "net/netstack.h" \endcode
/// \par Description
/// This library co-ordinates the various pieces of a typical IP network
/// stack into one unit. Included are handling for ARP, ICMP, and IP
/// packets. UDP and TCP packets are processed and passed to the user.
///
/// This is an example of how to use the various network libraries, and
/// is meant to be useful out-of-the-box for most users. However, some
/// users may find it restrictive and write their own handlers instead.
/// This stack implementation is by no means the only way to use the various
/// network libraries.
///
/// \note This is NOT a full-blown TCP/IP stack. It merely handles lower
/// level stack functions so that UDP and TCP packets can be sent
/// and received easily. End-to-end TCP functionality may be added
/// in a future version. Until then, I can recommend using other embedded
/// TCP/IP stacks like Adam Dunkel's uIP.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef NETSTACK_H
#define NETSTACK_H
#include "net.h"
#include "arp.h"
#include "icmp.h"
#include "ip.h"
#include "nic.h"
#define NETSTACK_DEBUG
/// NET_BUFFERSIZE is the common receive/process/transmit buffer.
/// - You may override the default NET_BUFFERSIZE by defining an alternate value in global.h.
/// - Network packets larger than NET_BUFFERSIZE will not be accepted.
#ifndef NETSTACK_BUFFERSIZE
#define NETSTACK_BUFFERSIZE (576+ETH_HEADER_LEN)
#endif
/// netstackInit prepares the network interface for use and should be called
/// once at the beginning of the user program.
/// \note Use ipSetAddress() to change network parameters in mid-run.
void netstackInit(uint32_t ipaddress, uint32_t netmask, uint32_t gatewayip);
/// netstackGetBuffer returns a pointer to the common receive/process/transmit buffer.
u08* netstackGetBuffer(void);
/// netstackService should be called in the main loop of the user program.
/// The function will process one received network packet per call.
/// The return value is the length of the packet processed, or zero if no
/// packet was processed.
int netstackService(void);
/// netstackIPProcess handles distribution of IP received packets.
///
void netstackIPProcess(unsigned int len, ip_hdr* packet);
/// This weakly-defined function is the default handler for incoming UDP/IP packets.
/// Users should define this same function in user code (same name and arguments) to
/// override this default handler and get access to the received packets.
void netstackUDPIPProcess(unsigned int len, udpip_hdr* packet) __attribute__ ((weak));
/// This weakly-defined function is the default handler for incoming TCP/IP packets.
/// Users should define this same function in user code (same name and arguments) to
/// override this default handler and get access to the received packets.
void netstackTCPIPProcess(unsigned int len, tcpip_hdr* packet) __attribute__ ((weak));
#endif
//@}

80
nic.h

@ -0,0 +1,80 @@
/*! \file nic.h \brief Network Interface Card (NIC) software definition. */
//*****************************************************************************
//
// File Name : 'nic.h'
// Title : Network Interface Card (NIC) software definition
// Author : Pascal Stang
// Created : 8/22/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
/// \ingroup network
/// \defgroup nic Network Interface Card (NIC) software definition (nic.h)
/// \code #include "net/nic.h" \endcode
/// \par Description
/// This is the software interface standard for network interface hardware
/// as used by AVRlib. Drivers for network hardware must implement these
/// functions to allow upper network layers to initialize the interface,
/// and send and receive net traffic.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//*****************************************************************************
//@{
#ifndef NIC_H
#define NIC_H
#include <inttypes.h>
//! Initialize network interface hardware.
/// Reset and bring up network interface hardware. This function should leave
/// the network interface ready to handle \c nicSend() and \c nicPoll() requests.
/// \note For some hardware, this command will take a non-negligible amount of
/// time (1-2 seconds).
void nicInit(void);
//! Send packet on network interface.
/// Function accepts the length (in bytes) of the data to be sent, and a pointer
/// to the data. This send command may assume an ethernet-like 802.3 header is at the
/// beginning of the packet, and contains the packet addressing information.
/// See net.h documentation for ethernet header format.
void nicSend(unsigned int len, unsigned char* packet);
//! Check network interface; return next received packet if avaialable.
/// Function accepts the maximum allowable packet length (in bytes), and a
/// pointer to the received packet buffer. Return value is the length
/// (in bytes) of the packet recevied, or zero if no packet is available.
/// Upper network layers may assume that an ethernet-like 802.3 header is at
/// the beginning of the packet, and contains the packet addressing information.
/// See net.h documentation for ethernet header format.
unsigned int nicPoll(unsigned int maxlen, unsigned char* packet);
//! Return the 48-bit hardware node (MAC) address of this network interface.
/// This function can return a MAC address read from the NIC hardware, if available.
/// If the hardware does not provide a MAC address, a software-defined address may be
/// returned. It may be acceptable to return an address that is less than 48-bits.
void nicGetMacAddress(uint8_t* macaddr);
//! Set the 48-bit hardware node (MAC) address of this network interface.
/// This function may not be supported on all hardware.
void nicSetMacAddress(uint8_t* macaddr);
//! Print network interface hardware registers.
/// Prints a formatted list of names and values of NIC registers for debugging
/// purposes.
void nicRegDump(void);
//! PHY Chip hard reset function
void nicHardReset(void);
//! PHY Chip soft reset function
void nicSoftReset(void);
//! PHY Chip reboot
void nicReboot(void);
#endif
//@}

@ -0,0 +1,40 @@
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "wiring.h"
#include "HardwareSerial.h"
// call with printString(PSTR("My string"))
void SPrint_P(const char *data)
{
char ch;
for (;;) {
ch = pgm_read_byte( data++ );
if ( !ch ) return;
Serial.print(ch);
}
}
void SPrintln_P(const char *data)
{
SPrint_P(data);
SPrint_P(PSTR("\r\n"));
}
void SPrintHex_P(const char *data)
{
char ch;
for (;;) {
ch = pgm_read_byte( data++ );
if ( !ch ) return;
Serial.print(ch, HEX);
}
}
void SPrintlnHex_P(const char *data)
{
printString(data);
Serial.println();
}

@ -0,0 +1,13 @@
#ifndef isDef_programStrings
#define isDef_programStrings
#ifndef nop
#define nop() asm volatile ("nop")
#endif
void SPrint_P(const char *data);
void SPrintln_P(const char *data);
void SPrintHex_P(const char *data);
void SPrintlnHex_P(const char *data);
#endif
Loading…
Cancel
Save