Added part15-tcpip - same as part14-ethernet, but replies to pings now

This commit is contained in:
Adam Greenwood-Byrne 2021-11-06 17:16:46 +00:00
parent ababff0e38
commit bc2ecc934d
29 changed files with 6081 additions and 0 deletions

20
part15-tcpip/Makefile Normal file
View file

@ -0,0 +1,20 @@
CFILES = $(wildcard *.c lib/*.c kernel/*.c net/*.c tcpip/*.c)
SFILES = $(wildcard boot/*.S lib/*.S kernel/*.S)
OFILES = $(CFILES:.c=.o) $(SFILES:.S=.o)
LLVMPATH = /opt/homebrew/opt/llvm/bin
CLANGFLAGS = -Wall -O0 -ffreestanding -nostdlib -mcpu=cortex-a72+nosimd
all: clean kernel8.img
%.o: %.c
$(LLVMPATH)/clang --target=aarch64-elf $(CLANGFLAGS) -c $< -o $@
%.o: %.S
$(LLVMPATH)/clang --target=aarch64-elf $(CLANGFLAGS) -c $< -o $@
kernel8.img: $(OFILES)
$(LLVMPATH)/ld.lld -m aarch64elf -nostdlib $(OFILES) -T boot/link.ld -o kernel8.elf
$(LLVMPATH)/llvm-objcopy -O binary kernel8.elf kernel8.img
clean:
/bin/rm kernel8.elf */*.o *.img > /dev/null 2> /dev/null || true

20
part15-tcpip/Makefile.gcc Normal file
View file

@ -0,0 +1,20 @@
CFILES = $(wildcard *.c lib/*.c kernel/*.c net/*.c tcpip/*.c)
SFILES = $(wildcard boot/*.S lib/*.S kernel/*.S)
OFILES = $(CFILES:.c=.o) $(SFILES:.S=.o)
GCCFLAGS = -Wall -O0 -ffreestanding -nostdlib -nostartfiles
GCCPATH = ../../gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin
all: clean kernel8.img
%.o: %.c
$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c $< -o $@
%.o: %.S
$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c $< -o $@
kernel8.img: $(OFILES)
$(GCCPATH)/aarch64-none-elf-ld -nostdlib $(OFILES) -T boot/link.ld -o kernel8.elf
$(GCCPATH)/aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
/bin/rm kernel8.elf */*.o *.img > /dev/null 2> /dev/null || true

114
part15-tcpip/boot/boot.S Normal file
View file

@ -0,0 +1,114 @@
#include "sysregs.h"
#define LOCAL_CONTROL 0xff800000
#define LOCAL_PRESCALER 0xff800008
#define OSC_FREQ 54000000
#define MAIN_STACK 0x400000
.section ".text.boot" // Make sure the linker puts this at the start of the kernel image
.global _start // Execution starts here
_start:
ldr x0, =LOCAL_CONTROL // Sort out the timer
str wzr, [x0]
mov w1, 0x80000000
str w1, [x0, #(LOCAL_PRESCALER - LOCAL_CONTROL)]
ldr x0, =OSC_FREQ
msr cntfrq_el0, x0
msr cntvoff_el2, xzr
// Check processor ID is zero (executing on main core), else hang
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// We're not on the main core, so hang in an infinite wait loop
adr x5, spin_cpu0
1: wfe
ldr x4, [x5, x1, lsl #3]
cbz x4, 1b
ldr x2, =__stack_start // Get ourselves a fresh stack - location depends on CPU core asking
lsl x1, x1, #9 // Multiply core_number by 512
add x3, x2, x1 // Add to the address
mov sp, x3
mov x0, #0
mov x1, #0
mov x2, #0
mov x3, #0
br x4
b 1b
2: // We're on the main core!
// First enable the FPU
mov x0, #0x33ff
msr cptr_el3, x0 // Disable coprocessor traps to EL3
mov x0, #3 << 20
msr cpacr_el1, x0 // Enable FP/SIMD at EL1
// Now get ready to switch from EL3 down to EL1
ldr x0, =SCTLR_VALUE_MMU_DISABLED
msr sctlr_el1, x0
ldr x0, =HCR_VALUE
msr hcr_el2, x0
ldr x0, =SCR_VALUE
msr scr_el3, x0
ldr x0, =SPSR_VALUE
msr spsr_el3, x0
adr x0, el1_entry
msr elr_el3, x0
eret
el1_entry:
// We're in EL1
// Clean the BSS section
ldr x1, =__bss_start // Start address
ldr w2, =__bss_size // Size of the section
3: cbz w2, 4f // Quit loop if zero
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b // Loop if non-zero
// Set stack to start somewhere safe
mov sp, #MAIN_STACK
// Jump to our main() routine in C (make sure it doesn't return)
4: bl main
// In case it does return, halt the master core too
b 1b
.ltorg
.org 0x110
.globl spin_cpu0
spin_cpu0:
.quad 0
.org 0x118
.globl spin_cpu1
spin_cpu1:
.quad 0
.org 0x120
.globl spin_cpu2
spin_cpu2:
.quad 0
.org 0x128
.globl spin_cpu3
spin_cpu3:
.quad 0
.globl get_el
get_el:
mrs x0, CurrentEL
lsr x0, x0, #2
ret

35
part15-tcpip/boot/link.ld Normal file
View file

@ -0,0 +1,35 @@
SECTIONS
{
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
__bss_size = (__bss_end - __bss_start)>>3;
}
.cpu1Stack :
{
. = ALIGN(16);
__stack_start = .;
. = . + 512;
__cpu1_stack = .;
}
.cpu2Stack :
{
. = . + 512;
__cpu2_stack = .;
}
.cpu3Stack :
{
. = . + 512;
__cpu3_stack = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}

View file

@ -0,0 +1,44 @@
#ifndef _SYSREGS_H
#define _SYSREGS_H
// ***************************************
// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual.
// ***************************************
#define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11)
#define SCTLR_EE_LITTLE_ENDIAN (0 << 25)
#define SCTLR_EOE_LITTLE_ENDIAN (0 << 24)
#define SCTLR_I_CACHE_DISABLED (0 << 12)
#define SCTLR_D_CACHE_DISABLED (0 << 2)
#define SCTLR_I_CACHE_ENABLED (1 << 12)
#define SCTLR_D_CACHE_ENABLED (1 << 2)
#define SCTLR_MMU_DISABLED (0 << 0)
#define SCTLR_MMU_ENABLED (1 << 0)
#define SCTLR_VALUE_MMU_DISABLED (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_ENABLED | SCTLR_D_CACHE_ENABLED | SCTLR_MMU_DISABLED)
// ***************************************
// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual.
// ***************************************
#define HCR_RW (1 << 31)
#define HCR_VALUE HCR_RW
// ***************************************
// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual.
// ***************************************
#define SCR_RESERVED (3 << 4)
#define SCR_RW (1 << 10)
#define SCR_NS (1 << 0)
#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS)
// ***************************************
// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual.
// ***************************************
#define SPSR_MASK_ALL (7 << 6)
#define SPSR_EL1h (5 << 0)
#define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h)
#endif

14
part15-tcpip/include/fb.h Normal file
View file

@ -0,0 +1,14 @@
void fb_init();
void drawPixel(int x, int y, unsigned char attr);
void drawChar(unsigned char ch, int x, int y, unsigned char attr, int zoom);
void drawString(int x, int y, char *s, unsigned char attr, int zoom);
void drawRect(int x1, int y1, int x2, int y2, unsigned char attr, int fill);
void drawCircle(int x0, int y0, int radius, unsigned char attr, int fill);
void drawLine(int x1, int y1, int x2, int y2, unsigned char attr);
void moveRect(int oldx, int oldy, int width, int height, int shiftx, int shifty, unsigned char attr);
void wait_msec(unsigned int n);
void debugstr(char *str);
void debugcrlf(void);
void debugch(unsigned char b);
void debughex(unsigned int d);
int strlen(const char *str);

19
part15-tcpip/include/io.h Normal file
View file

@ -0,0 +1,19 @@
#define PERIPHERAL_BASE 0xFE000000
#define LEGACY_BASE 0x7E000000
#define SAFE_ADDRESS 0x00400000 // Somewhere safe to store a lot of data
void uart_init();
void uart_writeText(char *buffer);
void uart_loadOutputFifo();
unsigned char uart_readByte();
unsigned int uart_isReadByteReady();
void uart_writeByteBlockingActual(unsigned char ch);
void uart_update();
void mmio_write(long reg, unsigned int val);
unsigned int mmio_read(long reg);
void gpio_useAsAlt0(unsigned int pin_number);
void gpio_useAsAlt3(unsigned int pin_number);
void gpio_setPinOutputBool(unsigned int pin_number, unsigned int onOrOff);
void gpio_initOutputPinWithPullNone(unsigned int pin_number);
void uart_hex(unsigned int d);
void uart_byte(unsigned char b);

34
part15-tcpip/include/mb.h Normal file
View file

@ -0,0 +1,34 @@
extern volatile unsigned int mbox[36];
enum {
MBOX_REQUEST = 0
};
enum {
MBOX_CH_POWER = 0,
MBOX_CH_FB = 1,
MBOX_CH_VUART = 2,
MBOX_CH_VCHIQ = 3,
MBOX_CH_LEDS = 4,
MBOX_CH_BTNS = 5,
MBOX_CH_TOUCH = 6,
MBOX_CH_COUNT = 7,
MBOX_CH_PROP = 8 // Request from ARM for response by VideoCore
};
enum {
MBOX_TAG_SETPOWER = 0x28001,
MBOX_TAG_SETCLKRATE = 0x38002,
MBOX_TAG_SETPHYWH = 0x48003,
MBOX_TAG_SETVIRTWH = 0x48004,
MBOX_TAG_SETVIRTOFF = 0x48009,
MBOX_TAG_SETDEPTH = 0x48005,
MBOX_TAG_SETPXLORDR = 0x48006,
MBOX_TAG_GETFB = 0x40001,
MBOX_TAG_GETPITCH = 0x40008,
MBOX_TAG_LAST = 0
};
unsigned int mbox_call(unsigned char ch);

View file

@ -0,0 +1,11 @@
extern unsigned int spin_cpu0;
extern unsigned int spin_cpu1;
extern unsigned int spin_cpu2;
extern unsigned int spin_cpu3;
void start_core1(void (*func)(void));
void start_core2(void (*func)(void));
void start_core3(void (*func)(void));
void clear_core1(void);
void clear_core2(void);
void clear_core3(void);

View file

@ -0,0 +1,6 @@
void spi_init();
void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size);
void spi_send(unsigned char *data, unsigned int size);
void spi_recv(unsigned char *data, unsigned int size);
void spi_send_no_selection(unsigned char command);
void spi_chip_select(unsigned char chip_select);

View file

@ -0,0 +1,253 @@
unsigned int vgapal[] = {
0x000000,
0x0000AA,
0x00AA00,
0x00AAAA,
0xAA0000,
0xAA00AA,
0xAA5500,
0xAAAAAA,
0x555555,
0x5555FF,
0x55FF55,
0x55FFFF,
0xFF5555,
0xFF55FF,
0xFFFF55,
0xFFFFFF
};
enum {
FONT_WIDTH = 8,
FONT_HEIGHT = 8,
FONT_BPG = 8, // Bytes per glyph
FONT_BPL = 1, // Bytes per line
FONT_NUMGLYPHS = 224
};
unsigned char font[FONT_NUMGLYPHS][FONT_BPG] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;)
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007F
{ 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x18, 0x30, 0x1E}, // U+00C7 (C cedille)
{ 0x00, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FC (u umlaut)
{ 0x38, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E9 (e aigu)
{ 0x7E, 0xC3, 0x3C, 0x60, 0x7C, 0x66, 0xFC, 0x00}, // U+00E2 (a circumflex)
{ 0x33, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E4 (a umlaut)
{ 0x07, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E0 (a grave)
{ 0x0C, 0x0C, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E5 (a ring)
{ 0x00, 0x00, 0x1E, 0x03, 0x03, 0x1E, 0x30, 0x1C}, // U+00E7 (c cedille)
{ 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00}, // U+00EA (e circumflex)
{ 0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00EB (e umlaut)
{ 0x07, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E8 (e grave)
{ 0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EF (i umlaut)
{ 0x3E, 0x63, 0x1C, 0x18, 0x18, 0x18, 0x3C, 0x00}, // U+00EE (i circumflex)
{ 0x07, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EC (i grave)
{ 0x63, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x63, 0x00}, // U+00C4 (A umlaut)
{ 0x0C, 0x0C, 0x00, 0x1E, 0x33, 0x3F, 0x33, 0x00}, // U+00C5 (A ring)
{ 0x07, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C8 (E grave)
{ 0x00, 0x00, 0xFE, 0x30, 0xFE, 0x33, 0xFE, 0x00}, // U+00E6 (ae)
{ 0x7C, 0x36, 0x33, 0x7F, 0x33, 0x33, 0x73, 0x00}, // U+00C6 (AE)
{ 0x1E, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F4 (o circumflex)
{ 0x00, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F6 (o umlaut)
{ 0x00, 0x07, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F2 (o grave)
{ 0x1E, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FB (u circumflex)
{ 0x00, 0x07, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00F9 (u grave)
{ 0x00, 0x33, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+00FF (y umlaut)
{ 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, // U+00D6 (O umlaut)
{ 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+00DC (U umlaut)
{ 0x18, 0x18, 0x7E, 0x03, 0x03, 0x7E, 0x18, 0x18}, // U+00A2 (dollarcents)
{ 0x1C, 0x36, 0x26, 0x0F, 0x06, 0x67, 0x3F, 0x00}, // U+00A3 (pound sterling)
{ 0x33, 0x33, 0x1E, 0x3F, 0x0C, 0x3F, 0x0C, 0x0C}, // U+00A5 (yen)
{ 0x7C, 0xC6, 0x1C, 0x36, 0x36, 0x1C, 0x33, 0x1E}, // U+00A7 (paragraph)
{ 0x70, 0xD8, 0x18, 0x3C, 0x18, 0x18, 0x1B, 0x0E}, // U+0192 (dutch florijn)
{ 0x38, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E1 (a aigu)
{ 0x1C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00ED (i augu)
{ 0x00, 0x38, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F3 (o aigu)
{ 0x00, 0x38, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FA (u aigu)
{ 0x00, 0x1F, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x00}, // U+00F1 (n ~)
{ 0x3F, 0x00, 0x33, 0x37, 0x3F, 0x3B, 0x33, 0x00}, // U+00D1 (N ~)
{ 0x3C, 0x36, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00}, // U+00AA (superscript a)
{ 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00BA (superscript 0)
{ 0x0C, 0x00, 0x0C, 0x06, 0x03, 0x33, 0x1E, 0x00}, // U+00BF (inverted ?)
{ 0x00, 0x00, 0x00, 0x3F, 0x03, 0x03, 0x00, 0x00}, // U+2310 (gun pointing right)
{ 0x00, 0x00, 0x00, 0x3F, 0x30, 0x30, 0x00, 0x00}, // U+00AC (gun pointing left)
{ 0xC3, 0x63, 0x33, 0x7B, 0xCC, 0x66, 0x33, 0xF0}, // U+00BD (1/2)
{ 0xC3, 0x63, 0x33, 0xBD, 0xEC, 0xF6, 0xF3, 0x03}, // U+00BC (1/4)
{ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00}, // U+00A1 (inverted !)
{ 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, // U+00AB (<<)
{ 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, // U+00BB (>>)
{ 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00}, // U+2591 (25% solid)
{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, // U+2592 (50% solid)
{ 0xFF, 0xAA, 0xFF, 0x55, 0xFF, 0xAA, 0xFF, 0x55}, // U+2593 (75% solid)
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // U+2502 (thin vertical)
{ 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08}, // U+2524 (down L, left L, up L)
{ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x08, 0x08}, // U+2561 (up L, down L, left D)
{ 0x14, 0x14, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14}, // U+2562 (up D, down D, left L)
{ 0x00, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x14, 0x14}, // U+2556 (down D, left L)
{ 0x00, 0x00, 0x00, 0x0F, 0x08, 0x0F, 0x08, 0x08}, // U+2555 (down L, left D)
{ 0x14, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14}, // U+2563 (up D, down D, left D)
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, // U+2551 (double vertical)
{ 0x00, 0x00, 0x00, 0x1F, 0x10, 0x17, 0x14, 0x14}, // U+2557 (down D, left D)
{ 0x14, 0x14, 0x14, 0x17, 0x10, 0x1F, 0x00, 0x00}, // U+255D (up D, left D)
{ 0x14, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x00, 0x00}, // U+255C (up D, left L)
{ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x00, 0x00}, // U+255B (up L, left D)
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08}, // U+2510 (down L, left L)
{ 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, 0x00}, // U+2514 (up L, right L)
{ 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0x00, 0x00}, // U+2534 (up L, right L, left L)
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08}, // U+252C (down L, right L, left L)
{ 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08}, // U+251C (down L, right L, up L)
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, // U+2500 (thin horizontal)
{ 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08}, // U+253C (up L, right L, left L, down L)
{ 0x08, 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x08, 0x08}, // U+255E (up L, down L, right D)
{ 0x14, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x14, 0x14}, // U+255F (up D, down D, right L)
{ 0x14, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x00, 0x00}, // U+255A (up D, right D)
{ 0x00, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14}, // U+2554 (down D, right D)
{ 0x14, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00}, // U+2569 (left D, right D, up D)
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14}, // U+2566 (left D, right D, down D)
{ 0x14, 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x14, 0x14}, // U+2560 (up D, down D, right D)
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00}, // U+2550 (double horizontal)
{ 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14}, // U+256C (left D, right D, down D, up D)
{ 0x08, 0x08, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x00}, // U+2567 (left D, right D, up L)
{ 0x14, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x00, 0x00}, // U+2568 (left L, right L, up D)
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x08, 0x08}, // U+2564 (left D, right D, down L)
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x14, 0x14}, // U+2565 (left L, right L, down D)
{ 0x14, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x00, 0x00}, // U+2559 (up D, right L)
{ 0x08, 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x00, 0x00}, // U+2558 (up L, right D)
{ 0x00, 0x00, 0x00, 0xF8, 0x08, 0xF8, 0x08, 0x08}, // U+2552 (down L, right D)
{ 0x00, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x14, 0x14}, // U+2553 (down D, right L)
{ 0x14, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x14, 0x14}, // U+256B (left L, right L, down D, up D)
{ 0x08, 0x08, 0x08, 0xFF, 0x08, 0xFF, 0x08, 0x08}, // U+256A (left D, right D, down L, up L)
{ 0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00}, // U+2518 (up L, left L)
{ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08}, // U+250C (down L, right L)
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // U+2588 (solid)
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}, // U+2584 (bottom half)
{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, // U+258C (left half)
{ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, // U+2590 (right half)
{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, // U+2580 (top half)
};

199
part15-tcpip/kernel/arp.c Normal file
View file

@ -0,0 +1,199 @@
#include "../net/enc28j60.h"
#include "../include/fb.h"
#include "../tcpip/ip_arp_udp_tcp.h"
ENC_HandleTypeDef handle;
// Structure for Ethernet header
typedef struct {
uint8_t DestAddrs[6];
uint8_t SrcAddrs[6];
uint16_t type;
} EtherNetII;
// Ethernet packet types
#define ARPPACKET 0x0608
#define IPPACKET 0x0008
// Structure for an ARP Packet
typedef struct {
EtherNetII eth;
uint16_t hardware;
uint16_t protocol;
uint8_t hardwareSize;
uint8_t protocolSize;
uint16_t opCode;
uint8_t senderMAC[6];
uint8_t senderIP[4];
uint8_t targetMAC[6];
uint8_t targetIP[4];
} ARP;
// ARP OpCodes
#define ARPREPLY 0x0200
#define ARPREQUEST 0x0100
// ARP hardware types
#define ETHERNET 0x0100
// MAC address to be assigned to the ENC28J60
uint8_t myMAC[6] = { 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee };
// Router MAC is not known to start with, and requires an ARP reply to find out
uint8_t routerMAC[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
// IP address to be assigned to the ENC28J60
uint8_t deviceIP[4] = { 192, 168, 0, 66 };
// IP Address of the router, whose hardware address we will find using the ARP request
uint8_t routerIP[4] = { 192, 168, 0, 1 };
// HELPER FUNCTIONS
void *memset(void *dest, unsigned char val, unsigned short len)
{
uint8_t *ptr = dest;
while (len-- > 0)
*ptr++ = val;
return dest;
}
void *memcpy(void *dest, const void *src, unsigned short len)
{
uint8_t *d = dest;
const uint8_t *s = src;
while (len--)
*d++ = *s++;
return dest;
}
uint8_t memcmp(void *str1, void *str2, unsigned count)
{
uint8_t *s1 = str1;
uint8_t *s2 = str2;
while (count-- > 0)
{
if (*s1++ != *s2++)
return s1[-1] < s2[-1] ? -1 : 1;
}
return 0;
}
// MAIN FUNCTIONS
void SendArpPacket(uint8_t *targetIP, uint8_t *deviceMAC)
{
/* Parameters:
* targetIP - The target IP Address for the ARP request (the one whose hardware
* address we want)
* deviceMAC - The MAC address of the ENC28J60, i.e. the source MAC for the ARP
* request
*/
ARP arpPacket;
// The source of the packet will be the ENC28J60 MAC address
memcpy(arpPacket.eth.SrcAddrs, deviceMAC, 6);
// The destination is broadcast - a MAC address of FF:FF:FF:FF:FF:FF */
memset(arpPacket.eth.DestAddrs, 0xFF, 6);
arpPacket.eth.type = ARPPACKET;
arpPacket.hardware = ETHERNET;
// We want an IP address resolved
arpPacket.protocol = IPPACKET;
arpPacket.hardwareSize = 0x06; // sizeof(deviceMAC);
arpPacket.protocolSize = 0x04; // sizeof(deviceIP);
arpPacket.opCode = ARPREQUEST;
// Target MAC is set to 0 as it is unknown
memset(arpPacket.targetMAC, 0, 6);
// Sender MAC is the ENC28J60's MAC address
memcpy(arpPacket.senderMAC, deviceMAC, 6);
// The target IP is the IP address we want resolved
memcpy(arpPacket.targetIP, targetIP, 4);
// Check if the last reply has come from an IP address that we want i.e. someone else is already using it
if (!memcmp(targetIP, deviceIP, 4)) {
// Yes, someone is using our IP so set the sender IP to 0.0.0.0
memset(arpPacket.senderIP, 0, 4);
} else {
// No, nobody is using our IP so we can use it confidently
memcpy(arpPacket.senderIP, deviceIP, 4);
}
// Send the packet
debugstr("Sending ARP request.");
debugcrlf();
enc28j60PacketSend(sizeof(ARP), &arpPacket);
}
void net_test(void)
{
while (1) {
while (!ENC_GetReceivedFrame(&handle));
uint16_t len = handle.RxFrameInfos.length;
uint8_t *buffer = (uint8_t *)handle.RxFrameInfos.buffer;
packetloop_arp_icmp_tcp(buffer, len);
}
}
void enc28j60PacketSend(unsigned short buflen, void *buffer) {
if (ENC_RestoreTXBuffer(&handle, buflen) == 0) {
ENC_WriteBuffer((unsigned char *) buffer, buflen);
handle.transmitLength = buflen;
ENC_Transmit(&handle);
}
}
void init_network(void)
{
handle.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
handle.Init.MACAddr = myMAC;
handle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
handle.Init.InterruptEnableBits = EIE_LINKIE | EIE_PKTIE;
debugstr("Starting network up.");
debugcrlf();
if (!ENC_Start(&handle)) {
debugstr("Could not initialise network card.");
} else {
debugstr("Setting MAC address to C0:FF:EE:C0:FF:EE.");
debugcrlf();
ENC_SetMacAddr(&handle);
debugstr("Network card successfully initialised.");
}
debugcrlf();
debugstr("Waiting for ifup... ");
while (!(handle.LinkStatus & PHSTAT2_LSTAT)) ENC_IRQHandler(&handle);
debugstr("done.");
debugcrlf();
debugstr("Initialising the TCP stack... ");
init_udp_or_www_server(myMAC, deviceIP);
debugstr("done.");
debugcrlf();
// Re-enable global interrupts
ENC_EnableInterrupts(EIE_INTIE);
}

58
part15-tcpip/kernel/irq.c Normal file
View file

@ -0,0 +1,58 @@
#include "kernel.h"
#include "../include/fb.h"
char *entry_error_messages[] = {
"SYNC_INVALID_EL1t",
"IRQ_INVALID_EL1t",
"FIQ_INVALID_EL1t",
"ERROR_INVALID_EL1T",
"SYNC_INVALID_EL1h",
"IRQ_INVALID_EL1h",
"FIQ_INVALID_EL1h",
"ERROR_INVALID_EL1h",
"SYNC_INVALID_EL0_64",
"IRQ_INVALID_EL0_64",
"FIQ_INVALID_EL0_64",
"ERROR_INVALID_EL0_64",
"SYNC_INVALID_EL0_32",
"IRQ_INVALID_EL0_32",
"FIQ_INVALID_EL0_32",
"ERROR_INVALID_EL0_32"
};
void enable_interrupt_controller() {
REGS_IRQ->irq0_enable_0 = SYS_TIMER_IRQ_1 | SYS_TIMER_IRQ_3;
}
void disable_interrupt_controller() {
REGS_IRQ->irq0_enable_0 = 0;
}
void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) {
debugstr(entry_error_messages[type]);
debugstr(" ESR: ");
debughex(esr);
debugstr("Addr: ");
debughex(address);
}
void handle_irq() {
unsigned int irq = REGS_IRQ->irq0_pending_0;
while(irq) {
if (irq & SYS_TIMER_IRQ_1) {
irq &= ~SYS_TIMER_IRQ_1;
handle_timer_1();
}
if (irq & SYS_TIMER_IRQ_3) {
irq &= ~SYS_TIMER_IRQ_3;
handle_timer_3();
}
}
}

View file

@ -0,0 +1,156 @@
#define SYNC_INVALID_EL1t 0
#define IRQ_INVALID_EL1t 1
#define FIQ_INVALID_EL1t 2
#define ERROR_INVALID_EL1t 3
#define SYNC_INVALID_EL1h 4
#define IRQ_INVALID_EL1h 5
#define FIQ_INVALID_EL1h 6
#define ERROR_INVALID_EL1h 7
#define SYNC_INVALID_EL0_64 8
#define IRQ_INVALID_EL0_64 9
#define FIQ_INVALID_EL0_64 10
#define ERROR_INVALID_EL0_64 11
#define SYNC_INVALID_EL0_32 12
#define IRQ_INVALID_EL0_32 13
#define FIQ_INVALID_EL0_32 14
#define ERROR_INVALID_EL0_32 15
//stack frame size
#define S_FRAME_SIZE 256
.macro kernel_entry
sub sp, sp, #S_FRAME_SIZE
stp x0, x1, [sp, #16 * 0]
stp x2, x3, [sp, #16 * 1]
stp x4, x5, [sp, #16 * 2]
stp x6, x7, [sp, #16 * 3]
stp x8, x9, [sp, #16 * 4]
stp x10, x11, [sp, #16 * 5]
stp x12, x13, [sp, #16 * 6]
stp x14, x15, [sp, #16 * 7]
stp x16, x17, [sp, #16 * 8]
stp x18, x19, [sp, #16 * 9]
stp x20, x21, [sp, #16 * 10]
stp x22, x23, [sp, #16 * 11]
stp x24, x25, [sp, #16 * 12]
stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14]
str x30, [sp, #16 * 15]
.endm
.macro kernel_exit
ldp x0, x1, [sp, #16 * 0]
ldp x2, x3, [sp, #16 * 1]
ldp x4, x5, [sp, #16 * 2]
ldp x6, x7, [sp, #16 * 3]
ldp x8, x9, [sp, #16 * 4]
ldp x10, x11, [sp, #16 * 5]
ldp x12, x13, [sp, #16 * 6]
ldp x14, x15, [sp, #16 * 7]
ldp x16, x17, [sp, #16 * 8]
ldp x18, x19, [sp, #16 * 9]
ldp x20, x21, [sp, #16 * 10]
ldp x22, x23, [sp, #16 * 11]
ldp x24, x25, [sp, #16 * 12]
ldp x26, x27, [sp, #16 * 13]
ldp x28, x29, [sp, #16 * 14]
ldr x30, [sp, #16 * 15]
add sp, sp, #S_FRAME_SIZE
eret
.endm
.macro handle_invalid_entry type
kernel_entry
mov x0, #\type
mrs x1, esr_el1
mrs x2, elr_el1
bl show_invalid_entry_message
b err_hang
.endm
.macro ventry label
.align 7
b \label
.endm
//Exception vectors table
.align 11
.globl vectors
vectors:
ventry sync_invalid_el1t // Synchronous EL1t
ventry irq_invalid_el1t // IRQ EL1t
ventry fiq_invalid_el1t // FIQ EL1t
ventry error_invalid_el1t // Error EL1t
ventry sync_invalid_el1h // Synchronous EL1h
ventry handle_el1_irq // IRQ EL1h
ventry fiq_invalid_el1h // FIQ EL1h
ventry error_invalid_el1h // Error EL1h
ventry sync_invalid_el0_64 // Synchronous 64-bit EL0
ventry irq_invalid_el0_64 // IRQ 64-bit EL0
ventry fiq_invalid_el0_64 // FIQ 64-bit EL0
ventry error_invalid_el0_64 // Error 64-bit EL0
ventry sync_invalid_el0_32 // Synchronous 32-bit EL0
ventry irq_invalid_el0_32 // IRQ 32-bit EL0
ventry fiq_invalid_el0_32 // FIQ 32-bit EL0
ventry error_invalid_el0_32 // Error 32-bit EL0
sync_invalid_el1t:
handle_invalid_entry SYNC_INVALID_EL1t
irq_invalid_el1t:
handle_invalid_entry IRQ_INVALID_EL1t
fiq_invalid_el1t:
handle_invalid_entry FIQ_INVALID_EL1t
error_invalid_el1t:
handle_invalid_entry ERROR_INVALID_EL1t
sync_invalid_el1h:
handle_invalid_entry SYNC_INVALID_EL1h
fiq_invalid_el1h:
handle_invalid_entry FIQ_INVALID_EL1h
error_invalid_el1h:
handle_invalid_entry ERROR_INVALID_EL1h
sync_invalid_el0_64:
handle_invalid_entry SYNC_INVALID_EL0_64
irq_invalid_el0_64:
handle_invalid_entry IRQ_INVALID_EL0_64
fiq_invalid_el0_64:
handle_invalid_entry FIQ_INVALID_EL0_64
error_invalid_el0_64:
handle_invalid_entry ERROR_INVALID_EL0_64
sync_invalid_el0_32:
handle_invalid_entry SYNC_INVALID_EL0_32
irq_invalid_el0_32:
handle_invalid_entry IRQ_INVALID_EL0_32
fiq_invalid_el0_32:
handle_invalid_entry FIQ_INVALID_EL0_32
error_invalid_el0_32:
handle_invalid_entry ERROR_INVALID_EL0_32
handle_el1_irq:
kernel_entry
bl handle_irq
kernel_exit
.globl err_hang
err_hang: b err_hang

View file

@ -0,0 +1,176 @@
#include "../include/fb.h"
#include "../include/io.h"
#include "../include/spi.h"
#include "../include/multicore.h"
#include "../net/enc28j60.h"
#include "kernel.h"
void initProgress(void)
{
drawRect(0, 0, 301, 50, 0x0f, 0);
drawString(309, 21, "Core 0", 0x0f, 1);
drawRect(0, 60, 301, 110, 0x0f, 0);
drawString(309, 81, "Core 1", 0x0f, 1);
drawRect(0, 120, 301, 170, 0x0f, 0);
drawString(309, 141, "Timer 1", 0x0f, 1);
drawRect(0, 180, 301, 230, 0x0f, 0);
drawString(309, 201, "Timer 3", 0x0f, 1);
}
void drawProgress(unsigned int core, unsigned int val) {
unsigned char col = (core + 1) + ((core + 1) << 4);
// val should be 0-100
if (val == 0) drawRect(1, (60 * core) + 1, 300, (60 * core) + 49, 0x00, 1);
if (val > 0) drawRect(1, (60 * core) + 1, (val * 3), (60 * core) + 49, col, 1);
}
void core3_main(void) {
clear_core3(); // Only run once
// Test the network card
spi_init();
init_network();
net_test();
while(1);
}
void core0_main(void)
{
unsigned int core0_val = 0;
while (core0_val <= 100) {
wait_msec(0x100000);
drawProgress(0, core0_val);
core0_val++;
}
debugstr("Core 0 done.");
debugcrlf();
}
void core1_main(void)
{
unsigned int core1_val = 0;
clear_core1(); // Only run once
while (core1_val <= 100) {
wait_msec(0x3FFFF);
drawProgress(1, core1_val);
core1_val++;
}
debugstr("Core 1 done.");
debugcrlf();
while(1);
}
// TIMER FUNCTIONS
const unsigned int timer1_int = CLOCKHZ;
const unsigned int timer3_int = CLOCKHZ / 4;
unsigned int timer1_val = 0;
unsigned int timer3_val = 0;
void timer_init() {
timer1_val = REGS_TIMER->counter_lo;
timer1_val += timer1_int;
REGS_TIMER->compare[1] = timer1_val;
timer3_val = REGS_TIMER->counter_lo;
timer3_val += timer3_int;
REGS_TIMER->compare[3] = timer3_val;
}
void handle_timer_1() {
timer1_val += timer1_int;
REGS_TIMER->compare[1] = timer1_val;
REGS_TIMER->control_status |= SYS_TIMER_IRQ_1;
unsigned int progval = timer1_val / timer1_int;
if (progval <= 100) {
drawProgress(2, progval);
} else {
debugstr("Timer 1 done.");
debugcrlf();
}
}
void handle_timer_3() {
timer3_val += timer3_int;
REGS_TIMER->compare[3] = timer3_val;
REGS_TIMER->control_status |= SYS_TIMER_IRQ_3;
unsigned int progval = timer3_val / timer3_int;
if (progval <= 100) drawProgress(3, progval);
}
unsigned long timer_get_ticks() {
unsigned int hi = REGS_TIMER->counter_hi;
unsigned int lo = REGS_TIMER->counter_lo;
//double check hi value didn't change after setting it...
if (hi != REGS_TIMER->counter_hi) {
hi = REGS_TIMER->counter_hi;
lo = REGS_TIMER->counter_lo;
}
return ((unsigned long)hi << 32) | lo;
}
void timer_sleep(unsigned int ms) {
unsigned long start = timer_get_ticks();
while(timer_get_ticks() < start + (ms * 1000));
}
void HAL_Delay(volatile unsigned int Delay) {
timer_sleep(Delay);
}
unsigned int HAL_GetTick(void) {
return timer_get_ticks();
}
void main(void)
{
fb_init();
unsigned int i=0;
while (i++<30) debugcrlf();
initProgress();
// Kick it off on core 1
start_core1(core1_main);
// Kick off the timers
irq_init_vectors();
enable_interrupt_controller();
irq_enable();
timer_init();
// Kick it off on core 3
start_core3(core3_main);
// Kick it off on core 0
core0_main();
// Disable IRQs and loop endlessly
irq_disable();
disable_interrupt_controller();
while(1);
}

View file

@ -0,0 +1,56 @@
#define PERIPHERAL_BASE 0xFE000000
#define CLOCKHZ 1000000
struct timer_regs {
volatile unsigned int control_status;
volatile unsigned int counter_lo;
volatile unsigned int counter_hi;
volatile unsigned int compare[4];
};
#define REGS_TIMER ((struct timer_regs *)(PERIPHERAL_BASE + 0x00003000))
struct arm_irq_regs_2711 {
volatile unsigned int irq0_pending_0;
volatile unsigned int irq0_pending_1;
volatile unsigned int irq0_pending_2;
volatile unsigned int res0;
volatile unsigned int irq0_enable_0;
volatile unsigned int irq0_enable_1;
volatile unsigned int irq0_enable_2;
volatile unsigned int res1;
volatile unsigned int irq0_disable_0;
volatile unsigned int irq0_disable_1;
volatile unsigned int irq0_disable_2;
};
typedef struct arm_irq_regs_2711 arm_irq_regs;
#define REGS_IRQ ((arm_irq_regs *)(PERIPHERAL_BASE + 0x0000B200))
enum vc_irqs {
SYS_TIMER_IRQ_0 = 1,
SYS_TIMER_IRQ_1 = 2,
SYS_TIMER_IRQ_2 = 4,
SYS_TIMER_IRQ_3 = 8,
AUX_IRQ = (1 << 29)
};
void irq_init_vectors();
void irq_enable();
void irq_disable();
void enable_interrupt_controller();
void disable_interrupt_controller();
void handle_timer_1();
void handle_timer_3();
unsigned long timer_get_ticks();
void timer_sleep(unsigned int ms);
void HAL_Delay(volatile unsigned int Delay);
unsigned int HAL_GetTick(void);
void init_network(void);
void net_test(void);
void enc28j60PacketSend(unsigned short buflen, void *buffer);
void *memcpy(void *dest, const void *src, unsigned short len);

View file

@ -0,0 +1,15 @@
.globl irq_init_vectors
irq_init_vectors:
adr x0, vectors
msr vbar_el1, x0
ret
.globl irq_enable
irq_enable:
msr daifclr, #2
ret
.globl irq_disable
irq_disable:
msr daifset, #2
ret

260
part15-tcpip/lib/fb.c Normal file
View file

@ -0,0 +1,260 @@
#include "../include/io.h"
#include "../include/mb.h"
#include "../include/terminal.h"
unsigned int width, height, pitch, isrgb;
unsigned char *fb;
int curx = 0;
int cury = 0;
void fb_init()
{
mbox[0] = 35*4; // Length of message in bytes
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETPHYWH; // Tag identifier
mbox[3] = 8; // Value size in bytes
mbox[4] = 0;
mbox[5] = 1920; // Value(width)
mbox[6] = 1080; // Value(height)
mbox[7] = MBOX_TAG_SETVIRTWH;
mbox[8] = 8;
mbox[9] = 8;
mbox[10] = 1920;
mbox[11] = 1080;
mbox[12] = MBOX_TAG_SETVIRTOFF;
mbox[13] = 8;
mbox[14] = 8;
mbox[15] = 0; // Value(x)
mbox[16] = 0; // Value(y)
mbox[17] = MBOX_TAG_SETDEPTH;
mbox[18] = 4;
mbox[19] = 4;
mbox[20] = 32; // Bits per pixel
mbox[21] = MBOX_TAG_SETPXLORDR;
mbox[22] = 4;
mbox[23] = 4;
mbox[24] = 1; // RGB
mbox[25] = MBOX_TAG_GETFB;
mbox[26] = 8;
mbox[27] = 8;
mbox[28] = 4096; // FrameBufferInfo.pointer
mbox[29] = 0; // FrameBufferInfo.size
mbox[30] = MBOX_TAG_GETPITCH;
mbox[31] = 4;
mbox[32] = 4;
mbox[33] = 0; // Bytes per line
mbox[34] = MBOX_TAG_LAST;
// Check call is successful and we have a pointer with depth 32
if (mbox_call(MBOX_CH_PROP) && mbox[20] == 32 && mbox[28] != 0) {
mbox[28] &= 0x3FFFFFFF; // Convert GPU address to ARM address
width = mbox[10]; // Actual physical width
height = mbox[11]; // Actual physical height
pitch = mbox[33]; // Number of bytes per line
isrgb = mbox[24]; // Pixel order
fb = (unsigned char *)((long)mbox[28]);
}
}
void drawPixel(int x, int y, unsigned char attr)
{
int offs = (y * pitch) + (x * 4);
*((unsigned int*)(fb + offs)) = vgapal[attr & 0x0f];
}
void drawRect(int x1, int y1, int x2, int y2, unsigned char attr, int fill)
{
int y=y1;
while (y <= y2) {
int x=x1;
while (x <= x2) {
if ((x == x1 || x == x2) || (y == y1 || y == y2)) drawPixel(x, y, attr);
else if (fill) drawPixel(x, y, (attr & 0xf0) >> 4);
x++;
}
y++;
}
}
void drawLine(int x1, int y1, int x2, int y2, unsigned char attr)
{
int dx, dy, p, x, y;
dx = x2-x1;
dy = y2-y1;
x = x1;
y = y1;
p = 2*dy-dx;
while (x<x2) {
if (p >= 0) {
drawPixel(x,y,attr);
y++;
p = p+2*dy-2*dx;
} else {
drawPixel(x,y,attr);
p = p+2*dy;
}
x++;
}
}
void drawCircle(int x0, int y0, int radius, unsigned char attr, int fill)
{
int x = radius;
int y = 0;
int err = 0;
while (x >= y) {
if (fill) {
drawLine(x0 - y, y0 + x, x0 + y, y0 + x, (attr & 0xf0) >> 4);
drawLine(x0 - x, y0 + y, x0 + x, y0 + y, (attr & 0xf0) >> 4);
drawLine(x0 - x, y0 - y, x0 + x, y0 - y, (attr & 0xf0) >> 4);
drawLine(x0 - y, y0 - x, x0 + y, y0 - x, (attr & 0xf0) >> 4);
}
drawPixel(x0 - y, y0 + x, attr);
drawPixel(x0 + y, y0 + x, attr);
drawPixel(x0 - x, y0 + y, attr);
drawPixel(x0 + x, y0 + y, attr);
drawPixel(x0 - x, y0 - y, attr);
drawPixel(x0 + x, y0 - y, attr);
drawPixel(x0 - y, y0 - x, attr);
drawPixel(x0 + y, y0 - x, attr);
if (err <= 0) {
y += 1;
err += 2*y + 1;
}
if (err > 0) {
x -= 1;
err -= 2*x + 1;
}
}
}
void drawChar(unsigned char ch, int x, int y, unsigned char attr, int zoom)
{
unsigned char *glyph = (unsigned char *)&font + (ch < FONT_NUMGLYPHS ? ch : 0) * FONT_BPG;
for (int i=1;i<=(FONT_HEIGHT*zoom);i++) {
for (int j=0;j<(FONT_WIDTH*zoom);j++) {
unsigned char mask = 1 << (j/zoom);
unsigned char col = (*glyph & mask) ? attr & 0x0f : (attr & 0xf0) >> 4;
drawPixel(x+j, y+i, col);
}
glyph += (i%zoom) ? 0 : FONT_BPL;
}
}
void drawString(int x, int y, char *s, unsigned char attr, int zoom)
{
while (*s) {
if (*s == '\r') {
x = 0;
} else if(*s == '\n') {
x = 0; y += (FONT_HEIGHT*zoom);
} else {
drawChar(*s, x, y, attr, zoom);
x += (FONT_WIDTH*zoom);
}
s++;
}
}
void moveRect(int oldx, int oldy, int width, int height, int shiftx, int shifty, unsigned char attr)
{
unsigned int newx = oldx + shiftx, newy = oldy + shifty;
unsigned int xcount = 0, ycount = 0;
unsigned int bitmap[width][height]; // This is very unsafe if it's too big for the stack...
unsigned int offs;
// Save the bitmap
while (xcount < width) {
while (ycount < height) {
offs = ((oldy + ycount) * pitch) + ((oldx + xcount) * 4);
bitmap[xcount][ycount] = *((unsigned int*)(fb + offs));
ycount++;
}
ycount=0;
xcount++;
}
// Wipe it out with background colour
drawRect(oldx, oldy, oldx + width, oldy + width, attr, 1);
// Draw it again
for (int i=newx;i<newx + width;i++) {
for (int j=newy;j<newy + height;j++) {
offs = (j * pitch) + (i * 4);
*((unsigned int*)(fb + offs)) = bitmap[i-newx][j-newy];
}
}
}
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// Get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// Read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// Calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
int strlen(const char *str) {
const char *s;
for (s = str; *s; ++s);
return (s - str);
}
void debugstr(char *str) {
if (curx + (strlen(str) * 8) >= 1920) {
curx = 0; cury += 8;
}
if (cury + 8 >= 1080) {
cury = 0;
}
drawString(curx, cury, str, 0x0f, 1);
curx += (strlen(str) * 8);
}
void debugcrlf(void) {
curx = 0; cury += 8;
}
void debugch(unsigned char b) {
unsigned int n;
int c;
for(c=4;c>=0;c-=4) {
n=(b>>c)&0xF;
n+=n>9?0x37:0x30;
debugstr((char *)&n);
}
debugstr(" ");
}
void debughex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
n=(d>>c)&0xF;
n+=n>9?0x37:0x30;
debugstr((char *)&n);
}
debugstr(" ");
}

199
part15-tcpip/lib/io.c Normal file
View file

@ -0,0 +1,199 @@
#include "../include/io.h"
// GPIO
enum {
GPFSEL0 = PERIPHERAL_BASE + 0x200000,
GPSET0 = PERIPHERAL_BASE + 0x20001C,
GPCLR0 = PERIPHERAL_BASE + 0x200028,
GPPUPPDN0 = PERIPHERAL_BASE + 0x2000E4
};
enum {
GPIO_MAX_PIN = 53,
GPIO_FUNCTION_OUT = 1,
GPIO_FUNCTION_ALT5 = 2,
GPIO_FUNCTION_ALT3 = 7,
GPIO_FUNCTION_ALT0 = 4
};
enum {
Pull_None = 0,
Pull_Down = 1, // Are down and up the right way around?
Pull_Up = 2
};
void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
unsigned int field_mask = (1 << field_size) - 1;
if (pin_number > field_max) return 0;
if (value > field_mask) return 0;
unsigned int num_fields = 32 / field_size;
unsigned int reg = base + ((pin_number / num_fields) * 4);
unsigned int shift = (pin_number % num_fields) * field_size;
unsigned int curval = mmio_read(reg);
curval &= ~(field_mask << shift);
curval |= value << shift;
mmio_write(reg, curval);
return 1;
}
unsigned int gpio_set (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
unsigned int gpio_clear (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
unsigned int gpio_pull (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
void gpio_useAsAlt0(unsigned int pin_number) {
gpio_pull(pin_number, Pull_None);
gpio_function(pin_number, GPIO_FUNCTION_ALT0);
}
void gpio_useAsAlt3(unsigned int pin_number) {
gpio_pull(pin_number, Pull_None);
gpio_function(pin_number, GPIO_FUNCTION_ALT3);
}
void gpio_useAsAlt5(unsigned int pin_number) {
gpio_pull(pin_number, Pull_None);
gpio_function(pin_number, GPIO_FUNCTION_ALT5);
}
void gpio_initOutputPinWithPullNone(unsigned int pin_number) {
gpio_pull(pin_number, Pull_None);
gpio_function(pin_number, GPIO_FUNCTION_OUT);
}
void gpio_setPinOutputBool(unsigned int pin_number, unsigned int onOrOff) {
if (onOrOff) {
gpio_set(pin_number, 1);
} else {
gpio_clear(pin_number, 1);
}
}
// UART
enum {
AUX_BASE = PERIPHERAL_BASE + 0x215000,
AUX_IRQ = AUX_BASE,
AUX_ENABLES = AUX_BASE + 4,
AUX_MU_IO_REG = AUX_BASE + 64,
AUX_MU_IER_REG = AUX_BASE + 68,
AUX_MU_IIR_REG = AUX_BASE + 72,
AUX_MU_LCR_REG = AUX_BASE + 76,
AUX_MU_MCR_REG = AUX_BASE + 80,
AUX_MU_LSR_REG = AUX_BASE + 84,
AUX_MU_MSR_REG = AUX_BASE + 88,
AUX_MU_SCRATCH = AUX_BASE + 92,
AUX_MU_CNTL_REG = AUX_BASE + 96,
AUX_MU_STAT_REG = AUX_BASE + 100,
AUX_MU_BAUD_REG = AUX_BASE + 104,
AUX_UART_CLOCK = 500000000,
UART_MAX_QUEUE = 16 * 1024
};
#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
unsigned char uart_output_queue[UART_MAX_QUEUE];
unsigned int uart_output_queue_write = 0;
unsigned int uart_output_queue_read = 0;
void uart_init() {
mmio_write(AUX_ENABLES, 1); //enable UART1
mmio_write(AUX_MU_IER_REG, 0);
mmio_write(AUX_MU_CNTL_REG, 0);
mmio_write(AUX_MU_LCR_REG, 3); //8 bits
mmio_write(AUX_MU_MCR_REG, 0);
mmio_write(AUX_MU_IER_REG, 0);
mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
gpio_useAsAlt5(14);
gpio_useAsAlt5(15);
mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
}
unsigned int uart_isOutputQueueEmpty() {
return uart_output_queue_read == uart_output_queue_write;
}
unsigned int uart_isReadByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x01; }
unsigned int uart_isWriteByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x20; }
unsigned char uart_readByte() {
while (!uart_isReadByteReady());
return (unsigned char)mmio_read(AUX_MU_IO_REG);
}
void uart_writeByteBlockingActual(unsigned char ch) {
while (!uart_isWriteByteReady());
mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
}
void uart_loadOutputFifo() {
while (!uart_isOutputQueueEmpty() && uart_isWriteByteReady()) {
uart_writeByteBlockingActual(uart_output_queue[uart_output_queue_read]);
uart_output_queue_read = (uart_output_queue_read + 1) & (UART_MAX_QUEUE - 1); // Don't overrun
}
}
void uart_writeByteBlocking(unsigned char ch) {
unsigned int next = (uart_output_queue_write + 1) & (UART_MAX_QUEUE - 1); // Don't overrun
while (next == uart_output_queue_read) uart_loadOutputFifo();
uart_output_queue[uart_output_queue_write] = ch;
uart_output_queue_write = next;
}
void uart_writeText(char *buffer) {
while (*buffer) {
if (*buffer == '\n') uart_writeByteBlockingActual('\r');
uart_writeByteBlockingActual(*buffer++);
}
}
void uart_drainOutputQueue() {
while (!uart_isOutputQueueEmpty()) uart_loadOutputFifo();
}
void uart_update() {
uart_loadOutputFifo();
if (uart_isReadByteReady()) {
unsigned char ch = uart_readByte();
if (ch == '\r') uart_writeText("\n"); else uart_writeByteBlocking(ch);
}
}
void uart_hex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_writeByteBlockingActual(n);
}
}
void uart_byte(unsigned char b) {
unsigned int n;
int c;
for(c=4;c>=0;c-=4) {
// get highest tetrad
n=(b>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_writeByteBlockingActual(n);
}
uart_writeByteBlockingActual(' ');
}

39
part15-tcpip/lib/mb.c Normal file
View file

@ -0,0 +1,39 @@
#include "../include/io.h"
// The buffer must be 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox
volatile unsigned int __attribute__((aligned(16))) mbox[36];
enum {
VIDEOCORE_MBOX = (PERIPHERAL_BASE + 0x0000B880),
MBOX_READ = (VIDEOCORE_MBOX + 0x0),
MBOX_POLL = (VIDEOCORE_MBOX + 0x10),
MBOX_SENDER = (VIDEOCORE_MBOX + 0x14),
MBOX_STATUS = (VIDEOCORE_MBOX + 0x18),
MBOX_CONFIG = (VIDEOCORE_MBOX + 0x1C),
MBOX_WRITE = (VIDEOCORE_MBOX + 0x20),
MBOX_RESPONSE = 0x80000000,
MBOX_FULL = 0x80000000,
MBOX_EMPTY = 0x40000000
};
unsigned int mbox_call(unsigned char ch)
{
// 28-bit address (MSB) and 4-bit value (LSB)
unsigned int r = ((unsigned int)((long) &mbox) &~ 0xF) | (ch & 0xF);
// Wait until we can write
while (mmio_read(MBOX_STATUS) & MBOX_FULL);
// Write the address of our buffer to the mailbox with the channel appended
mmio_write(MBOX_WRITE, r);
while (1) {
// Is there a reply?
while (mmio_read(MBOX_STATUS) & MBOX_EMPTY);
// Is it a reply to our message?
if (r == mmio_read(MBOX_READ)) return mbox[1]==MBOX_RESPONSE; // Is it successful?
}
return 0;
}

View file

@ -0,0 +1,44 @@
#include "../include/multicore.h"
void store32(unsigned long address, unsigned long value)
{
*(unsigned long *) address = value;
}
unsigned long load32(unsigned long address)
{
return *(unsigned long *) address;
}
void start_core1(void (*func)(void))
{
store32((unsigned long)&spin_cpu1, (unsigned long)func);
asm volatile ("sev");
}
void start_core2(void (*func)(void))
{
store32((unsigned long)&spin_cpu2, (unsigned long)func);
asm volatile ("sev");
}
void start_core3(void (*func)(void))
{
store32((unsigned long)&spin_cpu3, (unsigned long)func);
asm volatile ("sev");
}
void clear_core1(void)
{
store32((unsigned long)&spin_cpu1, 0);
}
void clear_core2(void)
{
store32((unsigned long)&spin_cpu2, 0);
}
void clear_core3(void)
{
store32((unsigned long)&spin_cpu3, 0);
}

100
part15-tcpip/lib/spi.c Normal file
View file

@ -0,0 +1,100 @@
#include "../include/io.h"
#include "../include/fb.h"
// SPI
struct Spi0Regs {
volatile unsigned int cs;
volatile unsigned int fifo;
volatile unsigned int clock;
volatile unsigned int data_length;
volatile unsigned int ltoh;
volatile unsigned int dc;
};
#define REGS_SPI0 ((struct Spi0Regs *)(PERIPHERAL_BASE + 0x00204000))
// CS Register
#define CS_LEN_LONG (1 << 25)
#define CS_DMA_LEN (1 << 24)
#define CS_CSPOL2 (1 << 23)
#define CS_CSPOL1 (1 << 22)
#define CS_CSPOL0 (1 << 21)
#define CS_RXF (1 << 20)
#define CS_RXR (1 << 19)
#define CS_TXD (1 << 18)
#define CS_RXD (1 << 17)
#define CS_DONE (1 << 16)
#define CS_LEN (1 << 13)
#define CS_REN (1 << 12)
#define CS_ADCS (1 << 11)
#define CS_INTR (1 << 10)
#define CS_INTD (1 << 9)
#define CS_DMAEN (1 << 8)
#define CS_TA (1 << 7)
#define CS_CSPOL (1 << 6)
#define CS_CLEAR_RX (1 << 5)
#define CS_CLEAR_TX (1 << 4)
#define CS_CPOL__SHIFT 3
#define CS_CPHA__SHIFT 2
#define CS_CS (1 << 0)
#define CS_CS__SHIFT 0
void spi_init() {
gpio_useAsAlt0(7); //CS1
gpio_initOutputPinWithPullNone(8); //CS0
gpio_useAsAlt0(9); //MISO
gpio_useAsAlt0(10); //MOSI
gpio_useAsAlt0(11); //SCLK
}
void spi_chip_select(unsigned char chip_select) {
gpio_setPinOutputBool(8, chip_select);
}
void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size) {
REGS_SPI0->data_length = size;
REGS_SPI0->cs = REGS_SPI0->cs | CS_CLEAR_RX | CS_CLEAR_TX | CS_TA;
unsigned int read_count = 0;
unsigned int write_count = 0;
while(read_count < size || write_count < size) {
while(write_count < size && REGS_SPI0->cs & CS_TXD) {
if (sbuffer) {
REGS_SPI0->fifo = *sbuffer++;
} else {
REGS_SPI0->fifo = 0;
}
write_count++;
}
while(read_count < size && REGS_SPI0->cs & CS_RXD) {
unsigned int data = REGS_SPI0->fifo;
if (rbuffer) {
*rbuffer++ = data;
}
read_count++;
}
}
while(!(REGS_SPI0->cs & CS_DONE)) {
while(REGS_SPI0->cs & CS_RXD) {
unsigned int r = REGS_SPI0->fifo;
debughex(r);
}
}
REGS_SPI0->cs = (REGS_SPI0->cs & ~CS_TA);
}
void spi_send(unsigned char *data, unsigned int size) {
spi_send_recv(data, 0, size);
}
void spi_recv(unsigned char *data, unsigned int size) {
spi_send_recv(0, data, size);
}

1450
part15-tcpip/net/enc28j60.c Normal file

File diff suppressed because it is too large Load diff

816
part15-tcpip/net/enc28j60.h Normal file
View file

@ -0,0 +1,816 @@
/**
******************************************************************************
* @file enc28j60.h
* @author Christian Schoffit, portions from Gregory Nutt:
* Copyright (C) 2010-2012, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* @version V1.0.0
* @date 02-June-2015
* @brief This file provides a set of functions needed to manage the ENC28J60
* Stand-Alone Ethernet Controller with SPI Interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2015 Christian Schoffit</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Christian Schoffit nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
#ifndef ENC28J60_H_INCLUDED
#define ENC28J60_H_INCLUDED
#include <stdint.h>
#include <stdbool.h>
#ifdef USE_PROTOTHREADS
#include "pt.h"
#else
#define PT_BEGIN(x)
#define PT_END(x)
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
/* Ethernet frames are between 64 and 1518 bytes long */
#define MIN_FRAMELEN 64
#define MAX_FRAMELEN 1518
/* External functions --------------------------------------------------------*/
void HAL_Delay(volatile uint32_t Delay);
uint32_t HAL_GetTick(void);
/* Callback functions *********************************************************/
/**
* Implement SPI Slave selection and deselection. Must be provided by user code
* param select: true if the ENC28J60 slave SPI if selected, false otherwise
* retval none
*/
void ENC_SPI_Select(bool select);
/**
* Implement SPI single byte send and receive.
* The ENC28J60 slave SPI must already be selected and wont be deselected after transmission
* Must be provided by user code
* param command: command or data to be sent to ENC28J60
* retval answer from ENC28J60
*/
void ENC_SPI_SendWithoutSelection(uint8_t command);
/**
* Implement SPI single byte send and receive. Must be provided by user code
* param command: command or data to be sent to ENC28J60
* retval answer from ENC28J60
*/
void ENC_SPI_Send(uint8_t command);
/**
* Implement SPI buffer send and receive. Must be provided by user code
* param master2slave: data to be sent from host to ENC28J60, can be NULL if we only want to receive data from slave
* param slave2master: answer from ENC28J60 to host, can be NULL if we only want to send data to slave
* retval none
*/
void ENC_SPI_SendBuf(uint8_t *master2slave, uint8_t *slave2master, uint16_t bufferSize);
/* Exported types ------------------------------------------------------------*/
/** @defgroup ETH_Exported_Types ETH Exported Types
* @{
*/
/**
* @brief ETH Init Structure definition
*/
typedef struct
{
uint32_t DuplexMode; /*!< Selects the MAC duplex mode: Half-Duplex or Full-Duplex mode
This parameter can be a value of @ref ETH_Duplex_Mode */
uint8_t *MACAddr; /*!< MAC Address of used Hardware: must be pointer on an array of 6 bytes */
uint32_t ChecksumMode; /*!< Selects if the checksum is check by hardware or by software.
This parameter can be a value of @ref ETH_Checksum_Mode */
uint8_t InterruptEnableBits; /*!< Selects the enabled interrupts */
} ENC_InitTypeDef;
/**
* @brief Received Frame Informations structure definition
*/
typedef struct
{
uint32_t length; /*!< Frame length */
uint8_t buffer[MAX_FRAMELEN+20]; /*!< Frame buffer */
} ENC_RxFrameInfos;
/**
* @brief ENC28J60 Handle Structure definition
*/
typedef struct
{
ENC_InitTypeDef Init; /*!< Ethernet Init Configuration */
uint8_t bank; /*!< Currently selected bank */
uint8_t interruptFlags;/*!< The last value of interrupts flags */
uint8_t pktCnt; /*!< The number of pending receive packets */
uint16_t nextpkt; /*!< Next packet address */
uint16_t LinkStatus; /*!< Ethernet link status */
uint16_t transmitLength;/*!< The length of ip frame to transmit */
uint32_t startTime; /*!< The start time of the current timer */
uint32_t duration; /*!< The duration of the current timer in ms */
uint16_t retries; /*!< The number of transmission retries left to do */
ENC_RxFrameInfos RxFrameInfos; /*!< last Rx frame infos */
} ENC_HandleTypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup ETH_Exported_Constants ETH Exported Constants
* @{
*/
/* Size of the Ethernet header */
#define ETH_HDRLEN 14 /* Minimum size: 2*6 + 2 */
#define ERR_OK 0 /* No error, everything OK. */
#define ERR_MEM -1 /* Out of memory error. */
#define ERR_BUF -2 /* Buffer error. */
#define ERR_TIMEOUT -3 /* Timeout. */
/* ENC28J60 Commands ********************************************************/
/* A total of seven instructions are implemented on the ENC28J60. Where:
*
* aaaaaa is the 5-bit address of a control register, and
* dddddddd is one or more bytes of data that may accompany the command.
*/
#define ENC_RCR (0x00) /* Read Control Register
* 000 | aaaaa | (Register value returned)) */
#define ENC_RBM (0x3a) /* Read Buffer Memory
* 001 | 11010 | (Read buffer data follows) */
#define ENC_WCR (0x40) /* Write Control Register
* 010 | aaaaa | dddddddd */
#define ENC_WBM (0x7a) /* Write Buffer Memory
* 011 | 11010 | (Write buffer data follows) */
#define ENC_BFS (0x80) /* Bit Field Set
* 100 | aaaaa | dddddddd */
#define ENC_BFC (0xa0) /* Bit Field Clear
* 101 | aaaaa | dddddddd */
#define ENC_SRC (0xff) /* System Reset
* 111 | 11111 | (No data) */
/* Global Control Registers *************************************************/
/* Control registers are accessed with the RCR, RBM, WCR, BFS, and BFC
* commands. The following identifies all ENC28J60 control registers. The
* control register memory is partitioned into four banks, selectable by the
* bank select bits, BSEL1:BSEL0, in the ECON1 register.
*
* The last five locations (0x1b to 0x1f) of all banks point to a common set
* of registers: EIE, EIR, ESTAT, ECON2 and ECON1. These are key registers
* used in controlling and monitoring the operation of the device. Their
* common mapping allows easy access without switching the bank.
*
* Control registers for the ENC28J60 are generically grouped as ETH, MAC and
* MII registers. Register names starting with E belong to the ETH group.
* Similarly, registers names starting with MA belong to the MAC group and
* registers prefixed with MI belong to the MII group.
*/
#define ENC_EIE (0x1b) /* Ethernet Interrupt Enable Register */
#define ENC_EIR (0x1c) /* Ethernet Interupt Request Register */
#define ENC_ESTAT (0x1d) /* Ethernet Status Register */
#define ENC_ECON2 (0x1e) /* Ethernet Control 2 Register */
#define ENC_ECON1 (0x1f) /* Ethernet Control 1 Register */
/* Ethernet Interrupt Enable Register Bit Definitions */
#define EIE_RXERIE (1 << 0) /* Bit 0: Receive Error Interrupt Enable */
#define EIE_TXERIE (1 << 1) /* Bit 1: Transmit Error Interrupt Enable */
/* Bit 2: Reserved */
#define EIE_TXIE (1 << 3) /* Bit 3: Transmit Enable */
#define EIE_LINKIE (1 << 4) /* Bit 4: Link Status Change Interrupt Enable */
#define EIE_DMAIE (1 << 5) /* Bit 5: DMA Interrupt Enable */
#define EIE_PKTIE (1 << 6) /* Bit 6: Receive Packet Pending Interrupt Enable */
#define EIE_INTIE (1 << 7) /* Bit 7: Global INT Interrupt Enable */
/* Ethernet Interrupt Request Register Bit Definitions */
#define EIR_RXERIF (1 << 0) /* Bit 0: Receive Error Interrupt */
#define EIR_TXERIF (1 << 1) /* Bit 1: Transmit Error Interrupt */
/* Bit 2: Reserved */
#define EIR_TXIF (1 << 3) /* Bit 3: Transmit Interrupt */
#define EIR_LINKIF (1 << 4) /* Bit 4: Link Change Interrupt */
#define EIR_DMAIF (1 << 5) /* Bit 5: DMA Interrupt */
#define EIR_PKTIF (1 << 6) /* Bit 6: Receive Packet Pending Interrupt */
/* Bit 7: Reserved */
#define EIR_ALLINTS (EIR_RXERIF | EIR_TXERIF | EIR_TXIF | EIR_LINKIF | EIR_DMAIF) /* All interrupts bar EIR_PKTIF*/
/* Ethernet Status Register Bit Definitions */
#define ESTAT_CLKRDY (1 << 0) /* Bit 0: Clock Ready */
#define ESTAT_TXABRT (1 << 1) /* Bit 1: Transmit Abort Error */
#define ESTAT_RXBUSY (1 << 2) /* Bit 2: Receive Busy */
/* Bit 3: Reserved */
#define ESTAT_LATECOL (1 << 4) /* Bit 4: Late Collision Error */
/* Bit 5: Reserved */
#define ESTAT_BUFER (1 << 6) /* Bit 6: Ethernet Buffer Error Status */
#define ESTAT_INT (1 << 7) /* Bit 7: INT Interrupt */
/* Ethernet Control 1 Register Bit Definitions */
#define ECON1_BSEL_SHIFT (0) /* Bits 0-1: Bank select */
#define ECON1_BSEL_MASK (3 << ECON1_BSEL_SHIFT)
# define ECON1_BSEL_BANK0 (0 << ECON1_BSEL_SHIFT) /* Bank 0 */
# define ECON1_BSEL_BANK1 (1 << ECON1_BSEL_SHIFT) /* Bank 1 */
# define ECON1_BSEL_BANK2 (2 << ECON1_BSEL_SHIFT) /* Bank 2 */
# define ECON1_BSEL_BANK3 (3 << ECON1_BSEL_SHIFT) /* Bank 3 */
#define ECON1_RXEN (1 << 2) /* Bit 2: Receive Enable */
#define ECON1_TXRTS (1 << 3) /* Bit 3: Transmit Request to Send */
#define ECON1_CSUMEN (1 << 4) /* Bit 4: DMA Checksum Enable */
#define ECON1_DMAST (1 << 5) /* Bit 5: DMA Start and Busy Status */
#define ECON1_RXRST (1 << 6) /* Bit 6: Receive Logic Reset */
#define ECON1_TXRST (1 << 7) /* Bit 7: Transmit Logic Reset */
/* Ethernet Control 2 Register */
/* Bits 0-2: Reserved */
#define ECON2_VRPS (1 << 3) /* Bit 3: Voltage Regulator Power Save Enable */
/* Bit 4: Reserved */
#define ECON2_PWRSV (1 << 5) /* Bit 5: Power Save Enable */
#define ECON2_PKTDEC (1 << 6) /* Bit 6: Packet Decrement */
#define ECON2_AUTOINC (1 << 7) /* Bit 7: Automatic Buffer Pointer Increment Enable */
/* Banked Control Registers *************************************************/
/* The remaining control registers are identified with a a 5 bit address and
* a bank selection. We pack the bank number and an indication if this is
* a MAC/PHY register access together with the control register address
* together to keep the design simpler.
*/
#define ENC_ADDR_SHIFT (0) /* Bits 0-4: Register address */
#define ENC_ADDR_MASK (0x1f << ENC_ADDR_SHIFT)
#define ENC_BANK_SHIFT (5) /* Bits 5-6: Bank number */
#define ENC_BANK_MASK (3 << ENC_BSEL_SHIFT)
# define ENC_BANK0 (0 << ENC_BSEL_SHIFT)
# define ENC_BANK1 (1 << ENC_BSEL_SHIFT)
# define ENC_BANK2 (2 << ENC_BSEL_SHIFT)
# define ENC_BANK3 (3 << ENC_BSEL_SHIFT)
#define ENC_PHYMAC_SHIFT (7) /* Bit 7: This is a PHY/MAC command */
#define ENC_PHYMAC (1 << ENC_PHYMAC_SHIFT)
#define REGADDR(a,b,m) ((m) << ENC_PHYMAC_SHIFT | (b) << ENC_BANK_SHIFT | (a))
#define GETADDR(a) ((a) & ENC_ADDR_MASK)
#define GETBANK(a) (((a) >> ENC_BANK_SHIFT) & 3)
#define ISPHYMAC(a) (((a) & ENC_PHYMAC) != 0)
/* Bank 0 Control Register Addresses */
#define ENC_ERDPTL REGADDR(0x00, 0, 0) /* Read Pointer Low Byte (ERDPT<7:0> */
#define ENC_ERDPTH REGADDR(0x01, 0, 0) /* Read Pointer High Byte (ERDPT<12:8>) */
#define ENC_EWRPTL REGADDR(0x02, 0, 0) /* Write Pointer Low Byte (EWRPT<7:0>) */
#define ENC_EWRPTH REGADDR(0x03, 0, 0) /* Write Pointer High Byte (EWRPT<12:8>) */
#define ENC_ETXSTL REGADDR(0x04, 0, 0) /* TX Start Low Byte (ETXST<7:0>) */
#define ENC_ETXSTH REGADDR(0x05, 0, 0) /* TX Start High Byte (ETXST<12:8>) */
#define ENC_ETXNDL REGADDR(0x06, 0, 0) /* TX End Low Byte (ETXND<7:0>) */
#define ENC_ETXNDH REGADDR(0x07, 0, 0) /* TX End High Byte (ETXND<12:8>) */
#define ENC_ERXSTL REGADDR(0x08, 0, 0) /* RX Start Low Byte (ERXST<7:0>) */
#define ENC_ERXSTH REGADDR(0x09, 0, 0) /* RX Start High Byte (ERXST<12:8>) */
#define ENC_ERXNDL REGADDR(0x0a, 0, 0) /* RX End Low Byte (ERXND<7:0>) */
#define ENC_ERXNDH REGADDR(0x0b, 0, 0) /* RX End High Byte (ERXND<12:8>) */
#define ENC_ERXRDPTL REGADDR(0x0c, 0, 0) /* RX RD Pointer Low Byte (ERXRDPT<7:0>) */
#define ENC_ERXRDPTH REGADDR(0x0d, 0, 0) /* RX RD Pointer High Byte (ERXRDPT<12:8>) */
#define ENC_ERXWRPTL REGADDR(0x0e, 0, 0) /* RX WR Pointer Low Byte (ERXWRPT<7:0>) */
#define ENC_ERXWRPTH REGADDR(0x0f, 0, 0) /* RX WR Pointer High Byte (ERXWRPT<12:8>) */
#define ENC_EDMASTL REGADDR(0x10, 0, 0) /* DMA Start Low Byte (EDMAST<7:0>) */
#define ENC_EDMASTH REGADDR(0x11, 0, 0) /* DMA Start High Byte (EDMAST<12:8>) */
#define ENC_EDMANDL REGADDR(0x12, 0, 0) /* DMA End Low Byte (EDMAND<7:0>) */
#define ENC_EDMANDH REGADDR(0x13, 0, 0) /* DMA End High Byte (EDMAND<12:8>) */
#define ENC_EDMADSTL REGADDR(0x14, 0, 0) /* DMA Destination Low Byte (EDMADST<7:0>) */
#define ENC_EDMADSTH REGADDR(0x15, 0, 0) /* DMA Destination High Byte (EDMADST<12:8>) */
#define ENC_EDMACSL REGADDR(0x16, 0, 0) /* DMA Checksum Low Byte (EDMACS<7:0>) */
#define ENC_EDMACSH REGADDR(0x17, 0, 0) /* DMA Checksum High Byte (EDMACS<15:8>) */
/* 0x18-0x1a: Reserved */
/* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */
/* Bank 1 Control Register Addresses */
#define ENC_EHT0 REGADDR(0x00, 1, 0) /* Hash Table Byte 0 (EHT<7:0>) */
#define ENC_EHT1 REGADDR(0x01, 1, 0) /* Hash Table Byte 1 (EHT<15:8>) */
#define ENC_EHT2 REGADDR(0x02, 1, 0) /* Hash Table Byte 2 (EHT<23:16>) */
#define ENC_EHT3 REGADDR(0x03, 1, 0) /* Hash Table Byte 3 (EHT<31:24>) */
#define ENC_EHT4 REGADDR(0x04, 1, 0) /* Hash Table Byte 4 (EHT<39:32>) */
#define ENC_EHT5 REGADDR(0x05, 1, 0) /* Hash Table Byte 5 (EHT<47:40>) */
#define ENC_EHT6 REGADDR(0x06, 1, 0) /* Hash Table Byte 6 (EHT<55:48>) */
#define ENC_EHT7 REGADDR(0x07, 1, 0) /* Hash Table Byte 7 (EHT<63:56>) */
#define ENC_EPMM0 REGADDR(0x08, 1, 0) /* Pattern Match Mask Byte 0 (EPMM<7:0>) */
#define ENC_EPMM1 REGADDR(0x09, 1, 0) /* Pattern Match Mask Byte 1 (EPMM<15:8>) */
#define ENC_EPMM2 REGADDR(0x0a, 1, 0) /* Pattern Match Mask Byte 2 (EPMM<23:16>) */
#define ENC_EPMM3 REGADDR(0x0b, 1, 0) /* Pattern Match Mask Byte 3 (EPMM<31:24>) */
#define ENC_EPMM4 REGADDR(0x0c, 1, 0) /* Pattern Match Mask Byte 4 (EPMM<39:32>) */
#define ENC_EPMM5 REGADDR(0x0d, 1, 0) /* Pattern Match Mask Byte 5 (EPMM<47:40>) */
#define ENC_EPMM6 REGADDR(0x0e, 1, 0) /* Pattern Match Mask Byte 6 (EPMM<55:48>) */
#define ENC_EPMM7 REGADDR(0x0f, 1, 0) /* Pattern Match Mask Byte 7 (EPMM<63:56>) */
#define ENC_EPMCSL REGADDR(0x10, 1, 0) /* Pattern Match Checksum Low Byte (EPMCS<7:0>) */
#define ENC_EPMCSH REGADDR(0x11, 1, 0) /* Pattern Match Checksum High Byte (EPMCS<15:0>) */
/* 0x12-0x13: Reserved */
#define ENC_EPMOL REGADDR(0x14, 1, 0) /* Pattern Match Offset Low Byte (EPMO<7:0>) */
#define ENC_EPMOH REGADDR(0x15, 1, 0) /* Pattern Match Offset High Byte (EPMO<12:8>) */
/* 0x16-0x17: Reserved */
#define ENC_ERXFCON REGADDR(0x18, 1, 0) /* Receive Filter Configuration */
#define ENC_EPKTCNT REGADDR(0x19, 1, 0) /* Ethernet Packet Count */
/* 0x1a: Reserved */
/* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */
/* Receive Filter Configuration Bit Definitions */
#define ERXFCON_BCEN (1 << 0) /* Bit 0: Broadcast Filter Enable */
#define ERXFCON_MCEN (1 << 1) /* Bit 1: Multicast Filter Enable */
#define ERXFCON_HTEN (1 << 2) /* Bit 2: Hash Table Filter Enable */
#define ERXFCON_MPEN (1 << 3) /* Bit 3: Magic Packet Filter Enable */
#define ERXFCON_PMEN (1 << 4) /* Bit 4: Pattern Match Filter Enable */
#define ERXFCON_CRCEN (1 << 5) /* Bit 5: Post-Filter CRC Check Enable */
#define ERXFCON_ANDOR (1 << 6) /* Bit 6: AND/OR Filter Select */
#define ERXFCON_UCEN (1 << 7) /* Bit 7: Unicast Filter Enable */
/* Bank 2 Control Register Addresses */
#define ENC_MACON1 REGADDR(0x00, 2, 1) /* MAC Control 1 */
/* 0x01: Reserved */
#define ENC_MACON3 REGADDR(0x02, 2, 1) /* MAC Control 3 */
#define ENC_MACON4 REGADDR(0x03, 2, 1) /* MAC Control 4 */
#define ENC_MABBIPG REGADDR(0x04, 2, 1) /* Back-to-Back Inter-Packet Gap (BBIPG<6:0>) */
/* 0x05: Reserved */
#define ENC_MAIPGL REGADDR(0x06, 2, 1) /* Non-Back-to-Back Inter-Packet Gap Low Byte (MAIPGL<6:0>) */
#define ENC_MAIPGH REGADDR(0x07, 2, 1) /* Non-Back-to-Back Inter-Packet Gap High Byte (MAIPGH<6:0>) */
#define ENC_MACLCON1 REGADDR(0x08, 2, 1) /* MAC Collision Control 1 */
#define ENC_MACLCON2 REGADDR(0x09, 2, 1) /* MAC Collision Control 2 */
#define ENC_MAMXFLL REGADDR(0x0a, 2, 1) /* Maximum Frame Length Low Byte (MAMXFL<7:0>) */
#define ENC_MAMXFLH REGADDR(0x0b, 2, 1) /* Maximum Frame Length High Byte (MAMXFL<15:8>) */
/* 0x0c-0x11: Reserved */
#define ENC_MICMD REGADDR(0x12, 2, 1) /* MII Command Register */
/* 0x13: Reserved */
#define ENC_MIREGADR REGADDR(0x14, 2, 1) /* MII Register Address */
/* 0x15: Reserved */
#define ENC_MIWRL REGADDR(0x16, 2, 1) /* MII Write Data Low Byte (MIWR<7:0>) */
#define ENC_MIWRH REGADDR(0x17, 2, 1) /* MII Write Data High Byte (MIWR<15:8>) */
#define ENC_MIRDL REGADDR(0x18, 2, 1) /* MII Read Data Low Byte (MIRD<7:0>) */
#define ENC_MIRDH REGADDR(0x19, 2, 1) /* MII Read Data High Byte(MIRD<15:8>) */
/* 0x1a: Reserved */
/* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */
/* MAC Control 1 Register Bit Definitions */
#define MACON1_MARXEN (1 << 0) /* Bit 0: MAC Receive Enable */
#define MACON1_PASSALL (1 << 1) /* Bit 1: Pass All Received Frames Enable */
#define MACON1_RXPAUS (1 << 2) /* Bit 2: Pause Control Frame Reception Enable */
#define MACON1_TXPAUS (1 << 3) /* Bit 3: Pause Control Frame Transmission Enable */
/* Bits 4-7: Unimplemented or reserved */
/* MAC Control 1 Register Bit Definitions */
#define MACON3_FULDPX (1 << 0) /* Bit 0: MAC Full-Duplex Enable */
#define MACON3_FRMLNEN (1 << 1) /* Bit 1: Frame Length Checking Enable */
#define MACON3_HFRMLEN (1 << 2) /* Bit 2: Huge Frame Enable */
#define MACON3_PHDRLEN (1 << 3) /* Bit 3: Proprietary Header Enable */
#define MACON3_TXCRCEN (1 << 4) /* Bit 4: Transmit CRC Enable */
#define MACON3_PADCFG0 (1 << 5) /* Bit 5: Automatic Pad and CRC Configuration */
#define MACON3_PADCFG1 (1 << 6) /* Bit 6: " " " " " " " " " " */
#define MACON3_PADCFG2 (1 << 7) /* Bit 7: " " " " " " " " " " */
/* MAC Control 1 Register Bit Definitions */
#define MACON4_NOBKOFF (1 << 4) /* Bit 4: No Backoff Enable */
#define MACON4_BPEN (1 << 5) /* Bit 5: No Backoff During Backpressure Enable */
#define MACON4_DEFER (1 << 6) /* Bit 6: Defer Transmission Enable bit */
/* MII Command Register Bit Definitions */
#define MICMD_MIIRD (1 << 0) /* Bit 0: MII Read Enable */
#define MICMD_MIISCAN (1 << 1) /* Bit 1: MII Scan Enable */
/* Bank 3 Control Register Addresses */
#define ENC_MAADR5 REGADDR(0x00, 3, 1) /* MAC Address Byte 5 (MAADR<15:8>) */
#define ENC_MAADR6 REGADDR(0x01, 3, 1) /* MAC Address Byte 6 (MAADR<7:0>) */
#define ENC_MAADR3 REGADDR(0x02, 3, 1) /* MAC Address Byte 3 (MAADR<31:24>), OUI Byte 3 */
#define ENC_MAADR4 REGADDR(0x03, 3, 1) /* MAC Address Byte 4 (MAADR<23:16>) */
#define ENC_MAADR1 REGADDR(0x04, 3, 1) /* MAC Address Byte 1 (MAADR<47:40>), OUI Byte 1 */
#define ENC_MAADR2 REGADDR(0x05, 3, 1) /* MAC Address Byte 2 (MAADR<39:32>), OUI Byte 2 */
#define ENC_EBSTSD REGADDR(0x06, 3, 0) /* Built-in Self-Test Fill Seed (EBSTSD<7:0>) */
#define ENC_EBSTCON REGADDR(0x07, 3, 0) /* Built-in Self-Test Control */
#define ENC_EBSTCSL REGADDR(0x08, 3, 0) /* Built-in Self-Test Checksum Low Byte (EBSTCS<7:0>) */
#define ENC_EBSTCSH REGADDR(0x09, 3, 0) /* Built-in Self-Test Checksum High Byte (EBSTCS<15:8>) */
#define ENC_MISTAT REGADDR(0x0a, 3, 1) /* MII Status Register */
/* 0x0b-0x11: Reserved */
#define ENC_EREVID REGADDR(0x12, 3, 0) /* Ethernet Revision ID */
/* 0x13-0x14: Reserved */
#define ENC_ECOCON REGADDR(0x15, 3, 0) /* Clock Output Control */
/* 0x16: Reserved */
#define ENC_EFLOCON REGADDR(0x17, 3, 0) /* Ethernet Flow Control */
#define ENC_EPAUSL REGADDR(0x18, 3, 0) /* Pause Timer Value Low Byte (EPAUS<7:0>) */
#define ENC_EPAUSH REGADDR(0x19, 3, 0) /* Pause Timer Value High Byte (EPAUS<15:8>) */
/* 0x1a: Reserved */
/* 0x1b-0x1f: EIE, EIR, ESTAT, ECON2, ECON1 */
/* Built-in Self-Test Control Register Bit Definitions */
#define EBSTCON_BISTST (1 << 0) /* Bit 0: Built-in Self-Test Start/Busy */
#define EBSTCON_TME (1 << 1) /* Bit 1: Test Mode Enable */
#define EBSTCON_TMSEL0 (1 << 2) /* Bit 2: Test Mode Select */
#define EBSTCON_TMSEL1 (1 << 3) /* Bit 3: " " " " " " */
#define EBSTCON_PSEL (1 << 4) /* Bit 4: Port Select */
#define EBSTCON_PSV0 (1 << 5) /* Bit 5: Pattern Shift Value */
#define EBSTCON_PSV1 (1 << 6) /* Bit 6: " " " " " */
#define EBSTCON_PSV2 (1 << 7) /* Bit 7: " " " " " */
/* MII Status Register Register Bit Definitions */
#define MISTAT_BUSY (1 << 0) /* Bit 0: MII Management Busy */
#define MISTAT_SCAN (1 << 1) /* Bit 1: MII Management Scan Operation */
#define MISTAT_NVALID (1 << 2) /* Bit 2: MII Management Read Data Not Valid */
/* Bits 3-7: Reserved or unimplemented */
/* Ethernet Flow Control Register Bit Definitions */
#define EFLOCON_FCEN0 (1 << 0) /* Bit 0: Flow Control Enable */
#define EFLOCON_FCEN1 (1 << 1) /* Bit 1: " " " " " " */
#define EFLOCON_FULDPXS (1 << 2) /* Bit 2: Read-Only MAC Full-Duplex Shadow */
/* Bits 3-7: Reserved or unimplemented */
/* PHY Registers ************************************************************/
#define ENC_PHCON1 (0x00) /* PHY Control Register 1 */
#define ENC_PHSTAT1 (0x01) /* PHY Status 1 */
#define ENC_PHID1 (0x02) /* PHY ID Register 1 */
#define ENC_PHID2 (0x03) /* PHY ID Register 2 */
#define ENC_PHCON2 (0x10) /* PHY Control Register 2 */
#define ENC_PHSTAT2 (0x11) /* PHY Status 2 */
#define ENC_PHIE (0x12) /* PHY Interrupt Enable Register */
#define ENC_PHIR (0x13) /* PHY Interrupt Request Register */
#define ENC_PHLCON (0x14)
/* PHY Control Register 1 Register Bit Definitions */
#define PHCON1_PDPXMD (1 << 8) /* Bit 8: PHY Duplex Mode */
#define PHCON1_PPWRSV (1 << 11) /* Bit 11: PHY Power-Down */
#define PHCON1_PLOOPBK (1 << 14) /* Bit 14: PHY Loopback */
#define PHCON1_PRST (1 << 15) /* Bit 15: PHY Software Reset */
/* PHY Status 1 Register Bit Definitions */
#define PHSTAT1_JBSTAT (1 << 1) /* Bit 1: PHY Latching Jabber Status */
#define PHSTAT1_LLSTAT (1 << 2) /* Bit 2: PHY Latching Link Status */
#define PHSTAT1_PHDPX (1 << 11) /* Bit 11: PHY Half-Duplex Capable */
#define PHSTAT1_PFDPX (1 << 12) /* Bit 12: PHY Full-Duplex Capable */
/* PHY Control Register 2 Register Bit Definitions */
#define PHCON2_HDLDIS (1 << 8) /* Bit 8: PHY Half-Duplex Loopback Disable */
#define PHCON2_JABBER (1 << 10) /* Bit 10: Jabber Correction Disable */
#define PHCON2_TXDIS (1 << 13) /* Bit 13: Twisted-Pair Transmitter Disable */
#define PHCON2_FRCLINK (1 << 14) /* Bit 14: PHY Force Linkup */
/* PHY Status 2 Register Bit Definitions */
#define PHSTAT2_PLRITY (1 << 5) /* Bit 5: Polarity Status */
#define PHSTAT2_DPXSTAT (1 << 9) /* Bit 9: PHY Duplex Status */
#define PHSTAT2_LSTAT (1 << 10) /* Bit 10: PHY Link Status */
#define PHSTAT2_COLSTAT (1 << 11) /* Bit 11: PHY Collision Status */
#define PHSTAT2_RXSTAT (1 << 12) /* Bit 12: PHY Receive Status */
#define PHSTAT2_TXSTAT (1 << 13) /* Bit 13: PHY Transmit Status */
/* PHY Interrupt Enable Register Bit Definitions */
#define PHIE_PGEIE (1 << 1) /* Bit 1: PHY Global Interrupt Enable */
#define PHIE_PLNKIE (1 << 4) /* Bit 4: PHY Link Change Interrupt Enable */
/* PHIR Regiser Bit Definitions */
#define PHIR_PGIF (1 << 2) /* Bit 2: PHY Global Interrupt */
#define PHIR_PLNKIF (1 << 4) /* Bit 4: PHY Link Change Interrupt */
/* PHLCON Regiser Bit Definitions */
/* Bit 0: Reserved */
#define PHLCON_STRCH (1 << 1) /* Bit 1: LED Pulse Stretching Enable */
#define PHLCON_LFRQ0 (1 << 2) /* Bit 2: LED Pulse Stretch Time Configuration */
#define PHLCON_LFRQ1 (1 << 3) /* Bit 3: " " " " " " " " " */
#define PHLCON_LBCFG0 (1 << 4) /* Bit 4: LEDB Configuration */
#define PHLCON_LBCFG1 (1 << 5) /* Bit 5: " " " " */
#define PHLCON_LBCFG2 (1 << 6) /* Bit 6: " " " " */
#define PHLCON_LBCFG3 (1 << 7) /* Bit 7: " " " " */
#define PHLCON_LACFG0 (1 << 8) /* Bit 8: LEDA Configuration */
#define PHLCON_LACFG1 (1 << 9) /* Bit 9: " " " " */
#define PHLCON_LACFG2 (1 << 10) /* Bit 10: " " " " */
#define PHLCON_LACFG3 (1 << 11) /* Bit 11: " " " " */
/* Packet Memory ************************************************************/
/* 8-Kbyte Transmit/Receive Packet Dual Port SRAM */
#define PKTMEM_START 0x0000
#define PKTMEM_END 0x1fff
/* maximum transfer unit */
#define CONFIG_NET_ETH_MTU 1500
/* Packet Control Bits Definitions ******************************************/
#define PKTCTRL_POVERRIDE (1 << 0) /* Bit 0: Per Packet Override */
#define PKTCTRL_PCRCEN (1 << 1) /* Bit 1: Per Packet CRC Enable */
#define PKTCTRL_PPADEN (1 << 2) /* Bit 2: Per Packet Padding Enable */
#define PKTCTRL_PHUGEEN (1 << 3) /* Bit 3: Per Packet Huge Frame Enable */
/* RX Status Bit Definitions ************************************************/
#define RXSTAT_LDEVENT (1 << 0) /* Bit 0: Long event or pack dropped */
/* Bit 1: Reserved */
#define RXSTAT_CEPS (1 << 2) /* Bit 2: Carrier event previously seen */
/* Bit 3: Reserved */
#define RXSTAT_CRCERROR (1 << 4) /* Bit 4: Frame CRC field bad */
#define RXSTAT_LENERROR (1 << 5) /* Bit 5: Packet length != data length */
#define RXSTAT_LENRANGE (1 << 6) /* Bit 6: Type/length field > 1500 bytes */
#define RXSTAT_OK (1 << 7) /* Bit 7: Packet with valid CRC and no symbol errors */
#define RXSTAT_MCAST (1 << 8) /* Bit 8: Packet with multicast address */
#define RXSTAT_BCAST (1 << 9) /* Bit 9: Packet with broadcast address */
#define RXSTAT_DRIBBLE (1 << 10) /* Bit 10: Additional bits received after packet */
#define RXSTAT_CTRLFRAME (1 << 11) /* Bit 11: Control frame with valid type/length */
#define RXSTAT_PAUSE (1 << 12) /* Bit 12: Control frame with pause frame opcde */
#define RXSTAT_UNKOPCODE (1 << 13) /* Bit 13: Control frame with unknown opcode */
#define RXSTAT_VLANTYPE (1 << 14) /* Bit 14: Current frame is a VLAN tagged frame */
/* Bit 15: Zero */
/* TSV bit definitions */
#define TSV_LATECOL (1 << 5) /* Bit 5: Late Collision Error, RSV byte 3 */
/** @defgroup ETH_Duplex_Mode ETH Duplex Mode
* @{
*/
#define ETH_MODE_FULLDUPLEX ((uint32_t)0x00000800)
#define ETH_MODE_HALFDUPLEX ((uint32_t)0x00000000)
/**
* @}
*/
/** @defgroup ETH_Rx_Mode ETH Rx Mode
* @{
*/
#define ETH_RXPOLLING_MODE ((uint32_t)0x00000000)
#define ETH_RXINTERRUPT_MODE ((uint32_t)0x00000001)
/**
* @}
*/
/** @defgroup ETH_Checksum_Mode ETH Checksum Mode
* @{
*/
#define ETH_CHECKSUM_BY_HARDWARE ((uint32_t)0x00000000)
#define ETH_CHECKSUM_BY_SOFTWARE ((uint32_t)0x00000001)
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup SPI_Exported_Functions
* @{
*/
/** @addtogroup SPI_Exported_Functions_Group1
* @{
*/
/* Initialization/de-initialization functions **********************************/
/**
* Initialize the enc28j60 and configure the needed hardware resources
* param handle: Handle on data configuration.
* retval None
*/
bool ENC_Start(ENC_HandleTypeDef *handle);
/****************************************************************************
* Function: ENC_SetMacAddr
*
* Description:
* Set the MAC address to the configured value. This is done after ifup
* or after a TX timeout. Note that this means that the interface must
* be down before configuring the MAC addr.
*
* Parameters:
* handle - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
void ENC_SetMacAddr(ENC_HandleTypeDef *handle);
/****************************************************************************
* Function: ENC_RestoreTXBuffer
*
* Description:
* Prepare TX buffer
*
* Parameters:
* handle - Reference to the driver state structure
* len - length of buffer
*
* Returned Value:
* ERR_OK 0 No error, everything OK.
* ERR_MEM -1 Out of memory error.
* ERR_TIMEOUT -3 Timeout.
*
* Assumptions:
*
****************************************************************************/
int8_t ENC_RestoreTXBuffer(ENC_HandleTypeDef *handle, uint16_t len);
/****************************************************************************
* Function: ENC_WriteBuffer
*
* Description:
* Write a buffer of data.
*
* Parameters:
* buffer - A pointer to the buffer to write from
* buflen - The number of bytes to write
*
* Returned Value:
* None
*
* Assumptions:
* Read pointer is set to the correct address
*
****************************************************************************/
void ENC_WriteBuffer(void *buffer, uint16_t buflen);
/****************************************************************************
* Function: ENC_Transmit
*
* Description:
* Start hardware transmission. Called either from:
*
* - pkif interrupt when an application responds to the receipt of data
* by trying to send something, or
* - From watchdog based polling.
*
* Parameters:
* handle - Reference to the driver state structure
*
* Returned Value:
* none
*
* Assumptions:
*
****************************************************************************/
#ifdef USE_PROTOTHREADS
PT_THREAD(ENC_Transmit(struct pt *pt, ENC_HandleTypeDef *handle));
#else
void ENC_Transmit(ENC_HandleTypeDef *handle);
#endif
/**
* @}
*/
/**
* @}
*/
/****************************************************************************
* Function: ENC_GetReceivedFrame
*
* Description:
* Check if we have received packet, and if so, retrive them.
*
* Parameters:
* handle - Reference to the driver state structure
*
* Returned Value:
* true if new packet is available; false otherwise
*
* Assumptions:
*
****************************************************************************/
bool ENC_GetReceivedFrame(ENC_HandleTypeDef *handle);
/****************************************************************************
* Function: ENC_IRQHandler
*
* Description:
* Perform interrupt handling logic outside of the interrupt handler (on
* the work queue thread).
*
* Parameters:
* handle - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
void ENC_IRQHandler(ENC_HandleTypeDef *handle);
/****************************************************************************
* Function: ENC_EnableInterrupts
*
* Description:
* Enable individual ENC28J60 interrupts
*
* Parameters:
* bits - The individual bits to enable
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
void ENC_EnableInterrupts(uint8_t bits);
/****************************************************************************
* Function: ENC_GetPkcnt
*
* Description:
* Get the number of pending receive packets
*
* Parameters:
* handle - Reference to the driver state structure
*
* Returned Value:
* the number of receive packet not processed yet
*
* Assumptions:
*
****************************************************************************/
void ENC_GetPkcnt(ENC_HandleTypeDef *handle);
/****************************************************************************
* Function: up_udelay
*
* Description:
* wait us µs
*
* Parameters:
* us - The amount of time to wait in µs
*
* Returned Value:
* none
*
* Assumptions:
*
****************************************************************************/
void up_udelay(uint32_t us);
#endif /* ENC28J60_H_INCLUDED */

21
part15-tcpip/net/encspi.c Normal file
View file

@ -0,0 +1,21 @@
#include "../include/spi.h"
void ENC_SPI_Select(unsigned char truefalse) {
spi_chip_select(!truefalse); // If it's true, select 0 (the ENC), if false, select 1 (i.e. deselect the ENC)
}
void ENC_SPI_SendBuf(unsigned char *master2slave, unsigned char *slave2master, unsigned short bufferSize) {
spi_chip_select(0);
spi_send_recv(master2slave, slave2master, bufferSize);
spi_chip_select(1); // De-select the ENC
}
void ENC_SPI_Send(unsigned char command) {
spi_chip_select(0);
spi_send(&command, 1);
spi_chip_select(1); // De-select the ENC
}
void ENC_SPI_SendWithoutSelection(unsigned char command) {
spi_send(&command, 1);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,212 @@
/*********************************************
* vim:sw=8:ts=8:si:et
* To use the above modeline in vim you must have "set modeline" in your .vimrc
* Author: Guido Socher
* Copyright:LGPL V2
* See http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
*
* IP/ARP/UDP/TCP functions
*
* Chip type : ATMEGA88/168/328/644 with ENC28J60
*********************************************/
//@{
#ifndef IP_ARP_UDP_TCP_H
#define IP_ARP_UDP_TCP_H 1
#include "net.h"
#include "../net/enc28j60.h"
#include "../kernel/kernel.h"
#include "../include/fb.h"
#include "ip_config.h"
// set my own mac address:
extern void init_mac(uint8_t *mymac); // not needed if you call init_udp_or_www_server
// -- web server functions --
#if defined (WWW_server) || defined (UDP_server)
// you must call this function once before you use any of the other server functions:
// mymac may be set to NULL in this function if init_mac was used before
// init_ip_arp_udp_tcp is now replaced by init_udp_or_www_server and the www_server_port function.
extern void init_udp_or_www_server(uint8_t *mymac,uint8_t *myip);
#endif
#if defined (WWW_server)
extern void www_server_port(uint16_t port); // not needed if you want port 80
// send data from the web server to the client:
extern void www_server_reply(uint8_t *buf,uint16_t dlen);
#endif
// for a UDP server:
#if defined (UDP_server)
extern uint8_t eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len);
extern void make_udp_reply_from_request_udpdat_ready(uint8_t *buf,uint16_t datalen,uint16_t port);
extern void make_udp_reply_from_request(uint8_t *buf,char *data,uint8_t datalen,uint16_t port);
#endif
// return 0 to just continue in the packet loop and return the position
// of the tcp data if there is tcp data part:
extern uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen);
// functions to fill the web pages with data:
extern uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const uint8_t *progmem_s);
extern uint16_t fill_tcp_data_string(uint8_t *buf,uint16_t pos, char *reply);
extern uint16_t fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s);
// fill a binary string of len data into the tcp packet:
extern uint16_t fill_tcp_data_len(uint8_t *buf,uint16_t pos, const uint8_t *s, uint8_t len);
// -- client only functions --
#if defined (WWW_client) || defined (NTP_client) || defined (UDP_client) || defined (TCP_client) || defined (PING_client)
extern void client_ifconfig(uint8_t *ip,uint8_t *netmask);
// route_via_gw can be used decide if a packed needs to be routed via GW or can be found on the LAN:
extern uint8_t route_via_gw(uint8_t *destip); // returns 1 if destip must be routed via the GW. Returns 0 if destip is on the local LAN
//
// The get_mac_with_arp function can be used to find the MAC address of
// a host that is directly connected to the same LAN. It translates the IP address into
// a MAC address.
// You need to provide a callback function. That function will be executed once the
// MAC address is found. We do this to not block execution in the main loop.
// NOTE: you can only do one MAC address resolution at a time. The reference_number is just
// a number given back to you to make it easier to know what this relates to.
//
// You declare the callback function:
//
//#define TRANS_NUM_GWMAC 12
//void arpresolver_result_callback(uint8_t *ip __attribute__((unused)),uint8_t reference_number,uint8_t *mac){ // the __attribute__((unused)) is a gcc compiler directive to avoid warnings about unsed variables.
// uint8_t i=0;
// if (reference_number==TRANS_NUM_GWMAC){
// // copy mac address over:
// while(i<6){gwmac[i]=mac[i];i++;}
// }
//}
//
// and then you can just call get_mac_with_arp like this:
// get_mac_with_arp(gwip,TRANS_NUM_GWMAC,&arpresolver_result_callback);
// Note: you must have initialized the stack with init_udp_or_www_server or client_ifconfig
// before you can use get_mac_with_arp(). The arp request will automatically be repeated if
// there is no answer.
extern void get_mac_with_arp(uint8_t *ip, uint8_t reference_number,void (*arp_result_callback)(uint8_t *ip,uint8_t reference_number,uint8_t *mac));
uint8_t get_mac_with_arp_wait(void); // checks current ongoing transaction, retuns 0 when the transaction is over
#endif
#ifdef TCP_client
// To use the tcp client you need to:
//
// Declare a callback function to get the result (tcp data from the server):
//
// uint8_t your_client_tcp_result_callback(uint8_t fd, uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data){
// ...your code;
// return(close_tcp_session);
// }
//
// statuscode=0 means the buffer has valid data, otherwise len and pos_in_buf
// are invalid. That is: do to use data_start_pos_in_buf and len_of_data
// if statuscode!=0.
//
// This callback gives you access to the TCP data of the first
// packet returned from the server. You should aim to minimize the server
// output such that this will be the only packet.
//
// close_tcp_session=1 means close the session now. close_tcp_session=0
// read all data and leave it to the other side to close it.
// If you connect to a web server then you want close_tcp_session=0.
// If you connect to a modbus/tcp equipment then you want close_tcp_session=1
//
// Declare a callback function to be called in order to fill in the
//
// request (tcp data sent to the server):
// uint16_t your_client_tcp_datafill_callback(uint8_t fd){...your code;return(len_of_data_filled_in);}
//
// Now call:
// fd=client_tcp_req(&your_client_tcp_result_callback,&your_client_tcp_datafill_callback,portnumber);
//
// fd is a file descriptor like number that you get back in the fill and result
// function so you know to which call of client_tcp_req this callback belongs.
//
// You can not start different clients (e.g modbus and web) at the
// same time but you can start them one after each other. That is
// when the request has timed out or when the result_callback was
// executed then you can start a new one. The fd makes it still possible to
// distinguish in the callback code the different types you started.
//
// Note that you might never get called back if the other side does
// not answer. A timer would be needed to recongnize such a condition.
//
// We use callback functions because that is the best implementation
// given the fact that we have very little RAM memory.
//
extern uint8_t client_tcp_req(uint8_t (*result_callback)(uint8_t fd,uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data),uint16_t (*datafill_callback)(uint8_t fd),uint16_t port,uint8_t *dstip,uint8_t *dstmac);
#endif
#ifdef WWW_client
// ----- http get
// The string buffers to which urlbuf_varpart and hoststr are pointing
// must not be changed until the callback is executed.
extern void client_browse_url(const prog_char *urlbuf, char *urlbuf_varpart, const char *hoststr,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac);
// The callback is a reference to a function which must look like this:
// void browserresult_callback(uint16_t webstatuscode,uint16_t datapos,uint16_t len)
// webstatuscode is zero if there was no proper reply from the server (garbage message total communication failure, this is rare).
// webstatuscode is otherwise the http status code (e.g webstatuscode=200 for 200 OK);
// For possible status codes look at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
// Basically 2xx is success and any 5xx, 4xx is a failure.
// ----- http post
// client web browser using http POST operation:
// additionalheaderline must be set to NULL if not used.
// The string buffers to which urlbuf_varpart and hoststr are pointing
// must not be changed until the callback is executed.
// postval is a string buffer which can only be de-allocated by the caller
// when the post operation was really done (e.g when callback was executed).
// postval must be urlencoded.
extern void client_http_post(const prog_char *urlbuf, char *urlbuf_varpart,const char *hoststr, const prog_char *additionalheaderline,char *postval,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac);
// The callback is a reference to a function which must look like this:
// void browserresult_callback(uint16_t webstatuscode,uint16_t datapos,uint16_t len)
// webstatuscode is zero if there was no proper reply from the server (garbage message total communication failure, this is rare).
// webstatuscode is otherwise the http status code (e.g webstatuscode=200 for 200 OK);
#endif
#ifdef NTP_client
// be careful to not mix client_ntp_request with situations where you are filling
// a web-page. Normally you will be using the same packet buffer and
// client_ntp_request writes immediately to buf. You might need to
// set a marker and call client_ntp_request when your main loop is idle.
extern void client_ntp_request(uint8_t *buf,uint8_t *ntpip,uint8_t srcport,uint8_t *dstmac);
extern uint8_t client_ntp_process_answer(uint8_t *buf,uint32_t *time,uint8_t dstport_l);
#endif
#ifdef UDP_client
// There are two ways of using this UDP client:
//
// 1) you call send_udp_prepare, you fill the data yourself into buf starting at buf[UDP_DATA_P],
// you send the packet by calling send_udp_transmit
//
// 2) You just allocate a large enough buffer for you data and you call send_udp and nothing else
// needs to be done.
//
extern void send_udp_prepare(uint8_t *buf,uint16_t sport, const uint8_t *dip, uint16_t dport,const uint8_t *dstmac);
extern void send_udp_transmit(uint8_t *buf,uint16_t datalen);
// send_udp sends via gwip, you must call client_set_gwip at startup, datalen must be less than 220 bytes
extern void send_udp(uint8_t *buf,char *data,uint8_t datalen,uint16_t sport, const uint8_t *dip, uint16_t dport,const uint8_t *dstmac);
#endif
// you can find out who ping-ed you if you want:
extern void register_ping_rec_callback(void (*callback)(uint8_t *srcip));
#ifdef PING_client
extern void client_icmp_request(uint8_t *buf,uint8_t *destip,uint8_t *dstmac);
// you must loop over this function to check if there was a ping reply:
extern uint8_t packetloop_icmp_checkreply(uint8_t *buf,uint8_t *ip_monitoredhost);
#endif // PING_client
#ifdef WOL_client
extern void send_wol(uint8_t *buf,uint8_t *wolmac);
#endif // WOL_client
#if defined GRATARP
// send a Gratuitous arp, this is to refresh the arp
// cash of routers and switches. It can improve the response
// time in wifi networks as some wifi equipment expects the initial
// communication to not start from the network side. That is wrong
// but some consumer devices are made like this.
extern uint8_t gratutious_arp(uint8_t *buf);
#endif // GRATARP
#endif /* IP_ARP_UDP_TCP_H */
//@}

View file

@ -0,0 +1,53 @@
/*********************************************
* vim:sw=8:ts=8:si:et
* To use the above modeline in vim you must have "set modeline" in your .vimrc
* Author: Guido Socher
* Copyright:LGPL V2
* See http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
*
* This file can be used to decide which functionallity of the
* TCP/IP stack shall be available. By picking the right functions
* you can significantly reduce the size of the resulting code.
*
*********************************************/
//@{
#ifndef IP_CONFIG_H
#define IP_CONFIG_H
//------------- functions in ip_arp_udp_tcp.c --------------
// an NTP client (ntp clock):
#undef NTP_client
// a spontanious sending UDP client (needed as well for DNS and DHCP)
#undef UDP_client
// a server answering to UDP messages
#define UDP_server
// a web server
#undef WWW_server
// to send out a ping:
#undef PING_client
#define PINGPATTERN 0x42
// a UDP wake on lan sender:
#undef WOL_client
// function to send a gratuitous arp
#undef GRATARP
// a "web browser". This can be use to upload data
// to a web server on the internet by encoding the data
// into the url (like a Form action of type GET):
#undef WWW_client
// if you do not need a browser and just a server:
//#undef WWW_client
//
//------------- functions in websrv_help_functions.c --------------
//
// functions to decode cgi-form data:
#undef FROMDECODE_websrv_help
// function to encode a URL (mostly needed for a web client)
#undef URLENCODE_websrv_help
#endif /* IP_CONFIG_H */
//@}

132
part15-tcpip/tcpip/net.h Normal file
View file

@ -0,0 +1,132 @@
/*********************************************
* vim:sw=8:ts=8:si:et
* To use the above modeline in vim you must have "set modeline" in your .vimrc
* Author: Guido Socher
* Copyright:LGPL V2
* See http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
*
* Based on the net.h file from the AVRlib library by Pascal Stang.
* For AVRlib See http://www.procyonengineering.com/
* Used with explicit permission of Pascal Stang.
*
*********************************************/
// notation: _P = position of a field
// _V = value of a field
//@{
#ifndef NET_H
#define NET_H
// ******* ETH *******
#define ETH_HEADER_LEN 14
// values of certain bytes:
#define ETHTYPE_ARP_H_V 0x08
#define ETHTYPE_ARP_L_V 0x06
#define ETHTYPE_IP_H_V 0x08
#define ETHTYPE_IP_L_V 0x00
// byte positions in the ethernet frame:
//
// Ethernet type field (2bytes):
#define ETH_TYPE_H_P 12
#define ETH_TYPE_L_P 13
//
#define ETH_DST_MAC 0
#define ETH_SRC_MAC 6
// ******* ARP *******
#define ETH_ARP_OPCODE_REPLY_H_V 0x0
#define ETH_ARP_OPCODE_REPLY_L_V 0x02
#define ETH_ARP_OPCODE_REQ_H_V 0x0
#define ETH_ARP_OPCODE_REQ_L_V 0x01
// start of arp header:
#define ETH_ARP_P 0xe
//
#define ETHTYPE_ARP_L_V 0x06
// arp.dst.ip
#define ETH_ARP_DST_IP_P 0x26
// arp.opcode
#define ETH_ARP_OPCODE_H_P 0x14
#define ETH_ARP_OPCODE_L_P 0x15
// arp.src.mac
#define ETH_ARP_SRC_MAC_P 0x16
#define ETH_ARP_SRC_IP_P 0x1c
#define ETH_ARP_DST_MAC_P 0x20
#define ETH_ARP_DST_IP_P 0x26
// ******* IP *******
#define IP_HEADER_LEN 20
// ip.src
#define IP_SRC_P 0x1a
#define IP_DST_P 0x1e
#define IP_HEADER_LEN_VER_P 0xe
#define IP_CHECKSUM_P 0x18
#define IP_TTL_P 0x16
#define IP_FLAGS_P 0x14
#define IP_P 0xe
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11
#define IP_ID_H_P 0x12
#define IP_ID_L_P 0x13
#define IP_PROTO_P 0x17
#define IP_PROTO_ICMP_V 1
#define IP_PROTO_TCP_V 6
// 17=0x11
#define IP_PROTO_UDP_V 17
// ******* ICMP *******
#define ICMP_TYPE_ECHOREPLY_V 0
#define ICMP_TYPE_ECHOREQUEST_V 8
//
#define ICMP_TYPE_P 0x22
#define ICMP_CHECKSUM_P 0x24
#define ICMP_CHECKSUM_H_P 0x24
#define ICMP_CHECKSUM_L_P 0x25
#define ICMP_IDENT_H_P 0x26
#define ICMP_IDENT_L_P 0x27
#define ICMP_DATA_P 0x2a
// ******* UDP *******
#define UDP_HEADER_LEN 8
//
#define UDP_SRC_PORT_H_P 0x22
#define UDP_SRC_PORT_L_P 0x23
#define UDP_DST_PORT_H_P 0x24
#define UDP_DST_PORT_L_P 0x25
//
#define UDP_LEN_H_P 0x26
#define UDP_LEN_L_P 0x27
#define UDP_CHECKSUM_H_P 0x28
#define UDP_CHECKSUM_L_P 0x29
#define UDP_DATA_P 0x2a
// ******* TCP *******
#define TCP_SRC_PORT_H_P 0x22
#define TCP_SRC_PORT_L_P 0x23
#define TCP_DST_PORT_H_P 0x24
#define TCP_DST_PORT_L_P 0x25
// the tcp seq number is 4 bytes 0x26-0x29
#define TCP_SEQ_H_P 0x26
#define TCP_SEQACK_H_P 0x2a
// flags: SYN=2
#define TCP_FLAGS_P 0x2f
#define TCP_FLAGS_SYN_V 2
#define TCP_FLAGS_FIN_V 1
#define TCP_FLAGS_RST_V 4
#define TCP_FLAGS_PUSH_V 8
#define TCP_FLAGS_SYNACK_V 0x12
#define TCP_FLAGS_ACK_V 0x10
#define TCP_FLAGS_PSHACK_V 0x18
// plain len without the options:
#define TCP_HEADER_LEN_PLAIN 20
#define TCP_HEADER_LEN_P 0x2e
#define TCP_WIN_SIZE 0x30
#define TCP_CHECKSUM_H_P 0x32
#define TCP_CHECKSUM_L_P 0x33
#define TCP_OPTIONS_P 0x36
//
#endif
//@}