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