git-svn-id: svn+ssh://oldsvn/home/mlalondesvn/svn/Ethduino@1 b05466c9-153a-0410-ad00-ea1d4d8a27b5master
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
|
@ -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,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
|
@ -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
|
||||
//@}
|
@ -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(ðaddr, 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(ðIpHeader->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();
|
||||
}
|
@ -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(ð_hdr->src);
|
||||
SPrint_P(PSTR("->DST:"));
|
||||
netPrintEthAddr(ð_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();
|
||||
}
|
||||
*/
|
||||
|
@ -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
|
||||
//@}
|
@ -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…
Reference in new issue