umtrx: moved new umtrx directory up one

This commit is contained in:
Josh Blum
2014-04-07 17:34:55 -07:00
parent 5969efe608
commit 505b677c7a
775 changed files with 0 additions and 0 deletions

1
zpu/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

4
zpu/AUTHORS Normal file
View File

@@ -0,0 +1,4 @@
Eric Blossom <eb@comsec.com>
Matt Ettus <matt@ettus.com>
Josh Blum <josh@ettus.com>
Nick Foster <nick@ettus.com>

126
zpu/CMakeLists.txt Normal file
View File

@@ -0,0 +1,126 @@
#
# Copyright 2010-2011 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
########################################################################
# setup project and compiler
########################################################################
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
#force the compiler because the check wont use the special flag below
INCLUDE(CMakeForceCompiler)
SET(CMAKE_SYSTEM_NAME Generic)
CMAKE_FORCE_C_COMPILER(zpu-elf-gcc GNU)
PROJECT(USRP_NXXX_FW C)
########################################################################
# lwIP header include dirs
########################################################################
SET(LWIPDIR ${CMAKE_SOURCE_DIR}/lwip/lwip-1.3.1)
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/lwip
${CMAKE_SOURCE_DIR}/lwip_port
${LWIPDIR}/src/include
${LWIPDIR}/src/include/ipv4
)
########################################################################
# misc flags for the gcc compiler
########################################################################
SET(CMAKE_C_FLAGS -phi) #always needed compile time and link time
ADD_DEFINITIONS(-Os)
ADD_DEFINITIONS(--std=gnu99)
ADD_DEFINITIONS(-Wall)
ADD_DEFINITIONS(-Werror-implicit-function-declaration)
ADD_DEFINITIONS(-ffunction-sections)
ADD_DEFINITIONS(-DSPARTAN6)
# ADD_DEFINITIONS(-DNO_FLASH)
# ADD_DEFINITIONS(-DNO_EEPROM)
# ADD_DEFINITIONS(-DNO_SPI_I2C)
ADD_DEFINITIONS(-DUMTRX)
MACRO(ADD_LINKER_FLAGS flags)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flags}")
ENDMACRO(ADD_LINKER_FLAGS)
ADD_LINKER_FLAGS("-Wl,--gc-sections")
ADD_LINKER_FLAGS("-Wl,--relax")
########################################################################
# define for the hal io (FIXME move?)
########################################################################
#ADD_DEFINITIONS(-DHAL_IO_USES_DBOARD_PINS)
ADD_DEFINITIONS(-DHAL_IO_USES_UART)
########################################################################
# common cflags and ldflags
########################################################################
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/../../host/lib/usrp
${CMAKE_SOURCE_DIR}/lib
)
########################################################################
# setup programs for output files
########################################################################
FIND_PROGRAM(LINKER zpu-elf-ld)
FIND_PROGRAM(OBJCOPY zpu-elf-objcopy)
FIND_PROGRAM(OBJDUMP zpu-elf-objdump)
FIND_PROGRAM(HEXDUMP hexdump)
########################################################################
# helper functions to build output formats
########################################################################
SET(GEN_OUTPUTS_BIN_SIZE "bin_size_not_set") #set before calling
MACRO(GEN_OUTPUTS target)
GET_FILENAME_COMPONENT(name ${target} NAME_WE)
#command to create a map from elf
ADD_CUSTOM_COMMAND(
OUTPUT ${name}.map DEPENDS ${target}
COMMAND ${LINKER} -Map ${name}.map ${target}
)
#command to create a bin from elf
ADD_CUSTOM_COMMAND(
OUTPUT ${name}.bin DEPENDS ${target}
COMMAND ${OBJCOPY} -O binary ${target} ${name}.bin
--pad-to ${GEN_OUTPUTS_BIN_SIZE}
)
#command to create a ihx from elf
ADD_CUSTOM_COMMAND(
OUTPUT ${name}.ihx DEPENDS ${target}
COMMAND ${OBJCOPY} -O ihex ${target} ${name}.ihx
--pad-to ${GEN_OUTPUTS_BIN_SIZE}
)
#command to create a dump from elf
ADD_CUSTOM_COMMAND(
OUTPUT ${name}.dump DEPENDS ${target}
COMMAND ${OBJDUMP} -DSC ${target} > ${name}.dump
)
#command to create a rom from bin
ADD_CUSTOM_COMMAND(
OUTPUT ${name}.rom DEPENDS ${name}.bin
COMMAND ${HEXDUMP} -v -e'1/1 \"%.2X\\n\"' ${name}.bin > ${name}.rom
)
#add a top level target for output files
ADD_CUSTOM_TARGET(
${name}_outputs ALL DEPENDS ${name}.map ${name}.bin ${name}.ihx ${name}.dump ${name}.rom
)
ENDMACRO(GEN_OUTPUTS)
########################################################################
# Add the subdirectories
########################################################################
ADD_SUBDIRECTORY(umtrx)

16
zpu/README Normal file
View File

@@ -0,0 +1,16 @@
########################################################################
# ZPU firmware code for USRP2 and N Series
########################################################################
This code requires the gcc-zpu tool-chain which can be found here:
http://opensource.zylin.com/zpudownload.html
zpu-elf-gcc should be in your $PATH
########################################################################
# Run the following commands to build
########################################################################
mkdir build
cd build
cmake ../
make

409
zpu/apps/txrx_uhd.c Normal file
View File

@@ -0,0 +1,409 @@
/*
* Copyright 2010-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//peripheral headers
#include "u2_init.h"
#include "umtrx_init.h"
#include "spi.h"
#include "i2c.h"
#include "hal_io.h"
#include "pic.h"
#ifdef UMTRX
# include "gpsdo.h"
#endif
//printf headers
#include "nonstdio.h"
//network headers
#include "arp_cache.h"
#include "ethernet.h"
#include "net_common.h"
#include "usrp2/fw_common.h"
#include "udp_fw_update.h"
#include "pkt_ctrl.h"
#include "udp_uart.h"
//standard headers
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifdef BOOTLOADER
#include <bootloader_utils.h>
#endif
//virtual registers in the firmware to store persistent values
static uint32_t fw_regs[8];
static void handle_udp_data_packet(
struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len
){
//handle ICMP destination unreachable
if (payload == NULL) switch(src.port){
case USRP2_UDP_RX_DSP0_PORT:
//the end continuous streaming command
sr_rx_ctrl0->cmd = 1 << 31 | 1 << 28; //no samples now
sr_rx_ctrl0->time_secs = 0;
sr_rx_ctrl0->time_ticks = 0; //latch the command
break;
case USRP2_UDP_RX_DSP1_PORT:
//the end continuous streaming command
sr_rx_ctrl1->cmd = 1 << 31 | 1 << 28; //no samples now
sr_rx_ctrl1->time_secs = 0;
sr_rx_ctrl1->time_ticks = 0; //latch the command
break;
case USRP2_UDP_TX_DSP0_PORT:
//end async update packets per second
sr_tx_ctrl0->cyc_per_up = 0;
break;
case USRP2_UDP_TX_DSP1_PORT:
//end async update packets per second
sr_tx_ctrl1->cyc_per_up = 0;
break;
default: return;
}
//handle an incoming UDP packet
size_t which = 0;
if (payload != 0) switch(dst.port){
case USRP2_UDP_RX_DSP0_PORT:
which = 0;
break;
case USRP2_UDP_RX_DSP1_PORT:
which = 2;
break;
case USRP2_UDP_TX_DSP0_PORT:
which = 1;
break;
case USRP2_UDP_TX_DSP1_PORT:
which = 3;
break;
default: return;
}
eth_mac_addr_t eth_mac_host; arp_cache_lookup_mac(&src.addr, &eth_mac_host);
setup_framer(eth_mac_host, *ethernet_mac_addr(), src, dst, which);
}
#define OTW_GPIO_BANK_TO_NUM(bank) \
(((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK))
static void handle_udp_ctrl_packet(
struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len
){
//printf("Got ctrl packet #words: %d\n", (int)payload_len);
const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload;
uint32_t ctrl_data_in_id = ctrl_data_in->id;
//ensure that the protocol versions match
if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){
if (ctrl_data_in->proto_ver) printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n",
USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver
);
#ifdef UMTRX
ctrl_data_in_id = UMTRX_CTRL_ID_REQUEST;
#else
ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO;
#endif
}
//ensure that this is not a short packet
if (payload_len < sizeof(usrp2_ctrl_data_t)){
printf("!Error in control packet handler: Expected payload length %d, but got %d\n",
(int)sizeof(usrp2_ctrl_data_t), payload_len
);
ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT;
}
//setup the output data
usrp2_ctrl_data_t ctrl_data_out;
ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM;
ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT;
ctrl_data_out.seq=ctrl_data_in->seq;
//handle the data based on the id
switch(ctrl_data_in_id){
/*******************************************************************
* Addressing
******************************************************************/
#ifdef UMTRX
case UMTRX_CTRL_ID_REQUEST:
ctrl_data_out.id = UMTRX_CTRL_ID_RESPONSE;
memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr));
break;
#else
case USRP2_CTRL_ID_WAZZUP_BRO:
ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE;
memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr));
break;
#endif
/*******************************************************************
* ZPU actions
******************************************************************/
#ifdef UMTRX
case UMTRX_CTRL_ID_ZPU_REQUEST:{
ctrl_data_out.id = UMTRX_CTRL_ID_ZPU_RESPONSE;
ctrl_data_out.data.zpu_action.action = ctrl_data_in->data.zpu_action.action;
switch (ctrl_data_in->data.zpu_action.action) {
case UMTRX_ZPU_REQUEST_GET_VCTCXO_DAC:
ctrl_data_out.data.zpu_action.data = (uint32_t)get_vctcxo_dac();
break;
case UMTRX_ZPU_REQUEST_SET_VCTCXO_DAC:
set_vctcxo_dac((uint16_t)ctrl_data_in->data.zpu_action.data);
break;
}
}
break;
#endif
#ifndef NO_SPI_I2C
/*******************************************************************
* SPI
******************************************************************/
case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{
//transact
uint32_t result = spi_transact(
(ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX,
ctrl_data_in->data.spi_args.dev, //which device
ctrl_data_in->data.spi_args.data, //32 bit data
ctrl_data_in->data.spi_args.num_bits, //length in bits
(ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE |
(ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL
);
//load output
ctrl_data_out.data.spi_args.data = result;
ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE;
}
break;
/*******************************************************************
* I2C
******************************************************************/
case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{
uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes;
i2c_read(
ctrl_data_in->data.i2c_args.addr,
ctrl_data_out.data.i2c_args.data,
num_bytes
);
ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE;
ctrl_data_out.data.i2c_args.bytes = num_bytes;
}
break;
case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{
uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes;
i2c_write(
ctrl_data_in->data.i2c_args.addr,
ctrl_data_in->data.i2c_args.data,
num_bytes
);
ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE;
ctrl_data_out.data.i2c_args.bytes = num_bytes;
}
break;
#endif
/*******************************************************************
* Peek and Poke Register
******************************************************************/
case USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO:
switch(ctrl_data_in->data.reg_args.action){
case USRP2_REG_ACTION_FPGA_PEEK32:
ctrl_data_out.data.reg_args.data = *((uint32_t *) ctrl_data_in->data.reg_args.addr);
break;
case USRP2_REG_ACTION_FPGA_PEEK16:
ctrl_data_out.data.reg_args.data = *((uint16_t *) ctrl_data_in->data.reg_args.addr);
break;
case USRP2_REG_ACTION_FPGA_POKE32:
*((uint32_t *) ctrl_data_in->data.reg_args.addr) = (uint32_t)ctrl_data_in->data.reg_args.data;
break;
case USRP2_REG_ACTION_FPGA_POKE16:
*((uint16_t *) ctrl_data_in->data.reg_args.addr) = (uint16_t)ctrl_data_in->data.reg_args.data;
break;
case USRP2_REG_ACTION_FW_PEEK32:
ctrl_data_out.data.reg_args.data = fw_regs[(ctrl_data_in->data.reg_args.addr)];
break;
case USRP2_REG_ACTION_FW_POKE32:
fw_regs[(ctrl_data_in->data.reg_args.addr)] = ctrl_data_in->data.reg_args.data;
break;
}
ctrl_data_out.id = USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE;
break;
/*******************************************************************
* Echo test
******************************************************************/
case USRP2_CTRL_ID_HOLLER_AT_ME_BRO:
ctrl_data_out.data.echo_args.len = payload_len;
ctrl_data_out.id = USRP2_CTRL_ID_HOLLER_BACK_DUDE;
send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, ctrl_data_in->data.echo_args.len);
return;
default:
ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT;
}
send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out));
}
#include <net/padded_eth_hdr.h>
static void handle_inp_packet(uint32_t *buff, size_t num_lines){
//test if its an ip recovery packet
typedef struct{
padded_eth_hdr_t eth_hdr;
char code[4];
union {
struct ip_addr ip_addr;
} data;
}recovery_packet_t;
recovery_packet_t *recovery_packet = (recovery_packet_t *)buff;
if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){
printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline();
set_ip_addr(&recovery_packet->data.ip_addr);
return;
}
//pass it to the slow-path handler
handle_eth_packet(buff, num_lines);
}
//------------------------------------------------------------------
/*
* Called when eth phy state changes (w/ interrupts disabled)
*/
void link_changed_callback(int speed){
printf("\neth link changed: speed = %d\n", speed);
if (speed != 0){
char led = speed==1000?LED_RJ45_ORANGE:LED_RJ45_GREEN;
hal_set_leds(led, led);
pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_MASTER);
send_gratuitous_arp();
}
else{
hal_set_leds(0x0, LED_RJ45_ORANGE);
hal_set_leds(0x0, LED_RJ45_GREEN);
pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
}
}
int
main(void)
{
u2_init();
#ifdef BOOTLOADER
putstr("\nUSRP N210 UDP bootloader\n");
#else
putstr("\nTxRx-UHD-ZPU\n");
#endif
printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM);
printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM);
//init readback for firmware minor version number
fw_regs[U2_FW_REG_VER_MINOR] = USRP2_FW_VER_MINOR;
#ifdef BOOTLOADER
//load the production FPGA image or firmware if appropriate
do_the_bootload_thing();
//if we get here we've fallen through to safe firmware
set_default_mac_addr();
set_default_ip_addr();
#endif
#ifdef UMTRX
umtrx_init();
#endif
print_mac_addr(ethernet_mac_addr()); newline();
print_ip_addr(get_ip_addr()); newline();
//1) register the addresses into the network stack
register_addrs(ethernet_mac_addr(), get_ip_addr());
pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_TX_DSP0_PORT, USRP2_UDP_TX_DSP1_PORT);
//2) register callbacks for udp ports we service
init_udp_listeners();
register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet);
register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet);
register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet);
register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet);
register_udp_listener(USRP2_UDP_TX_DSP1_PORT, handle_udp_data_packet);
#ifdef USRP2P
#ifndef NO_FLASH
register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet);
#endif
#endif
udp_uart_init(USRP2_UDP_UART_BASE_PORT); //setup uart messaging
//3) set the routing mode to slave to set defaults
pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
//4) setup ethernet hardware to bring the link up
ethernet_register_link_changed_callback(link_changed_callback);
ethernet_init();
while(true){
size_t num_lines;
void *buff = pkt_ctrl_claim_incoming_buffer(&num_lines);
if (buff != NULL){
handle_inp_packet((uint32_t *)buff, num_lines);
pkt_ctrl_release_incoming_buffer();
}
udp_uart_poll(); //uart message handling
pic_interrupt_handler();
/*
int pending = pic_regs->pending; // poll for under or overrun
if (pending & PIC_UNDERRUN_INT){
pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt
putchar('U');
}
if (pending & PIC_OVERRUN_INT){
pic_regs->pending = PIC_OVERRUN_INT; // clear interrupt
putchar('O');
}
*/
}
}

29
zpu/bin/bin_to_mif.py Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env python
import struct
import sys
hextab = ('0000', '0001', '0010', '0011',
'0100', '0101', '0110', '0111',
'1000', '1001', '1010', '1011',
'1100', '1101', '1110', '1111')
def w_to_binary_ascii(w):
return ''.join([hextab[(w >> 4*i) & 0xf] for i in range(7,-1,-1)])
def bin_to_mif(bin_input_file, mif_output_file):
ifile = open(bin_input_file, 'rb')
ofile = open(mif_output_file, 'w')
idata = ifile.read()
fmt = ">%dI" % ((len(idata) / 4),)
words = struct.unpack(fmt, idata)
for w in words:
ofile.write(w_to_binary_ascii(w))
ofile.write('\n')
if __name__ == '__main__':
if len(sys.argv) != 3:
sys.stderr.write("usage: bin_to_mif bin_input_file mif_output_file\n")
raise SystemExit, 1
bin_to_mif(sys.argv[1], sys.argv[2])

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
import struct
import sys
BOOTRAM_SIZE = 16384
def do_8_words(ofile, which_ram, row, words):
ofile.write("defparam bootram.RAM%d.INIT_%02X=256'h" % (which_ram, row))
ofile.write("%08x_%08x_%08x_%08x_%08x_%08x_%08x_%08x;\n" % (
words[7], words[6], words[5], words[4], words[3], words[2], words[1], words[0]))
def bin_to_ram_macro_init(bin_input_file, ram_init_output_file):
ifile = open(bin_input_file, 'rb')
ofile = open(ram_init_output_file, 'w')
idata = ifile.read()
idata_words = len(idata) / 4
fmt = ">%dI"%idata_words
words = struct.unpack(fmt, idata[:idata_words*4])
# pad to a multiple of 8 words
r = len(words) % 8
if r != 0:
words += (8 - r) * (0,)
if len(words) > (BOOTRAM_SIZE / 4):
sys.stderr.write("bin_to_macro_init: error: input file %s is > %dKiB\n" % (bin_input_file,BOOTRAM_SIZE))
sys.exit(1)
for q in range(0, BOOTRAM_SIZE/4, 512):
for i in range(q, min(q+512, len(words)), 8):
do_8_words(ofile, int(q / 512), (i/8) % 64, words[i:i+8])
if __name__ == '__main__':
if len(sys.argv) != 3:
sys.stderr.write("usage: bin_to_ram_macro_init bin_input_file ram_init_output_file\n")
sys.exit(1)
bin_to_ram_macro_init(sys.argv[1], sys.argv[2])

34
zpu/bin/divisors.py Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python
speeds = (9600, 19200, 38400, 57600, 115200, 230400)
master_clk = 100e6
wb_clk = master_clk / 2
def divisor(speed):
div0 = wb_clk // (speed * 16)
div1 = div0 + 1
actual0 = actual_speed(div0)
actual1 = actual_speed(div1)
if abs(actual0 - speed) < abs(actual1 - speed):
return div0
else:
return div1
def actual_speed(divisor):
return (wb_clk // divisor) / 16
def doit(speed):
div = divisor(speed)
actual = actual_speed(div)
rel_error = (actual - speed) / speed
print "target: %6d divisor: %6d actual: %11.4f %6.3f%%" % (speed, div, actual, rel_error*100)
def main():
print "wb_clk = %f" % (wb_clk,)
for s in speeds:
doit(s)
if __name__ == '__main__':
main()

142
zpu/bin/elf_to_sbf Executable file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/env python
#
# Copyright 2009 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import sys
import struct
from optparse import OptionParser
from pprint import pprint
import sbf
# see /usr/include/elf.h for the various magic values
_ehdr_fmt = ">16sHH5I6H"
_ehdr_fmt_size = struct.calcsize(_ehdr_fmt)
_phdr_fmt = ">8I"
_phdr_fmt_size = struct.calcsize(_phdr_fmt)
class elf32_ehdr(object):
def __init__(self, s):
(self.ident, self.type, self.machine, self.version, self.entry,
self.phoff, self.shoff, self.flags, self.ehsize,
self.phentsize, self.phnum, self.shentsize, self.shnum,
self.shstrndx) = struct.unpack(_ehdr_fmt, s)
class elf32_phdr(object):
def __init__(self, s):
(self.type, self.offset, self.vaddr, self.paddr,
self.filesz, self.memsz,
self.flags, self.align) = struct.unpack(_phdr_fmt, s)
def __repr__(self):
return "<elf32_phdr %s offset=%d paddr=0x%x, filesz=%d>" % (
p_type_str(self.type), self.offset, self.paddr, self.filesz)
def p_type_str(t):
if t <= 8:
return ('NULL', 'LOAD', 'DYNAMIC', 'INTERP', 'NOTE', 'SHLIB', 'PHDR', 'TLS', 'NUM')[t]
return "0x%x" % (t,)
def _get_ehdr(f):
if len(f) < _ehdr_fmt_size:
return False
ehdr = elf32_ehdr(f[0:_ehdr_fmt_size])
return ehdr
def elf32_big_endian_exec_p(f):
ehdr = _get_ehdr(f)
if not ehdr:
return False
#pprint(ehdr, sys.stderr)
e_ident = ehdr.ident
if not e_ident.startswith('\177ELF'):
return False
if (ord(e_ident[4]) != 1 # EI_CLASS == CLASS32
or ord(e_ident[5]) != 2 # EI_DATA == DATA2MSB
or ord(e_ident[6]) != 1 # EI_VERSION == EV_CURRENT
):
return False
if ehdr.type != 2: # e_type == ET_EXEC
return False
return True
# return (entry, (phdr, ...))
def get_elf32_prog_headers(f):
ehdr = _get_ehdr(f)
entry = ehdr.entry
phoff = ehdr.phoff
phentsize = ehdr.phentsize
phnum = ehdr.phnum
def extract(i):
start = phoff + i * phentsize
end = start + phentsize
return f[start:end]
return (entry, [elf32_phdr(extract(i)) for i in range(phnum)])
def main():
usage = "%prog: [options] elf_file"
parser = OptionParser()
parser.add_option("-o", "--output", default=None,
help="specify output filename [default=stdout]")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.print_help()
sys.exit(1)
elf_file = open(args[0], 'rb')
elf_contents = elf_file.read()
if not elf32_big_endian_exec_p(elf_contents):
sys.stderr.write("%s: not a big-endian 32-bit ELF executable\n" % (args[0],))
sys.exit(1)
if options.output is None:
sbf_file = sys.stdout
else:
sbf_file = open(options.output, 'wb')
(entry, phdrs) = get_elf32_prog_headers(elf_contents)
#pprint(phdrs, sys.stderr)
def phdr_to_sec_desc(phdr):
target_addr = phdr.paddr
data = elf_contents[phdr.offset:phdr.offset+phdr.filesz]
#print >>sys.stderr, "pdhr_to_sec_desc:", (target_addr, data)
return sbf.sec_desc(target_addr, data)
sections = map(phdr_to_sec_desc, phdrs)
# pprint(sections, sys.stderr)
sbf.write_sbf(sbf_file, sbf.header(entry, sections))
if __name__ == '__main__':
main()

134
zpu/bin/sbf.py Executable file
View File

@@ -0,0 +1,134 @@
#
# Copyright 2009 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
_SBF_MAGIC = 'SBF!'
_SBF_DONT_EXECUTE = 0x1
_SBF_MAX_SECTIONS = 14
_SBF_HEADER_LEN = 128
import struct
import sys
from pprint import pprint
def dump_data(f, offset, data):
L = len(data) // 4
for i in range(L):
f.write('%08x: %08x\n' % (offset + 4 * i, struct.unpack('>I', data[4*i:4*(i+1)])[0]))
remainder = len(data) - L * 4
if remainder != 0:
f.write('%08x: ' % (offset + L*4,))
i = 0
while i < remainder:
f.write('%02x' % ((ord(data[L*4 + i]),)))
i += 1
f.write('\n')
class sec_desc(object):
def __init__(self, target_addr, data):
self.target_addr = target_addr
self.data = data
def __repr__(self):
#print >>sys.stderr, "target_addr:", self.target_addr
#print >>sys.stderr, "data:", self.data
return "<sec_desc target_addr=0x%x len=%d>" % (
self.target_addr, len(self.data))
class header(object):
def __init__(self, entry, sections):
self.entry = entry
self.section = sections
def dump(self, f):
if self.entry == _SBF_DONT_EXECUTE:
f.write("Entry: DONT_EXECUTE\n")
else:
f.write("Entry: 0x%x\n" % (self.entry,))
for i in range(len(self.section)):
s = self.section[i]
f.write("Section[%d]: target_addr = 0x%x length = %d\n" % (i,
s.target_addr,
len(s.data)))
dump_data(f, s.target_addr, s.data)
#
# Returns an iterator. Each yield returns (target_addr, data)
#
def iterator(self, max_piece=512):
for s in self.section:
offset = 0
L = len(s.data)
while offset < L:
n = min(max_piece, L - offset)
yield (s.target_addr + offset,
s.data[offset:offset+n])
offset += n
def read_sbf(input_file):
"""Parse an SBF file"""
f = input_file.read(_SBF_HEADER_LEN)
#if len(f) < _SBF_HEADER_LEN or not f.startswith(_SBF_MAGIC):
#raise ValueError, '%s: not an SBF file' % (input_file.name,)
def extract(i):
start = 16+8*i
stop = start+8
return struct.unpack('>2I', f[start:stop])
def get_data(ss):
L = ss[1]
s = input_file.read(L)
#if len(s) != L:
#raise ValueError, '%s: file is too short' % (input_file.name(),)
return s
(magic, entry, nsections, reserved) = struct.unpack('>4s3I', f[0:16])
assert nsections <= _SBF_MAX_SECTIONS
descs = [extract(i) for i in range(nsections)]
#pprint(descs, sys.stderr)
data = map(get_data, descs)
secs = map(lambda ss, data: sec_desc(ss[0], data), descs, data)
return header(entry, secs)
def write_sbf(output_file, sbf_header):
assert(len(sbf_header.section) <= _SBF_MAX_SECTIONS)
sbf_header.nsections = len(sbf_header.section)
f = output_file
# write the file header
f.write(struct.pack('>4s3I', _SBF_MAGIC, sbf_header.entry, sbf_header.nsections, 0))
# write the section headers
for i in range(sbf_header.nsections):
f.write(struct.pack('>2I',
sbf_header.section[i].target_addr,
len(sbf_header.section[i].data)))
for i in range(_SBF_MAX_SECTIONS - sbf_header.nsections):
f.write(struct.pack('>2I', 0, 0))
# write the section data
for i in range(sbf_header.nsections):
f.write(sbf_header.section[i].data)
return True

363
zpu/bin/serial_loader Executable file
View File

@@ -0,0 +1,363 @@
#!/usr/bin/env python
#
# Copyright 2009 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import termios
import tty
import os
import sys
import threading
import Queue
from optparse import OptionParser
import time
import sbf
GDB_ESCAPE = chr(0x7d)
# Indexes for termios list.
IFLAG = 0
OFLAG = 1
CFLAG = 2
LFLAG = 3
ISPEED = 4
OSPEED = 5
CC = 6
class terminal(object):
def __init__(self, device, speed_bits):
fd = os.open(device, os.O_RDWR)
if not os.isatty(fd):
raise ValueError(device + " is not a tty")
self.read_file = os.fdopen(fd, "rb", 0)
self.write_file = os.fdopen(os.dup(fd), "wb", 0)
self.old_attrs = termios.tcgetattr(self.write_file.fileno())
#print "old_attrs: ", self.old_attrs
attrs = list(self.old_attrs) # copy of attributes
attrs[ISPEED] = speed_bits # set input and output speed
attrs[OSPEED] = speed_bits
termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs)
tty.setraw(self.write_file.fileno()) # enable raw mode
attrs = termios.tcgetattr(self.write_file.fileno())
attrs[CC][termios.VMIN] = 1 # minimim of 1 char
attrs[CC][termios.VTIME] = 1 # wait no longer than 1/10
termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs)
def __del__(self):
termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, self.old_attrs)
self.read_file.close()
self.write_file.close()
def read(self, n):
"""Read at most n bytes from tty"""
return self.read_file.read(n)
def write(self, str):
"""Write str to tty."""
return self.write_file.write(str)
def hexnibble(i):
return "0123456789abcdef"[i & 0xf]
def build_pkt(payload):
s = ['$']
checksum = 0
for p in payload:
if p in ('$', '#', GDB_ESCAPE):
s.append(GDB_ESCAPE)
s.append(p)
checksum += ord(p)
checksum &= 0xff
s.append('#')
s.append(hexnibble(checksum >> 4))
s.append(hexnibble(checksum))
return ''.join(s)
def build_memory_read_pkt(addr, len):
return build_pkt(('m%x,%x' % (addr, len)))
def build_memory_write_hex_pkt(addr, s):
hexdata = ''.join(["%02x" % (ord(c),) for c in s])
return build_pkt(('M%x,%x:' % (addr, len(s))) + hexdata)
def build_memory_write_pkt(addr, s):
return build_pkt(('X%x,%x:' % (addr, len(s))) + s)
def build_goto_pkt(addr):
return build_pkt(('c%x' % (addr,)))
def get_packet(f):
"""Return a valid packet, or None on EOF or timeout"""
LOOKING_FOR_DOLLAR = 0
LOOKING_FOR_HASH = 1
CSUM1 = 2
CSUM2 = 3
fd = f.fileno()
state = LOOKING_FOR_DOLLAR
buf = []
while True:
ch = os.read(fd, 1)
sys.stdout.write(ch)
if len(ch) == 0:
print("Returning None")
return(None)
if state == LOOKING_FOR_DOLLAR:
if ch == '$':
buf = []
state = LOOKING_FOR_HASH
elif ch == '#':
state = LOOKING_FOR_DOLLAR
elif state == LOOKING_FOR_HASH:
if ch == '$':
state = LOOKING_FOR_DOLLAR
elif ch == '#':
state = CSUM1
else:
if ch == GDB_ESCAPE:
ch = getc()
buf.append(ch)
elif state == CSUM1:
chksum1 = ch
state = CSUM2
elif state == CSUM2:
chksum2 = ch
r = ''.join(buf)
if chksum1 == '.' and chksum2 == '.':
return r
expected_checksum = int(chksum1 + chksum2, 16)
checksum = 0
for c in buf:
checksum += ord(c)
checksum &= 0xff
if checksum == expected_checksum:
return r
state = LOOKING_FOR_DOLLAR
else:
raise ValueError( "Invalid state")
class packet_reader_thread(threading.Thread):
def __init__(self, tty_in, q):
threading.Thread.__init__(self)
self.setDaemon(1)
self.tty_in = tty_in
self.q = q
self._keep_running = True
self.start()
def run(self):
while self._keep_running == True:
p = get_packet(self.tty_in)
if p is not None:
self.q.put(('pkt', p))
def _make_tr_table():
table = []
for c in range(256):
if c < ord(' ') or c > ord('~'):
table.append('.')
else:
table.append(chr(c))
return ''.join(table)
class controller(object):
def __init__(self, tty):
self.tty = tty
self.q = Queue.Queue(0)
self.timers = {}
self.next_tid = 1
self.current_tid = 0
self.ntimeouts = 0
self.packet_reader = packet_reader_thread(tty.read_file, self.q)
self.state = None
self.debug = False
self.tt = _make_tr_table()
self.done = False
self.addr = None
self.bits = None
def shutdown(self):
self.packet_reader._keep_running = False
def start_timeout(self, timeout_in_secs):
def callback(tid):
if self.timers.has_key(tid):
del self.timers[tid]
self.q.put(('timeout', tid))
self.next_tid += 1
tid = self.next_tid
timer = threading.Timer(timeout_in_secs, callback, (tid,))
self.timers[tid] = timer
timer.start()
return tid
def cancel_timeout(self, tid):
if self.timers.has_key(tid):
self.timers[tid].cancel()
del self.timers[tid]
def send_packet(self, pkt):
if self.debug:
if len(pkt) > 64:
s = pkt[0:64] + '...'
else:
s = pkt
sys.stdout.write('-> ' + s.translate(self.tt) + '\n')
self.tty.write(pkt);
def send_packet_start_timeout(self, pkt, secs):
self.send_packet(pkt)
self.current_tid = self.start_timeout(secs)
def upload_code(self, sbf):
MAX_PIECE = 512 # biggest piece to send
MWRITE_TIMEOUT = 0.1
IDLE = 0
WAIT_FOR_ACK = 1
UPLOAD_DONE = 2
DONE = 3
FAILED = 4
self.done = False
it = sbf.iterator(MAX_PIECE)
entry_addr = sbf.entry
def get_next_bits():
try:
(self.addr, self.bits) = it.next()
except StopIteration:
self.done = True
def is_done():
return self.done
def send_piece():
pkt = build_memory_write_pkt(self.addr, self.bits)
#pkt = build_memory_write_hex_pkt(self.addr, self.bits)
self.send_packet_start_timeout(pkt, MWRITE_TIMEOUT)
state = WAIT_FOR_ACK
def advance():
get_next_bits()
if is_done():
self.state = DONE
self.send_packet(build_goto_pkt(entry_addr))
else:
self.ntimeouts = 0
send_piece()
get_next_bits()
if is_done(): # empty file
return True
send_piece() # initial transition
while 1:
(event, value) = self.q.get()
if event == 'timeout' and value == self.current_tid:
self.ntimeouts += 1
if self.ntimeouts >= 5:
return False # say we failed
send_piece() # resend
elif event == 'pkt':
if value == 'OK':
self.cancel_timeout(self.current_tid)
advance()
if self.state == DONE:
return True
else:
print("Error returned from firmware: " + value)
return False
else:
print("Unknown event:", (event, value))
def main():
usage="%prog: [options] filename"
parser = OptionParser(usage=usage)
parser.add_option("-t", "--tty", type="string", default="/dev/ttyS0",
help="select serial port [default=%default]")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.print_help()
raise SystemExit(1)
filename = args[0]
f = open(filename, "rb")
try:
# Try to open the file as an SBF file
sbf_header = sbf.read_sbf(f)
except:
# If that fails, build an SBF from the binary, assuming default
# load address and entry point
f.seek(0)
t = f.read()
if t.startswith('\177ELF'):
sys.stderr.write("Can't load an ELF file. Please use an SBF file instead.\n")
raise SystemExit( 1)
sbf_header = sbf.header(0x8000, [sbf.sec_desc(0x8000, t)])
tty = terminal(options.tty, termios.B115200)
ctrl = controller(tty)
ok = ctrl.upload_code(sbf_header)
if ok:
print("OK")
try:
raw_input("Press Enter to exit: ")
except KeyboardInterrupt:
pass
ctrl.shutdown()
time.sleep(0.2)
else:
print("Upload failed")
ctrl.shutdown()
if __name__ == "__main__":
main()

138
zpu/bin/uart_ihex_flash_loader.py Executable file
View File

@@ -0,0 +1,138 @@
#!/usr/bin/python
import serial
from optparse import OptionParser
import os, sys
#TODO: pull everything but parser out of main() and put it in a separate function we can call from another script. lets us automate loading RAM+FLASH to produce a fully-loaded image.
#TODO: make it fail gracefully -- if it gets a NOK or times out, do at least one retry.
#TODO: put hooks in (eventually) to allow verifying a firmware image so the user can more safely update the "safe" image
#TODO: how about a progress indicator? FPGA images take FOREVER. you can use wc -l to get the number of lines, or do it with file i/o.
def main():
usage="%prog: [options] filename"
parser = OptionParser(usage=usage)
parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0",
help="select serial port [default=%default]")
parser.add_option("-b", "--baudrate", type=int, default=115200,
help="set baudrate [default=%default]")
parser.add_option("-F", "--write-safe-firmware", action="store_const", const=1, dest="image",
help="write to safe firmware image")
parser.add_option("-f", "--write-production-firmware", action="store_const", const=2, dest="image",
help="write to production firmware image")
parser.add_option("-P", "--write-safe-fpga", action="store_const", const=3, dest="image",
help="write to safe FPGA image")
parser.add_option("-p", "--write-production-fpga", action="store_const", const=4, dest="image",
help="write to production FPGA image")
(options, args) = parser.parse_args()
if(options.image is None):
print("At least one of -f, -F, -p, -P must be specified.\n")
parser.print_help()
raise SystemExit(1)
if len(args) != 1:
parser.print_help()
raise SystemExit(1)
if(options.image == 3):
print "Are you *really* sure you want to write to the failsafe FPGA image? If you mess this up your USRP2+ will become a brick. Press 'y' to continue, any other key to abort."
if(raw_input().rstrip() is not "y"):
print "Good choice."
raise SystemExit(0)
elif(options.image == 1):
print "Are you *really* sure you want to write to the failsafe firmware image? If you mess this up your USRP2+ will only be able to be reprogrammed via the UART RAM loader.\nPress 'y' to continue, any other key to abort."
if(raw_input().rstrip() is not "y"):
print "Good choice."
raise SystemExit(0)
filename = args[0]
f = open(filename, "r")
#now we start doing things...
if(os.path.exists(options.tty) is False):
sys.stderr.write("No serial port found at %s\n" % options.tty)
raise SystemExit(1)
try:
ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0)
except serial.SerialException:
sys.stderr.write("Unable to open serial port\n")
raise SystemExit(1)
ser.open()
#test to see if a valid USRP2+ in flash load mode is connected
ser.write("garbage\n")
ser.readline()
ser.write("!SECTORSIZE\n")
reply = ser.readline().rstrip()
if("NOK" in reply):
sys.stderr.write("Error writing to USRP2+. Try again.\n")
raise SystemExit(1)
elif("OK" in reply):
sectorsize = int(reply[3:5], 16)
print("USRP2+ found with sector size %i. Erasing old image." % 2**sectorsize)
else:
sys.stderr.write("Invalid response or no USRP2+ connected.\n")
raise SystemExit(1)
if(options.image == 1):
sectors = range(127, 128)
runcmd = "!RUNSFD\n"
elif(options.image == 2):
sectors = range(64, 65)
runcmd = "!RUNPFD\n"
elif(options.image == 3):
sectors = range(0,32)
runcmd = "!RUNSFPGA\n"
elif(options.image == 4):
sectors = range(32,64)
runcmd = "!RUNPFPGA\n"
writeaddr = sectors[0] << sectorsize
if(options.image < 3):
writeaddr -= 0x8000 #i know this is awkward, but we subtract 0x8000 from the address for firmware loads. the reason we do this is that the IHX files are located at 0x8000 (RAM_BASE), and
#doing this here allows us to use the same IHX files for RAM load as for Flash load, without relocating in objcopy or relinking with another ld script.
#this limits us to writing above 32K for our firmware images. since the safe FPGA image located at 0x00000000 takes up 2MB of space this isn't really a worry.
#FPGA images (.mcs) always start at 0x00000000 so they don't need this relocation.
for sector in sectors:
print "Erasing sector %i" % sector
ser.write("!ERASE %i\n" % sector)
reply = ser.readline()
if("NOK" in reply):
sys.stderr.write("Error erasing sector %i" % sector)
raise SystemExit(1)
print "Setting start address to %i" % writeaddr
ser.write("!SETADDR %i\n" % writeaddr)
if("NOK" in reply):
sys.stderr.write("Error setting address\n")
raise SystemExit(1)
else:
print reply
for line in f:
ser.write(line.rstrip()+'\n')
reply = ser.readline()
if("NOK" in reply): #TODO: simplify this logic, use (reply.rstrip() is "NOK")
print("Received NOK reply during data write")
raise SystemExit(1)
elif("DONE" in reply):
print("Finished writing program. Loading...\n")
ser.write(runcmd)
elif("OK" not in reply):
print("Received invalid reply %s during data write" % reply)
raise SystemExit(1)
else:
print reply.rstrip() + '\t' + line.rstrip()
print ser.readline()
if __name__ == '__main__':
main()

70
zpu/bin/uart_ihex_ram_loader.py Executable file
View File

@@ -0,0 +1,70 @@
#!/usr/bin/python
import serial
from optparse import OptionParser
import os, sys
def main():
usage="%prog: [options] filename"
parser = OptionParser(usage=usage)
parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0",
help="select serial port [default=%default]")
parser.add_option("-b", "--baudrate", type=int, default=115200,
help="set baudrate [default=%default]")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.print_help()
raise SystemExit(1)
filename = args[0]
f = open(filename, "r")
#all we have to do is load the IHX file and attempt to spit it out to the serial port.
if(os.path.exists(options.tty) is False):
sys.stderr.write("No serial port found at %s\n" % options.tty)
raise SystemExit(1)
try:
ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0)
except serial.SerialException:
sys.stderr.write("Unable to open serial port\n")
raise SystemExit(1)
ser.open()
#test to see if a valid USRP2+ in RAM load mode is connected
ser.write("WOOOOO\n");
reply = ser.readline()
if("NOK" not in reply):
sys.stderr.write("Valid USRP2+ not connected or no response received\n")
raise SystemExit(1)
else:
print("USRP2+ found.")
for line in f:
ser.write(line.rstrip() + '\n')
reply = ser.readline()
if("NOK" in reply): #blocks to wait for response
print("Received NOK reply from USRP2+")
raise SystemExit(1)
elif("OK" not in reply):
print("Received invalid reply!")
raise SystemExit(1)
# else:
# print("OK received")
print "USRP2+ RAM programmed.\nLoading program."
#at this point it should have sent the end line of the file, which starts the program!
#we'll just act like a dumb terminal now
# ser.timeout = 0
# try:
# while 1:
# print ser.readline()
# except KeyboardInterrupt:
# raise SystemExit(0)
if __name__ == '__main__':
main()

50
zpu/lib/CMakeLists.txt Normal file
View File

@@ -0,0 +1,50 @@
#
# Copyright 2010 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
########################################################################
SET(COMMON_SRCS
${CMAKE_SOURCE_DIR}/lib/u2_init.c
${CMAKE_SOURCE_DIR}/lib/umtrx_init.c
${CMAKE_SOURCE_DIR}/lib/abort.c
# ${CMAKE_SOURCE_DIR}/lib/ad9510.c
# ${CMAKE_SOURCE_DIR}/lib/clocks.c
${CMAKE_SOURCE_DIR}/lib/eeprom.c
${CMAKE_SOURCE_DIR}/lib/eth_addrs.c
${CMAKE_SOURCE_DIR}/lib/eth_mac.c
${CMAKE_SOURCE_DIR}/lib/_exit.c
${CMAKE_SOURCE_DIR}/lib/exit.c
${CMAKE_SOURCE_DIR}/lib/hal_io.c
${CMAKE_SOURCE_DIR}/lib/hal_uart.c
${CMAKE_SOURCE_DIR}/lib/i2c.c
${CMAKE_SOURCE_DIR}/lib/mdelay.c
${CMAKE_SOURCE_DIR}/lib/memcpy_wa.c
${CMAKE_SOURCE_DIR}/lib/memset_wa.c
${CMAKE_SOURCE_DIR}/lib/nonstdio.c
${CMAKE_SOURCE_DIR}/lib/pic.c
${CMAKE_SOURCE_DIR}/lib/pkt_ctrl.c
${CMAKE_SOURCE_DIR}/lib/print_addrs.c
${CMAKE_SOURCE_DIR}/lib/print_rmon_regs.c
${CMAKE_SOURCE_DIR}/lib/print_buffer.c
${CMAKE_SOURCE_DIR}/lib/printf.c
${CMAKE_SOURCE_DIR}/lib/ihex.c
${CMAKE_SOURCE_DIR}/lib/spi.c
${CMAKE_SOURCE_DIR}/lib/net_common.c
${CMAKE_SOURCE_DIR}/lib/arp_cache.c
${CMAKE_SOURCE_DIR}/lib/banal.c
${CMAKE_SOURCE_DIR}/lib/udp_uart.c
${CMAKE_SOURCE_DIR}/lib/gpsdo.c
)

27
zpu/lib/_exit.c Normal file
View File

@@ -0,0 +1,27 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Stub so we can compile using 3.4 based mb-gcc
*/
void
_exit(int status)
{
while (1)
;
}

32
zpu/lib/abort.c Normal file
View File

@@ -0,0 +1,32 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <nonstdio.h>
extern void _exit(int status);
void
abort(void)
{
putstr("\n\nabort\n");
// FIXME loop blinking leds
_exit(-1);
}

42
zpu/lib/ad9510.c Normal file
View File

@@ -0,0 +1,42 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ad9510.h"
#include "spi.h"
#include <memory_map.h>
#define RD (1 << 15)
#define WR (0 << 15)
void
ad9510_write_reg(int regno, uint8_t value)
{
uint32_t inst = WR | (regno & 0xff);
uint32_t v = (inst << 8) | (value & 0xff);
spi_transact(SPI_TXONLY, SPI_SS_AD9510, v, 24, SPIF_PUSH_FALL);
}
int
ad9510_read_reg(int regno)
{
uint32_t inst = RD | (regno & 0xff);
uint32_t v = (inst << 8) | 0;
uint32_t r = spi_transact(SPI_TXRX, SPI_SS_AD9510, v, 24,
SPIF_PUSH_FALL | SPIF_LATCH_FALL);
return r & 0xff;
}

30
zpu/lib/ad9510.h Normal file
View File

@@ -0,0 +1,30 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_AD9510_H
#define INCLUDED_AD9510_H
#include <stdint.h>
/*
* Analog Device AD9510 1.2 GHz Clock Distribution IC w/ PLL
*/
void ad9510_write_reg(int regno, uint8_t value);
int ad9510_read_reg(int regno);
#endif /* INCLUDED_AD9510_H */

90
zpu/lib/arp_cache.c Normal file
View File

@@ -0,0 +1,90 @@
/* -*- c++ -*- */
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "arp_cache.h"
#include <stddef.h>
typedef struct {
struct ip_addr ip;
eth_mac_addr_t mac;
} arp_cache_t;
#define NENTRIES 8 // power-of-2
static size_t nentries;
static size_t victim;
static arp_cache_t cache[NENTRIES];
void
arp_cache_init(void)
{
nentries = 0;
victim = 0;
}
// returns non-negative index if found, else -1
static int
arp_cache_lookup(const struct ip_addr *ip)
{
int i;
for (i = 0; i < nentries; i++)
if (cache[i].ip.addr == ip->addr)
return i;
return -1;
}
static int
arp_cache_alloc(void)
{
if (nentries < NENTRIES)
return nentries++;
int i = victim;
victim = (victim + 1) % NENTRIES;
return i;
}
void
arp_cache_update(const struct ip_addr *ip,
const eth_mac_addr_t *mac)
{
int i = arp_cache_lookup(ip);
if (i < 0){
i = arp_cache_alloc();
cache[i].ip = *ip;
cache[i].mac = *mac;
}
else {
cache[i].mac = *mac;
}
}
bool
arp_cache_lookup_mac(const struct ip_addr *ip,
eth_mac_addr_t *mac)
{
int i = arp_cache_lookup(ip);
if (i < 0)
return false;
*mac = cache[i].mac;
return true;
}

33
zpu/lib/arp_cache.h Normal file
View File

@@ -0,0 +1,33 @@
/* -*- c++ -*- */
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ARP_CACHE_H
#define INCLUDED_ARP_CACHE_H
#include <lwip/ip_addr.h>
#include <net/eth_mac_addr.h>
#include <stdbool.h>
void arp_cache_init(void);
void arp_cache_update(const struct ip_addr *ip,
const eth_mac_addr_t *mac);
bool arp_cache_lookup_mac(const struct ip_addr *ip,
eth_mac_addr_t *mac);
#endif /* INCLUDED_ARP_CACHE_H */

31
zpu/lib/banal.c Normal file
View File

@@ -0,0 +1,31 @@
/* -*- c++ -*- */
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <banal.h>
uint32_t
get_uint32(const unsigned char *s)
{
return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
}
uint64_t
get_uint64(const unsigned char *s)
{
return (((uint64_t)get_uint32(s)) << 32) | get_uint32(s+4);
}

71
zpu/lib/banal.h Normal file
View File

@@ -0,0 +1,71 @@
/* -*- c -*- */
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_BANAL_H
#define INCLUDED_BANAL_H
#include <stdint.h>
#define dimof(x) (sizeof(x)/sizeof(x[0]))
//-------------- unsigned get_int 8, 16, 32, 64 --------------//
static inline uint8_t
get_uint8(const unsigned char *s)
{
return s[0];
}
static inline uint16_t
get_uint16(const unsigned char *s)
{
return (s[0] << 8) | s[1];
}
uint32_t
get_uint32(const unsigned char *s);
uint64_t
get_uint64(const unsigned char *s);
//--------------- signed get_int 8, 16, 32, 64 --------------//
static inline int8_t
get_int8(const unsigned char *s)
{
return get_uint8(s);
}
static inline int16_t
get_int16(const unsigned char *s)
{
return get_uint16(s);
}
static inline int32_t
get_int32(const unsigned char *s)
{
return get_uint32(s);
}
static inline int64_t
get_int64(const unsigned char *s)
{
return get_uint64(s);
}
#endif /* INCLUDED_BANAL_H */

118
zpu/lib/clocks.c Normal file
View File

@@ -0,0 +1,118 @@
//
// Copyright 2010-2011 Ettus Research LLC
//
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <clocks.h>
#include <stdbool.h>
#include "memory_map.h"
#include "ad9510.h"
#include "spi.h"
/*!
* \brief Lock Detect -- Return True if our PLL is locked
*/
bool clocks_lock_detect();
/*!
* \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle.
*/
void clocks_enable_fpga_clk(bool enable, int divisor);
void
clocks_init(void)
{
// Set up basic clocking functions in AD9510
ad9510_write_reg(0x45, 0x01);
//enable the 100MHz clock output to the FPGA for 50MHz CPU clock
clocks_enable_fpga_clk(true, 1);
spi_wait();
//wait for the clock to stabilize
while(!clocks_lock_detect());
//issue a reset to the DCM so it locks up to the new freq
output_regs->clk_ctrl |= CLK_RESET;
}
bool
clocks_lock_detect()
{
return (pic_regs->pending & PIC_CLKSTATUS);
}
int inline
clocks_gen_div(int divisor)
{
int L,H;
L = (divisor>>1)-1;
H = divisor-L-2;
return (L<<4)|H;
}
#define CLOCK_OUT_EN 0x08
#define CLOCK_OUT_DIS_CMOS 0x01
#define CLOCK_OUT_DIS_PECL 0x02
#define CLOCK_DIV_DIS 0x80
#define CLOCK_DIV_EN 0x00
#define CLOCK_MODE_PECL 1
#define CLOCK_MODE_LVDS 2
#define CLOCK_MODE_CMOS 3
//CHANGED: set to PECL for default behavior
void
clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode)
{
int enable_word, div_word, div_en_word;
switch(mode) {
case CLOCK_MODE_LVDS :
enable_word = enable ? 0x02 : 0x03;
break;
case CLOCK_MODE_CMOS :
enable_word = enable ? 0x08 : 0x09;
break;
case CLOCK_MODE_PECL :
default:
enable_word = enable ? 0x08 : 0x0A;
break;
}
if(enable && (divisor>1)) {
div_word = clocks_gen_div(divisor);
div_en_word = CLOCK_DIV_EN;
}
else {
div_word = 0;
div_en_word = CLOCK_DIV_DIS;
}
ad9510_write_reg(reg_en,enable_word); // Output en/dis
ad9510_write_reg(reg_div,div_word); // Set divisor
ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider
ad9510_write_reg(0x5A, 0x01); // Update Regs
}
// Clock 1
void
clocks_enable_fpga_clk(bool enable, int divisor)
{
clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL);
}

30
zpu/lib/clocks.h Normal file
View File

@@ -0,0 +1,30 @@
//
// Copyright 2010-2011 Ettus Research LLC
//
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_CLOCKS_H
#define INCLUDED_CLOCKS_H
/*!
* One time call to initialize the master clock to a reasonable state.
* We come out of here using our free running 100MHz oscillator.
*/
void clocks_init(void);
#endif /* INCLUDED_CLOCKS_H */

26
zpu/lib/compiler.h Normal file
View File

@@ -0,0 +1,26 @@
/* -*- c++ -*- */
/*
* Copyright 2009, 2010 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_COMPILER_H
#define INCLUDED_COMPILER_H
// FIXME gcc specific.
#define _AL4 __attribute__((aligned (4)))
#define FORCE_INLINE inline __attribute__((always_inline))
#endif /* INCLUDED_COMPILER_H */

88
zpu/lib/eeprom.c Normal file
View File

@@ -0,0 +1,88 @@
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "i2c.h"
#include "mdelay.h"
#include "usrp2/fw_common.h"
static const int EEPROM_PAGESIZE = 16;
bool find_safe_booted_flag(void) {
#ifdef NO_EEPROM
return 0;
#else
unsigned char flag_byte;
eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1);
return (flag_byte == 0x5E);
#endif
}
void set_safe_booted_flag(bool flag) {
#ifndef NO_EEPROM
unsigned char flag_byte = flag ? 0x5E : 0xDC;
eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1);
#endif
}
#ifndef NO_EEPROM
bool
eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len)
{
unsigned char cmd[2];
const unsigned char *p = (unsigned char *) buf;
// The simplest thing that could possibly work:
// all writes are single byte writes.
//
// We could speed this up using the page write feature,
// but we write so infrequently, why bother...
while (len-- > 0){
cmd[0] = eeprom_offset++;
cmd[1] = *p++;
bool r = i2c_write (i2c_addr, cmd, sizeof (cmd));
mdelay (10); // delay 10ms worst case write time
if (!r)
return false;
}
return true;
}
bool
eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len)
{
unsigned char *p = (unsigned char *) buf;
// We setup a random read by first doing a "zero byte write".
// Writes carry an address. Reads use an implicit address.
unsigned char cmd[1];
cmd[0] = eeprom_offset;
if (!i2c_write (i2c_addr, cmd, sizeof (cmd)))
return false;
while (len > 0){
// int n = std::min (len, MAX_EP0_PKTSIZE);
int n = len;
if (!i2c_read (i2c_addr, p, n))
return false;
len -= n;
p += n;
}
return true;
}
#endif

150
zpu/lib/eth_addrs.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* Copyright 2010-2011 Ettus Research LLC
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ethernet.h"
#include "memory_map.h"
#include "nonstdio.h"
#include <stdbool.h>
#include "i2c.h"
#include "usrp2/fw_common.h"
static bool
unprogrammed(const void *t, size_t len)
{
int i;
uint8_t *p = (uint8_t *)t;
bool all_zeros = true;
bool all_ones = true;
for (i = 0; i < len; i++){
all_zeros &= p[i] == 0x00;
all_ones &= p[i] == 0xff;
}
return all_ones | all_zeros;
}
//////////////////// MAC Addr Stuff ///////////////////////
static bool src_mac_addr_initialized = false;
static const eth_mac_addr_t default_mac_addr = {{
0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
}};
static eth_mac_addr_t src_mac_addr = {{
0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
}};
void set_default_mac_addr(void)
{
src_mac_addr_initialized = true;
src_mac_addr = default_mac_addr;
}
const eth_mac_addr_t *
ethernet_mac_addr(void)
{
if (!src_mac_addr_initialized){ // fetch from eeprom
src_mac_addr_initialized = true;
#ifndef NO_EEPROM
// if we're simulating, don't read the EEPROM model, it's REALLY slow
if (hwconfig_simulation_p())
return &src_mac_addr;
eth_mac_addr_t tmp;
bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp));
if (!ok || unprogrammed(&tmp, sizeof(tmp))){
// use the default
}
else
src_mac_addr = tmp;
#endif
}
return &src_mac_addr;
}
bool
ethernet_set_mac_addr(const eth_mac_addr_t *t)
{
#ifdef NO_EEPROM
bool ok = true;
#else
bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t));
#endif
if (ok){
src_mac_addr = *t;
src_mac_addr_initialized = true;
//eth_mac_set_addr(t); //this breaks the link
}
return ok;
}
//////////////////// IP Addr Stuff ///////////////////////
static bool src_ip_addr_initialized = false;
static const struct ip_addr default_ip_addr = {
(192 << 24 | 168 << 16 | 10 << 8 | 2 << 0)
};
static struct ip_addr src_ip_addr = {
(192 << 24 | 168 << 16 | 10 << 8 | 2 << 0)
};
void set_default_ip_addr(void)
{
src_ip_addr_initialized = true;
src_ip_addr = default_ip_addr;
}
const struct ip_addr *get_ip_addr(void)
{
if (!src_ip_addr_initialized){ // fetch from eeprom
src_ip_addr_initialized = true;
#ifndef NO_EEPROM
// if we're simulating, don't read the EEPROM model, it's REALLY slow
if (hwconfig_simulation_p())
return &src_ip_addr;
struct ip_addr tmp;
bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp));
if (!ok || unprogrammed(&tmp, sizeof(tmp))){
// use the default
}
else
src_ip_addr = tmp;
#endif
}
return &src_ip_addr;
}
bool set_ip_addr(const struct ip_addr *t){
#ifdef NO_EEPROM
bool ok = true;
#else
bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr));
#endif
if (ok){
src_ip_addr = *t;
src_ip_addr_initialized = true;
}
return ok;
}

121
zpu/lib/eth_mac.c Normal file
View File

@@ -0,0 +1,121 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "eth_mac.h"
#include "memory_map.h"
#include <stdbool.h>
#include "eth_phy.h" // for simulation constants
#include "mdelay.h"
#include "stdio.h"
#define PHY_ADDR 1
void
eth_mac_set_addr(const eth_mac_addr_t *src)
{
/* disable because MAC_SET_PASS_ALL is set below
eth_mac->ucast_hi =
(((unsigned int)src->addr[0])<<8) +
((unsigned int)src->addr[1]);
eth_mac->ucast_lo =
(((unsigned int)src->addr[2])<<24) +
(((unsigned int)src->addr[3])<<16) +
(((unsigned int)src->addr[4])<<8) +
(((unsigned int)src->addr[5]));
*/
}
void
eth_mac_init(const eth_mac_addr_t *src)
{
eth_mac->miimoder = 25; // divider from CPU clock (50MHz/25 = 2MHz)
eth_mac_set_addr(src);
eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST | MAC_SET_PAUSE_SEND_EN | MAC_SET_PASS_ALL;
eth_mac->pause_time = 38;
eth_mac->pause_thresh = 1200;
// set rx flow control high and low water marks
// unsigned int lwmark = (2*2048 + 64)/4; // 2 * 2048-byte frames + 1 * 64-byte pause frame
// eth_mac->fc_hwmark = lwmark + 2048/4; // plus a 2048-byte frame
// eth_mac->fc_lwmark = 600; // there are currently 2047 lines in the fifo
// eth_mac->fc_hwmark = 1200;
//eth_mac->fc_padtime = 1700; // how long before flow control runs out do we
// request a re-pause. Units of 8ns (bytes)
//eth_mac->tx_pause_en = 0; // pay attn to pause frames sent to us
//eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
//eth_mac->pause_frame_send_en = 0; // enable sending pause frames
}
int
eth_mac_read_rmon(int addr)
{
int t = 0;
/*
eth_mac->rmon_rd_addr = addr;
eth_mac->rmon_rd_apply = 1;
while(eth_mac->rmon_rd_grant == 0)
;
t = eth_mac->rmon_rd_dout;
eth_mac->rmon_rd_apply = 0;
*/
return t;
}
int
eth_mac_miim_read(int addr)
{
int phy_addr = PHY_ADDR;
eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr;
eth_mac->miicommand = MIIC_RSTAT;
while((eth_mac->miistatus & MIIS_BUSY) != 0)
;
int r = eth_mac->miirx_data;
//printf("MIIM-READ ADDR 0x%x DATA 0x%x\n",addr, r);
return r;
}
void
eth_mac_miim_write(int addr, int value)
{
int phy_addr = PHY_ADDR;
eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr;
eth_mac->miitx_data = value;
eth_mac->miicommand = MIIC_WCTRLDATA;
// printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value);
while((eth_mac->miistatus & MIIS_BUSY) != 0)
;
}
int
eth_mac_miim_read_status(void)
{
if (hwconfig_simulation_p())
return 0;
return eth_mac->miistatus;
}

32
zpu/lib/eth_mac.h Normal file
View File

@@ -0,0 +1,32 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ETH_MAC_H
#define INCLUDED_ETH_MAC_H
#include <net/eth_mac_addr.h>
void eth_mac_init(const eth_mac_addr_t *src);
void eth_mac_set_addr(const eth_mac_addr_t *src);
int eth_mac_read_rmon(int addr);
int eth_mac_miim_read(int addr);
void eth_mac_miim_write(int addr, int value);
int eth_mac_miim_read_status(void);
#endif /* INCLUDED_ETH_MAC_H */

99
zpu/lib/ethernet.h Normal file
View File

@@ -0,0 +1,99 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ETHERNET_H
#define INCLUDED_ETHERNET_H
#include <net/eth_mac_addr.h>
#include <lwip/ip_addr.h>
#include <stdbool.h>
typedef void (*ethernet_link_changed_callback_t)(int speed);
/*!
* \brief one time call to initialize ethernet
*/
void ethernet_init(void);
/*!
* \brief Specify the function to call on link state changes.
*
* When the link comes up, speed is the link speed in Mbit/s.
* When the link goes down, speed is 0.
*/
void ethernet_register_link_changed_callback(ethernet_link_changed_callback_t cb);
/*!
* \returns ethernet MAC address
*/
const eth_mac_addr_t *ethernet_mac_addr(void);
/*!set mac addr to default*/
void set_default_mac_addr(void);
/*!
* \brief write mac address to eeprom and begin using it
*/
bool ethernet_set_mac_addr(const eth_mac_addr_t *t);
/*!
* \returns IP address
*/
const struct ip_addr *get_ip_addr(void);
/*!set ip addr to default*/
void set_default_ip_addr(void);
/*!
* \brief write ip address to eeprom and begin using it
*/
bool set_ip_addr(const struct ip_addr *t);
/*
* \brief read RMON regs and return error mask
*/
int ethernet_check_errors(void);
#define RME_RX_CRC 0x0001
#define RME_RX_FIFO_FULL 0x0002
#define RME_RX_2SHORT_2LONG 0x0004
#define RME_TX_JAM_DROP 0x0010
#define RME_TX_FIFO_UNDER 0x0020
#define RME_TX_FIFO_OVER 0x0040
typedef enum { LS_UNKNOWN, LS_DOWN, LS_UP } eth_link_state_t;
// flow control bitmasks
#define FC_NONE 0x0
#define FC_WE_TX 0x1 // we send PAUSE frames
#define FC_WE_RX 0x2 // we honor received PAUSE frames
#define FC_SYMM (FC_WE_TX | FC_WE_RX)
#define S_UNKNOWN (-1) // unknown link speed
typedef struct {
eth_link_state_t link_state;
int link_speed; // in Mb/s
int flow_control;
} ethernet_t;
#endif /* INCLUDED_ETHERNET_H */

27
zpu/lib/ethertype.h Normal file
View File

@@ -0,0 +1,27 @@
/* -*- c++ -*- */
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ETHERTYPE_H
#define INCLUDED_ETHERTYPE_H
// all we care about
#define ETHERTYPE_IPV4 0x0800
#define ETHERTYPE_ARP 0x0806
#endif /* INCLUDED_ETHERTYPE_H */

28
zpu/lib/exit.c Normal file
View File

@@ -0,0 +1,28 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
extern void _exit(int status);
void
exit(int status)
{
_exit(status);
}

198
zpu/lib/gpsdo.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* Copyright 2012 Sylvain Munaut <tnt@246tNt.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* peripheral headers */
#include "u2_init.h"
#include "pic.h"
#include "spi.h"
#include "memory_map.h"
/* printf headers */
#include "nonstdio.h"
/* standard headers */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
/* #define GPSDO_DEBUG 1 */
/* DAC */
/* ---- */
#define DAC_BITS 12
uint16_t dac_value; /* Current DAC value */
int
set_vctcxo_dac(uint16_t v)
{
#ifdef GPSDO_DEBUG
printf("DAC: %d\n", v);
#endif
dac_value = v;
return spi_transact(
SPI_TXRX, SPI_SS_DAC,
v & ((1 << DAC_BITS) - 1),
16, SPIF_PUSH_RISE | SPIF_LATCH_RISE
);
}
uint16_t
get_vctcxo_dac(void)
{
return dac_value;
}
/* PID */
/* --- */
#define PID_SCALE_SHIFT 7
#define PID_TARGET 52000000 /* 52 MHz */
#define PID_MAX_ERR 10000 /* 10 kHz off max */
#define PID_MAX_DEV ((1 << (DAC_BITS-1)) - 1)
#define PID_MID_VAL (1 << (DAC_BITS-1)) /* 2048 - the middle value of the DAC */
#define MAX_INT ((1<<31)-1)
typedef struct {
/* Loop constants */
int16_t Pk;
int16_t Ik;
int16_t Dk;
int32_t max_error;
int32_t max_sum_error;
/* Previous value */
int32_t val_prev;
/* State */
int32_t err_sum;
} pid_data_t;
static pid_data_t g_pid;
static void
_gpsdo_pid_init(void)
{
/* Configure loop */
g_pid.Pk = 64;
g_pid.Ik = 16;
g_pid.Dk = 256; /* Seems high but we LPF PID input so d is dampened */
/* Reset state */
g_pid.val_prev = PID_TARGET;
g_pid.err_sum = 0;
}
static void
_gpsdo_pid_step(int32_t val)
{
int32_t error;
int32_t p_term, d_term, i_term;
int32_t tot;
/* Compute error */
error = PID_TARGET - val;
if (error > PID_MAX_ERR)
error = PID_MAX_ERR;
else if (error < -PID_MAX_ERR)
error = -PID_MAX_ERR;
/* Compute P term */
p_term = error * g_pid.Pk;
/* Compute I term */
g_pid.err_sum += error;
i_term = g_pid.err_sum * g_pid.Ik;
/* Compute D term */
d_term = (g_pid.val_prev - val) * g_pid.Dk;
g_pid.val_prev = val;
/* Final value */
tot = (p_term + i_term + d_term) >> PID_SCALE_SHIFT;
if (tot > PID_MAX_DEV)
tot = PID_MAX_DEV;
else if (tot < -PID_MAX_DEV)
tot = -PID_MAX_DEV;
/* Update DAC */
set_vctcxo_dac( PID_MID_VAL + tot );
}
/* Driver */
/* ------ */
static int32_t g_val_lpf = PID_TARGET;
static void
_gpsdo_irq_handler(unsigned irq)
{
if (gpsdo_regs->csr & GPSDO_CSR_RDY)
{
/* Counter value */
int32_t val = gpsdo_regs->cnt;
#ifdef GPSDO_DEBUG
printf("GPSDO Count: %d\n", val);
#endif
/* Next request */
gpsdo_regs->csr = GPSDO_CSR_REQ;
/* TODO:: Save the current wall time to be able check
time passed since the last lock later. This is useful
e.g. to check whether we still have a GPS lock.*/
/* Check validity of value */
if (abs(val - PID_TARGET) < 100000)
{
/* LPF the value */
g_val_lpf = (g_val_lpf * 7 + val + 4) >> 3;
/* Update PID */
_gpsdo_pid_step(g_val_lpf);
}
}
}
void
gpsdo_init(void)
{
/* Set the DAC to mid value */
set_vctcxo_dac( PID_MID_VAL );
/* Register IRQ handler */
pic_register_handler(IRQ_GPSDO, _gpsdo_irq_handler);
/* Init PID */
_gpsdo_pid_init();
/* Start request */
gpsdo_regs->csr = GPSDO_CSR_REQ;
}

30
zpu/lib/gpsdo.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* Copyright 2012 Sylvain Munaut <tnt@246tNt.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_GPSDO_H
#define INCLUDED_GPSDO_H
void gpsdo_init(void);
/* Set value of the VCTCXO DAC */
int set_vctcxo_dac(uint16_t v);
/* Get the current VCTCXO DAC value */
uint16_t get_vctcxo_dac(void);
#endif /* INCLUDED_GPSDO_H */

274
zpu/lib/hal_io.c Normal file
View File

@@ -0,0 +1,274 @@
/* -*- c -*- */
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// conditionalized on HAL_IO_USES_DBOARD_PINS && HAL_IO_USES_UART
#include "memory_map.h"
#include "hal_uart.h"
#include "hal_io.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
/*
* ========================================================================
* leds
* ========================================================================
*/
static unsigned long leds_shadow = 0;
static unsigned long led_src_shadow = 0;
void
hal_set_leds(int value, int mask)
{
int ei = hal_disable_ints();
leds_shadow = (leds_shadow & ~mask) | (value & mask);
output_regs->leds = leds_shadow;
hal_restore_ints(ei);
}
// Allow hardware control over leds. 1 = hardware, 0 = software
void
hal_set_led_src(int value, int mask)
{
int ei = hal_disable_ints();
led_src_shadow = (led_src_shadow & ~mask) | (value & mask);
output_regs->led_src = led_src_shadow;
hal_restore_ints(ei);
}
void
hal_toggle_leds(int mask)
{
int ei = hal_disable_ints();
leds_shadow ^= mask;
output_regs->leds = leds_shadow;
hal_restore_ints(ei);
}
// ================================================================
// primitives
// ================================================================
#if defined(HAL_IO_USES_DBOARD_PINS)
//
// Does i/o using high 9-bits of rx daughterboard pins.
//
// 1 1 1 1 1 1
// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | char |W| |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//
// Asserts W when writing char
//
#define W 0x0080
void
hal_io_init(void)
{
// make high 9 bits of tx daughterboard outputs
hal_gpio_set_rx_mode(15, 7, GPIOM_OUTPUT);
// and set them to zero
hal_gpio_set_rx(0x0000, 0xff80);
}
void
hal_finish(void)
{
volatile unsigned long *p = (unsigned long *) 0xC2F0;
*p = 0;
}
// %c
inline int
putchar(int ch)
{
hal_gpio_set_rx((s << 8) | W, 0xff80);
hal_gpio_set_rx(0, 0xff80);
return ch;
}
#elif defined(HAL_IO_USES_UART)
void
hal_io_init(void)
{
hal_uart_init();
}
void
hal_finish(void)
{
}
// %c
inline int
fputchar(hal_uart_name_t u, int ch)
{
hal_uart_putc(u, ch);
return ch;
}
inline int
putchar(int ch)
{
hal_uart_putc(DEFAULT_UART, ch);
return ch;
}
int
fgetchar(hal_uart_name_t u)
{
return hal_uart_getc(u);
}
int
getchar(void)
{
return fgetchar(DEFAULT_UART);
}
#else // nop all i/o
void
hal_io_init(void)
{
}
void
hal_finish(void)
{
}
// %c
inline int
putchar(int ch)
{
return ch;
}
int
getchar(void)
{
return EOF;
}
#endif
// ================================================================
// (slightly) higher level functions
//
// These are here so we can inline the calls to putchar.
// The rest of the stuff was moved to nonstdio.c
// ================================================================
// \n
inline void
fnewline(hal_uart_name_t u)
{
fputchar(u, '\n');
}
inline void
newline(void)
{
fnewline(DEFAULT_UART);
}
int
fputstr(hal_uart_name_t u, const char *s)
{
while (*s)
fputchar(u, *s++);
return 0;
}
int
fnputstr(hal_uart_name_t u, const char *s, int len)
{
int x = 0;
while (*s && (len > x++))
fputchar(u, *s++);
return x;
}
int
putstr(const char *s)
{
return fputstr(DEFAULT_UART, s);
}
int
fputs(hal_uart_name_t u, const char *s)
{
fputstr(u, s);
fputchar(u, '\n');
return 0;
}
int puts(const char *s)
{
return fputs(DEFAULT_UART, s);
}
char *
fgets(hal_uart_name_t u, char * const s)
{
char *x = s;
while((*x=(char)hal_uart_getc(u)) != '\n') x++;
*x = 0;
return s;
}
int
fngets(hal_uart_name_t u, char * const s, int len)
{
char *x = s;
while(((*x=(char)hal_uart_getc(u)) != '\n') && ((x-s) < len)) x++;
*x = 0;
return (x-s);
}
int
fngets_noblock(hal_uart_name_t u, char * const s, int len)
{
int i;
for(i=0; i < len; i++) {
int ret = hal_uart_getc_noblock(u);
s[i] = (char) ret;
if((ret == -1) || (s[i] == '\n')) break;
}
s[i] = 0;
return i;
}
char *
gets(char * const s)
{
return fgets(DEFAULT_UART, s);
}

96
zpu/lib/hal_io.h Normal file
View File

@@ -0,0 +1,96 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_HAL_IO_H
#define INCLUDED_HAL_IO_H
#include "memory_map.h"
#include "hal_uart.h"
void hal_io_init(void);
void hal_finish();
char *gets(char * const s);
int fputstr(hal_uart_name_t u, const char *s);
int fnputstr(hal_uart_name_t u, const char *s, int len);
int fngets(hal_uart_name_t u, char * const s, int len);
int fngets_noblock(hal_uart_name_t u, char * const s, int len);
/*
* ------------------------------------------------------------------------
* control the leds
*
* Low 4-bits are the general purpose leds on the board
* The next bit is the led on the ethernet connector
* ------------------------------------------------------------------------
*/
void hal_set_leds(int value, int mask);
void hal_set_led_src(int value, int mask);
void hal_toggle_leds(int mask);
/*
* ------------------------------------------------------------------------
* simple timeouts
* ------------------------------------------------------------------------
*/
static inline void
hal_set_timeout(int delta_ticks)
{
sr_simple_timer->onetime = delta_ticks;
}
/*
* ------------------------------------------------------------------------
* interrupt enable/disable
* ------------------------------------------------------------------------
*/
/*!
* \brief Disable interrupts and return previous interrupt enable state.
* [Microblaze specific]
*/
static inline int
hal_disable_ints(void)
{
return 0; /* NOP */
}
/*!
* \brief Enable interrupts and return previous interrupt enable state.
* [Microblaze specific]
*/
static inline int
hal_enable_ints(void)
{
return 0; /* NOP */
}
/*!
* \brief Set interrupt enable state to \p prev_state.
* [Microblaze specific]
*/
static inline void
hal_restore_ints(int prev_state)
{
/* NOP */
}
#endif /* INCLUDED_HAL_IO_H */

137
zpu/lib/hal_uart.c Normal file
View File

@@ -0,0 +1,137 @@
/* -*- c -*- */
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "memory_map.h"
#include "hal_uart.h"
#include "hal_io.h"
#include "mdelay.h"
//just to save you from going insane, note that firmware/FPGA UARTs [0-2] correspond to serial ports [1-3].
//so in software, we refer to UART_DEBUG as UART0, but it transmits on pin TXD<1>. see the UART assignments in hal_uart.h.
#define NSPEEDS 6
#define MAX_WB_DIV 4
//if you're going to recalculate the divisors, it's just uart_clock_rate / baud_rate.
//uart_clock_rate is 50MHz for USRP2.
static const uint16_t
#ifndef UMTRX
divisor_table[NSPEEDS] = {
5208, // 9600
2604, // 19200
1302, // 38400
868, // 57600
434, // 115200
217 // 230400
};
#else
//uart_clock_rate is 52MHz for UmTRX.
divisor_table[NSPEEDS] = {
5417, // 9600
2708, // 19200
1354, // 38400
903, // 57600
451, // 115200
226 // 230400
};
#endif //UMTRX
static char uart_mode[4] = {
[UART_DEBUG] = UART_MODE_ONLCR,
[UART_EXP] = UART_MODE_ONLCR,
[UART_GPS] = UART_MODE_ONLCR
};
static char uart_speeds[4] = {
[UART_DEBUG] = US_230400,
[UART_EXP] = US_230400,
#ifdef UMTRX
[UART_GPS] = US_9600
#else
[UART_GPS] = US_115200
#endif // UMTRX
};
void
hal_uart_set_mode(hal_uart_name_t uart, int mode)
{
uart_mode[uart] = mode;
}
void hal_uart_set_speed(hal_uart_name_t uart, hal_uart_speed_t speed)
{
uart_regs[uart].clkdiv = divisor_table[speed];
}
void
hal_uart_init(void)
{
for(int i = 0; i < 3; i++) {
hal_uart_set_mode(i, uart_mode[i]);
hal_uart_set_speed(i, uart_speeds[i]);
}
}
void
hal_uart_putc(hal_uart_name_t u, int ch)
{
if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR)) //map \n->\r\n if necessary
hal_uart_putc(u, '\r');
while (uart_regs[u].txlevel == 0) // wait for fifo to have space
;
uart_regs[u].txchar = ch;
}
void
hal_uart_putc_nowait(hal_uart_name_t u, int ch)
{
if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR)) //map \n->\r\n if necessary
hal_uart_putc(u, '\r');
if(uart_regs[u].txlevel) // If fifo has space
uart_regs[u].txchar = ch;
}
int
hal_uart_getc(hal_uart_name_t u)
{
while ((uart_regs[u].rxlevel) == 0) // wait for data to be ready
;
return uart_regs[u].rxchar;
}
int
hal_uart_getc_noblock(hal_uart_name_t u)
{
// int timeout = 0;
// while (((uart_regs[u].rxlevel) == 0) && (timeout++ < HAL_UART_TIMEOUT_MS))
// mdelay(1);
if(uart_regs[u].rxlevel == 0) return -1;
return uart_regs[u].rxchar;
}
int hal_uart_rx_flush(hal_uart_name_t u)
{
char x = 0;
while(uart_regs[u].rxlevel) x = uart_regs[u].rxchar;
return x;
}

92
zpu/lib/hal_uart.h Normal file
View File

@@ -0,0 +1,92 @@
/* -*- c -*- */
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_HAL_UART_H
#define INCLUDED_HAL_UART_H
/*!
* \brief uart mode flags
*/
#define UART_MODE_RAW 0x0000 // no mapping on input or output
#define UART_MODE_ONLCR 0x0001 // map \n to \r\n on output (default)
#define DEFAULT_UART UART_DEBUG //which UART printf, gets, etc. use
typedef enum {
US_9600 = 0,
US_19200 = 1,
US_38400 = 2,
US_57600 = 3,
US_115200 = 4,
US_230400 = 5
} hal_uart_speed_t;
typedef struct {
hal_uart_speed_t speed;
} hal_uart_config_t;
typedef enum {
UART_DEBUG = 0,
UART_EXP = 1,
UART_GPS = 2
} hal_uart_name_t;
/*
* \brief Set uart mode
*/
void hal_uart_set_mode(hal_uart_name_t uart, int flags);
/*!
* \brief one-time call to init
*/
void hal_uart_init(void);
/*!
* \brief Set uart parameters
* Default is 115,200 bps, 8N1.
*/
void hal_uart_set_config(const hal_uart_config_t *c);
/*!
* \brief Get uart configuation.
*/
void hal_uart_get_config(hal_uart_config_t *c);
/*!
* \brief Enqueue \p ch for output over serial port
*/
void hal_uart_putc(hal_uart_name_t u, int ch);
/*!
* \brief Enqueue \p ch for output over serial port, silent fail if queue is full
*/
void hal_uart_putc_nowait(hal_uart_name_t u, int ch);
/*
* \brief Blocking read of next char from serial port
*/
int hal_uart_getc(hal_uart_name_t u);
/*
* \brief Non-blocking read of next char from serial port, return -1 if nothing available
*/
int hal_uart_getc_noblock(hal_uart_name_t u);
int hal_uart_rx_flush(hal_uart_name_t u);
#endif /* INCLUDED_HAL_UART_H */

129
zpu/lib/i2c.c Normal file
View File

@@ -0,0 +1,129 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "i2c.h"
#include "memory_map.h"
#include "stdint.h"
#include <string.h>
#include "nonstdio.h"
#define MAX_WB_DIV 4 // maximum wishbone divisor (from 100 MHz MASTER_CLK)
// prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally]
#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 400000)) - 1)
static uint16_t prescaler_values[MAX_WB_DIV+1] = {
0xffff, // 0: can't happen
PRESCALER(1), // 1: 100 MHz
PRESCALER(2), // 2: 50 MHz
PRESCALER(3), // 3: 33.333 MHz
PRESCALER(4), // 4: 25 MHz
};
void
i2c_init(void)
{
i2c_regs->ctrl = 0; // disable core
// setup prescaler depending on wishbone divisor
int wb_div = hwconfig_wishbone_divisor();
if (wb_div > MAX_WB_DIV)
wb_div = MAX_WB_DIV;
i2c_regs->prescaler_lo = prescaler_values[wb_div] & 0xff;
i2c_regs->prescaler_hi = (prescaler_values[wb_div] >> 8) & 0xff;
i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE; // enable core
//now this is done separately to maintain common code for async and sync
//pic_register_handler(IRQ_I2C, i2c_irq_handler);
}
static inline void
wait_for_xfer(void)
{
while (i2c_regs->cmd_status & I2C_ST_TIP) // wait for xfer to complete
;
}
static inline bool
wait_chk_ack(void)
{
wait_for_xfer();
if ((i2c_regs->cmd_status & I2C_ST_RXACK) != 0){ // target NAK'd
return false;
}
return true;
}
bool
i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len)
{
if (len == 0) // reading zero bytes always works
return true;
while (i2c_regs->cmd_status & I2C_ST_BUSY)
;
i2c_regs->data = (i2c_addr << 1) | 1; // 7 bit address and read bit (1)
// generate START and write addr
i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START;
if (!wait_chk_ack())
goto fail;
for (; len > 0; buf++, len--){
i2c_regs->cmd_status = I2C_CMD_RD | (len == 1 ? (I2C_CMD_NACK | I2C_CMD_STOP) : 0);
wait_for_xfer();
*buf = i2c_regs->data;
}
return true;
fail:
i2c_regs->cmd_status = I2C_CMD_STOP; // generate STOP
return false;
}
bool
i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len)
{
while (i2c_regs->cmd_status & I2C_ST_BUSY)
;
i2c_regs->data = (i2c_addr << 1) | 0; // 7 bit address and write bit (0)
// generate START and write addr (and maybe STOP)
i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0);
if (!wait_chk_ack())
goto fail;
for (; len > 0; buf++, len--){
i2c_regs->data = *buf;
i2c_regs->cmd_status = I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0);
if (!wait_chk_ack())
goto fail;
}
return true;
fail:
i2c_regs->cmd_status = I2C_CMD_STOP; // generate STOP
return false;
}

39
zpu/lib/i2c.h Normal file
View File

@@ -0,0 +1,39 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_I2C_H
#define INCLUDED_I2C_H
#include <stdbool.h>
#include "stdint.h"
void i2c_init(void);
bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len);
bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len);
bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len);
// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
// Which EEPROM is determined by i2c_addr. See i2c_addr.h
bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len);
bool find_safe_booted_flag(void);
void set_safe_booted_flag(bool flag);
#endif /* INCLUDED_I2C_H */

206
zpu/lib/i2c_async.c Normal file
View File

@@ -0,0 +1,206 @@
//
// Copyright 2010 Ettus Research LLC
//
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//i2c_async.c: asynchronous (interrupt-driven) routines for I2C.
//separated out here so we can have a small I2C lib for bootloader and
//retain interrupt-driven I2C for the main app.
#include "memory_map.h"
#include "stdint.h"
#include <string.h>
#include "pic.h"
#include "nonstdio.h"
#include "i2c_async.h"
//asynchronous (interrupt-driven) i2c state variables
volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer
volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position
volatile uint8_t i2c_len = 0; //length remaining in current transfer
volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state
i2c_dir_t i2c_dir; //I2C transfer direction
void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete
static void i2c_irq_handler(unsigned irq);
inline void i2c_async_err(void);
void i2c_register_handler(void) {
pic_register_handler(IRQ_I2C, i2c_irq_handler);
}
static void i2c_irq_handler(unsigned irq) {
//i2c state machine.
//printf("I2C irq handler\n");
//first let's make sure nothing is f'ed up
//TODO: uncomment this error checking when we have some way to handle errors
// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it
// printf("\tNACK received\n");
// i2c_async_err();
// return;
// }// else printf("\tACK received, proceeding\n");
if(i2c_regs->cmd_status & I2C_ST_AL) {
printf("\tArbitration lost!\n");
i2c_async_err();
return;
}
if(i2c_regs->cmd_status & I2C_ST_TIP) {
//printf("\tI2C still busy in interrupt\n");
return;
}
//now decide what to do
switch(i2c_state) {
case I2C_STATE_IDLE:
//this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad.
printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n");
i2c_async_err();
break;
case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet.
case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg
//if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len);
//else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len);
if(i2c_dir == I2C_DIR_READ) {
if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data;
//printf("\tRead %x\n", *(i2c_bufptr-1));
//set up another data byte
if(i2c_len > 1) //only one more byte to transfer
i2c_regs->cmd_status = I2C_CMD_RD;
else
i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP;
}
else if(i2c_dir == I2C_DIR_WRITE) {
//write a byte
//printf("\tWriting %x\n", *i2c_bufptr);
i2c_regs->data = *(i2c_bufptr++);
if(i2c_len > 1)
i2c_regs->cmd_status = I2C_CMD_WR;
else {
//printf("\tGenerating STOP\n");
i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP;
}
};
i2c_len--;
if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE;
else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition
break;
case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us.
//printf("\tI2C in state LAST BYTE\n");
if(i2c_dir == I2C_DIR_READ) {
*(i2c_bufptr++) = i2c_regs->data;
//printf("\tRead %x\n", *(i2c_bufptr-1));
i2c_state = I2C_STATE_DATA_READY;
} else {
i2c_state = I2C_STATE_IDLE;
}
i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time
if(i2c_callback) {
i2c_callback(); //if we registered a callback, call it!
}
break;
default: //terrible things have happened.
break;
}
}
void i2c_register_callback(void (*volatile callback)(void)) {
i2c_callback = callback;
}
inline void i2c_async_err(void) {
i2c_state = I2C_STATE_IDLE;
i2c_regs->ctrl &= ~I2C_CTRL_IE;
printf("I2C error\n");
//TODO: set an error flag instead of just dropping things on the floor
i2c_regs->cmd_status = I2C_CMD_STOP;
}
bool i2c_async_read(uint8_t addr, unsigned int len) {
//printf("Starting async read\n");
if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle
if(len == 0) return true; //just idiot-proofing
if(len > sizeof(i2c_buf)) return false;
//disable I2C interrupts and clear pending interrupts on the I2C device
i2c_regs->ctrl &= ~I2C_CTRL_IE;
i2c_regs->cmd_status |= I2C_CMD_IACK;
i2c_len = len;
i2c_dir = I2C_DIR_READ;
i2c_bufptr = i2c_buf;
//then set up the transfer by issuing the control byte
i2c_regs->ctrl |= I2C_CTRL_IE;
i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit
i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr
//update the state so the irq handler knows what's going on
i2c_state = I2C_STATE_CONTROL_BYTE_SENT;
return true;
}
bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) {
//printf("Starting async write\n");
if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle
if(len > sizeof(i2c_buf)) return false;
//disable I2C interrupts and clear pending interrupts on the I2C device
i2c_regs->ctrl &= ~I2C_CTRL_IE;
i2c_regs->cmd_status |= I2C_CMD_IACK;
//copy the buffer into our own if writing
memcpy((void *)i2c_buf, buf, len);
i2c_len = len;
i2c_dir = I2C_DIR_WRITE;
i2c_bufptr = i2c_buf;
//then set up the transfer by issuing the control byte
i2c_regs->ctrl |= I2C_CTRL_IE;
i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit
i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr
//update the state so the irq handler knows what's going on
i2c_state = I2C_STATE_CONTROL_BYTE_SENT;
return true;
}
//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request.
bool i2c_async_data_ready(void *buf) {
if(i2c_state == I2C_STATE_DATA_READY) {
i2c_state = I2C_STATE_IDLE;
memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this
//printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf);
return true;
}
return false;
}

50
zpu/lib/i2c_async.h Normal file
View File

@@ -0,0 +1,50 @@
//
// Copyright 2010 Ettus Research LLC
//
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_I2C_ASYNC_H
#define INCLUDED_I2C_ASYNC_H
#include <stdbool.h>
#include "stdint.h"
typedef enum { I2C_STATE_IDLE,
I2C_STATE_CONTROL_BYTE_SENT,
I2C_STATE_DATA,
I2C_STATE_LAST_BYTE,
I2C_STATE_DATA_READY,
I2C_STATE_ERROR
} i2c_state_t;
typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t;
bool i2c_async_read(uint8_t addr, unsigned int len);
bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len);
bool i2c_async_data_ready(void *);
//static void i2c_irq_handler(unsigned irq);
void i2c_register_callback(void (*callback)(void));
void i2c_register_handler(void);
// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
// Which EEPROM is determined by i2c_addr. See i2c_addr.h
bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void));
bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void));
#endif /* INCLUDED_I2C_ASYNC_H */

153
zpu/lib/if_arp.h Normal file
View File

@@ -0,0 +1,153 @@
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Global definitions for the ARP (RFC 826) protocol.
*
* Version: @(#)if_arp.h 1.0.1 04/16/93
*
* Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
* Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
* Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Florian La Roche,
* Jonathan Layes <layes@loran.com>
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _LINUX_IF_ARP_H
#define _LINUX_IF_ARP_H
/* ARP protocol HARDWARE identifiers. */
#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */
#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
#define ARPHRD_EETHER 2 /* Experimental Ethernet */
#define ARPHRD_AX25 3 /* AX.25 Level 2 */
#define ARPHRD_PRONET 4 /* PROnet token ring */
#define ARPHRD_CHAOS 5 /* Chaosnet */
#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
#define ARPHRD_ARCNET 7 /* ARCnet */
#define ARPHRD_APPLETLK 8 /* APPLEtalk */
#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
#define ARPHRD_ATM 19 /* ATM */
#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */
#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */
#define ARPHRD_EUI64 27 /* EUI-64 */
#define ARPHRD_INFINIBAND 32 /* InfiniBand */
/* Dummy types for non ARP hardware */
#define ARPHRD_SLIP 256
#define ARPHRD_CSLIP 257
#define ARPHRD_SLIP6 258
#define ARPHRD_CSLIP6 259
#define ARPHRD_RSRVD 260 /* Notional KISS type */
#define ARPHRD_ADAPT 264
#define ARPHRD_ROSE 270
#define ARPHRD_X25 271 /* CCITT X.25 */
#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */
#define ARPHRD_CAN 280 /* Controller Area Network */
#define ARPHRD_PPP 512
#define ARPHRD_CISCO 513 /* Cisco HDLC */
#define ARPHRD_HDLC ARPHRD_CISCO
#define ARPHRD_LAPB 516 /* LAPB */
#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */
#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
#define ARPHRD_SKIP 771 /* SKIP vif */
#define ARPHRD_LOOPBACK 772 /* Loopback device */
#define ARPHRD_LOCALTLK 773 /* Localtalk device */
#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */
#define ARPHRD_BIF 775 /* AP1000 BIF */
#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */
#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */
#define ARPHRD_IPGRE 778 /* GRE over IP */
#define ARPHRD_PIMREG 779 /* PIMSM register interface */
#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */
#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */
#define ARPHRD_ECONET 782 /* Acorn Econet */
#define ARPHRD_IRDA 783 /* Linux-IrDA */
/* ARP works differently on different FC media .. so */
#define ARPHRD_FCPP 784 /* Point to point fibrechannel */
#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */
#define ARPHRD_FCPL 786 /* Fibrechannel public loop */
#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */
/* 787->799 reserved for fibrechannel media types */
#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */
#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
/* ARP protocol opcodes. */
#define ARPOP_REQUEST 1 /* ARP request */
#define ARPOP_REPLY 2 /* ARP reply */
#define ARPOP_RREQUEST 3 /* RARP request */
#define ARPOP_RREPLY 4 /* RARP reply */
#define ARPOP_InREQUEST 8 /* InARP request */
#define ARPOP_InREPLY 9 /* InARP reply */
#define ARPOP_NAK 10 /* (ATM)ARP NAK */
/* ARP Flag values. */
#define ATF_COM 0x02 /* completed entry (ha valid) */
#define ATF_PERM 0x04 /* permanent entry */
#define ATF_PUBL 0x08 /* publish entry */
#define ATF_USETRAILERS 0x10 /* has requested trailers */
#define ATF_NETMASK 0x20 /* want to use a netmask (only
for proxy entries) */
#define ATF_DONTPUB 0x40 /* don't answer this addresses */
typedef unsigned short __be16;
/*
* This structure defines an ethernet arp header.
*/
struct arphdr
{
__be16 ar_hrd; /* format of hardware address */
__be16 ar_pro; /* format of protocol address */
unsigned char ar_hln; /* length of hardware address */
unsigned char ar_pln; /* length of protocol address */
__be16 ar_op; /* ARP opcode (command) */
#if 0
/*
* Ethernet looks like this : This bit is variable sized however...
*/
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
unsigned char ar_sip[4]; /* sender IP address */
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
unsigned char ar_tip[4]; /* target IP address */
#endif
};
/*
* This structure defines an ethernet arp header.
*/
struct arp_eth_ipv4
{
__be16 ar_hrd; /* format of hardware address */
__be16 ar_pro; /* format of protocol address */
unsigned char ar_hln; /* length of hardware address */
unsigned char ar_pln; /* length of protocol address */
__be16 ar_op; /* ARP opcode (command) */
unsigned char ar_sha[6]; /* sender hardware address */
unsigned char ar_sip[4]; /* sender IP address */
unsigned char ar_tha[6]; /* target hardware address */
unsigned char ar_tip[4]; /* target IP address */
};
#endif /* _LINUX_IF_ARP_H */

57
zpu/lib/ihex.c Normal file
View File

@@ -0,0 +1,57 @@
/* -*- c++ -*- */
/*
* Copyright 2010 Ettus Research LLC
*
*/
#include "ihex.h"
#include <ctype.h> //man that pulls in a lot of shit
//this is not safe and you should run isxdigit beforehand
uint8_t asc2nibble(char input) {
if(input > 'Z') return input - 'W';
else if(input > '9') return input - '7';
else return input - '0';
}
int ihex_parse(char input[], ihex_record_t *record) {
//given a NULL-TERMINATED input string (use gets()) in I16HEX format, write the binary record in record. return 0 on success.
uint8_t inputlen;
uint8_t t, i, checksum_calc=0, checksum_read;
//first check for ":" leading character
if(input[0] != ':') return -1;
//then check the string for only valid ASCII ['0'-'F']
inputlen=1;
while(input[inputlen]) {
if( !isxdigit(input[inputlen++]) ) return -2;
}
//then read the length.
record->length = (asc2nibble(input[1]) << 4) + asc2nibble(input[2]);
if(input[(record->length<<1) + 11] != 0) return -3; //if we're missing a null terminator in the right place
//then read the address.
record->addr = (asc2nibble(input[3]) << 12) + (asc2nibble(input[4]) << 8) + (asc2nibble(input[5]) << 4) + asc2nibble(input[6]);
//then read the record type.
record->type = (asc2nibble(input[7]) << 4) + asc2nibble(input[8]);
// if(record->type > 4) return -4;
//then read the data, which goes from input[9] to input[9+length*2].
for(i=0; i < record->length; i++) {
t = 9 + (i<<1);
record->data[i] = (asc2nibble(input[t]) << 4) + (asc2nibble(input[t + 1]));
checksum_calc += record->data[i]; //might as well keep a running checksum as we read
}
checksum_calc += record->length + record->type + (record->addr >> 8) + (record->addr & 0xFF); //get the rest of the data into that checksum
checksum_calc = ~checksum_calc + 1; //checksum is 2's complement
//now read the checksum of the record
checksum_read = (asc2nibble(input[9 + (record->length<<1)]) << 4) + asc2nibble(input[10 + (record->length<<1)]);
if(checksum_calc != checksum_read) return -5; //compare 'em
return 0;
}

18
zpu/lib/ihex.h Normal file
View File

@@ -0,0 +1,18 @@
/* -*- c++ -*- */
/*
* Copyright 2010 Ettus Research LLC
*
*/
#include <stdint.h>
#include <stddef.h>
typedef struct {
uint8_t type;
size_t length;
uint32_t addr;
uint8_t *data;
} ihex_record_t;
int ihex_parse(char input[], ihex_record_t *record);

31
zpu/lib/mdelay.c Normal file
View File

@@ -0,0 +1,31 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mdelay.h"
#include "memory_map.h"
void mdelay(int ms){
if (hwconfig_simulation_p()) return;
for(int i = 0; i < ms; i++){
static const uint32_t num_ticks = TIME64_CLK_RATE/1000;
const uint32_t ticks_begin = router_status->time64_ticks_rb;
while((router_status->time64_ticks_rb - ticks_begin) < num_ticks){
/*NOP*/
}
}
}

29
zpu/lib/mdelay.h Normal file
View File

@@ -0,0 +1,29 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_MDELAY_H
#define INCLUDED_MDELAY_H
/*!
* \brief Delay about ms milliseconds
*
* If simulating, _very_ short delay
*/
void mdelay(int ms);
#endif /* INCLUDED_MDELAY_H */

42
zpu/lib/memcpy_wa.c Normal file
View File

@@ -0,0 +1,42 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "memcpy_wa.h"
#include <stdint.h>
#include <stdlib.h>
/*
* For copying to/from non-byte-adressable memory, such as
* the buffers. dst, src, and nbytes must all satisfy (x % 4 == 0)
*/
void
memcpy_wa(void *dst, const void *src, size_t nbytes)
{
if (((intptr_t) dst & 0x3)
|| ((intptr_t) src & 0x3)
|| (nbytes & 0x3))
exit(1); /* die! */
int *dp = (int *) dst;
int *sp = (int *) src;
unsigned nw = nbytes/4;
unsigned i;
for (i = 0; i < nw; i++)
dp[i] = sp[i];
}

32
zpu/lib/memcpy_wa.h Normal file
View File

@@ -0,0 +1,32 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_MEMCPY_WA_H
#define INCLUDED_MEMCPY_WA_H
#include <stddef.h>
/*
* For copying to/from non-byte-adressable memory, such as
* the buffers. dst, src, and nbytes must all satisfy (x % 4 == 0)
*/
void memcpy_wa(void *dst, const void *src, size_t nbytes);
#endif /* INCLUDED_MEMCPY_WA_H */

521
zpu/lib/memory_map.h Normal file
View File

@@ -0,0 +1,521 @@
// Copyright 2010-2011 Ettus Research LLC
/*
* Copyright 2007,2008,2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_MEMORY_MAP_H
#define INCLUDED_MEMORY_MAP_H
#include <stdint.h>
#ifdef UMTRX
// The master clock rate in FPGA
# define MASTER_CLK_RATE 104000000 // UmTRX: 104 MHz
// The TIME64 / VITA TIMER clock rate in FPGA
# define TIME64_CLK_RATE 13000000 // UmTRX: 13 MHz
#else
// The master clock rate in FPGA
# define MASTER_CLK_RATE 100000000 // USRP2(p): 100 MHz
// The TIME64 / VITA TIMER clock rate in FPGA
# define TIME64_CLK_RATE 100000000 // USRP2(p): 100 MHz
#endif
////////////////////////////////////////////////////////////////////////
// Define slave bases
////////////////////////////////////////////////////////////////////////
#define ROUTER_RAM_BASE 0x4000
#define SPI_BASE 0x5000
#define I2C_BASE 0x5400
#define GPSDO_BASE 0x5800
#define READBACK_BASE 0x5C00
#define ETH_BASE 0x6000
#define SETTING_REGS_BASE 0x7000
#define PIC_BASE 0x8000
#define I2C_AUX_BASE 0x8400
#define UART_BASE 0x8800
#define ATR_BASE 0x8C00
#ifdef USRP2
#define SDSPI_BASE 0xB000
#endif
#ifdef USRP2P
#define ICAP_BASE 0xA000
#define SPIF_BASE 0xB000
#define RAM_BASE 0xC000
#endif
/////////////////////////////////////////////////////
// SPI Core, Slave 2. See core docs for more info
/////////////////////////////////////////////////////
typedef struct {
volatile uint32_t txrx0;
volatile uint32_t txrx1;
volatile uint32_t txrx2;
volatile uint32_t txrx3;
volatile uint32_t ctrl;
volatile uint32_t div;
volatile uint32_t ss;
} spi_regs_t;
#define spi_regs ((spi_regs_t *) SPI_BASE)
// Masks for controlling different peripherals
#define SPI_SS_AD9510 1
#define SPI_SS_AD9777 2
#define SPI_SS_RX_DAC 4
#define SPI_SS_RX_ADC 8
#define SPI_SS_RX_DB 16
#define SPI_SS_TX_DAC 32
#define SPI_SS_TX_ADC 64
#define SPI_SS_TX_DB 128
#define SPI_SS_ADS62P44 256
////////////////////////////////////////////////
// Masks for controlling different peripherals in UmTRX
#define SPI_SS_LMS1 1
#define SPI_SS_LMS2 2
#define SPI_SS_DAC 4
#define SPI_SS_AUX1 8
#define SPI_SS_AUX2 16
#define LMS_RD_CMD(addr) ((uint16_t)(addr)<<8)
#define LMS_WR_CMD(addr, val) ( 0x8000 | ((uint16_t)(addr)<<8) | (val) )
// Masks for different parts of CTRL reg
#define SPI_CTRL_ASS (1<<13)
#define SPI_CTRL_IE (1<<12)
#define SPI_CTRL_LSB (1<<11)
#define SPI_CTRL_TXNEG (1<<10)
#define SPI_CTRL_RXNEG (1<< 9)
#define SPI_CTRL_GO_BSY (1<< 8)
#define SPI_CTRL_CHAR_LEN_MASK 0x7F
////////////////////////////////////////////////
// I2C, Slave 3
////////////////////////////////////////////////
typedef struct {
volatile uint32_t prescaler_lo; // r/w
volatile uint32_t prescaler_hi; // r/w
volatile uint32_t ctrl; // r/w
volatile uint32_t data; // wr = transmit reg; rd = receive reg
volatile uint32_t cmd_status; // wr = command reg; rd = status reg
} i2c_regs_t;
#define i2c_regs ((i2c_regs_t *) I2C_BASE)
#define i2c_aux_regs ((i2c_aux_regs_t *) I2C_AUX_BASE)
#define I2C_CTRL_EN (1 << 7) // core enable
#define I2C_CTRL_IE (1 << 6) // interrupt enable
//
// STA, STO, RD, WR, and IACK bits are cleared automatically
//
#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
#define I2C_CMD_STOP (1 << 6) // generate stop condition
#define I2C_CMD_RD (1 << 5) // read from slave
#define I2C_CMD_WR (1 << 4) // write to slave
#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
#define I2C_CMD_RSVD_2 (1 << 2) // reserved
#define I2C_CMD_RSVD_1 (1 << 1) // reserved
#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
#define I2C_ST_RSVD_4 (1 << 4) // reserved
#define I2C_ST_RSVD_3 (1 << 3) // reserved
#define I2C_ST_RSVD_2 (1 << 2) // reserved
#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
#define I2C_ST_IP (1 << 0) // Interrupt pending
///////////////////////////////////////////////////
// GPSDO, Slave 4
///////////////////////////////////////////////////
typedef struct {
volatile uint32_t csr;
volatile uint32_t cnt;
} gpsdo_regs_t;
#define gpsdo_regs ((gpsdo_regs_t *) GPSDO_BASE)
#define GPSDO_CSR_REQ (1 << 0) // Snap request
#define GPSDO_CSR_RDY (1 << 1) // Ready
#define GPSDO_CSR_PPS_POL (1 << 31) // PPS polarity
///////////////////////////////////////////////////
// Packet Router Status, Slave 5
///////////////////////////////////////////////////
typedef struct {
volatile uint32_t _padding[8];
volatile uint32_t status;
volatile uint32_t _unused;
volatile uint32_t time64_secs_rb;
volatile uint32_t time64_ticks_rb;
volatile uint32_t compat_num;
volatile uint32_t irqs;
} router_status_t;
#define router_status ((router_status_t *) READBACK_BASE)
/*!
* \brief return non-zero if we're running under the simulator
*/
inline static int
hwconfig_simulation_p(void)
{
return 0;
}
/*!
* \brief Return Wishbone Clock divisor.
* The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor.
*/
inline static int
hwconfig_wishbone_divisor(void)
{
return 2;
}
///////////////////////////////////////////////////
// Ethernet Core, Slave 6
///////////////////////////////////////////////////
typedef struct {
volatile int settings;
volatile int ucast_hi;
volatile int ucast_lo;
volatile int mcast_hi;
volatile int mcast_lo;
volatile int miimoder;
volatile int miiaddress;
volatile int miitx_data;
volatile int miicommand;
volatile int miistatus;
volatile int miirx_data;
volatile int pause_time;
volatile int pause_thresh;
} eth_mac_regs_t;
// settings register
#define MAC_SET_PAUSE_EN (1 << 0) // Makes us respect received pause frames (normally on)
#define MAC_SET_PASS_ALL (1 << 1) // Enables promiscuous mode, currently broken
#define MAC_SET_PASS_PAUSE (1 << 2) // Sends pause frames through (normally off)
#define MAC_SET_PASS_BCAST (1 << 3) // Sends broadcast frames through (normally on)
#define MAC_SET_PASS_MCAST (1 << 4) // Sends multicast frames that match mcast addr (normally off)
#define MAC_SET_PASS_UCAST (1 << 5) // Sends unicast (normal) frames through if they hit in address filter (normally on)
#define MAC_SET_PAUSE_SEND_EN (1 << 6) // Enables sending pause frames
// miicommand register
#define MIIC_SCANSSTAT (1 << 0) // Scan status
#define MIIC_RSTAT (1 << 1) // Read status
#define MIIC_WCTRLDATA (1 << 2) // Write control data
// miistatus register
#define MIIS_LINKFAIL (1 << 0) // The link failed
#define MIIS_BUSY (1 << 1) // The MII is busy (operation in progress)
#define MIIS_NVALID (1 << 2) // The data in the status register is invalid
// This it is only valid when the scan status is active.
#define eth_mac ((eth_mac_regs_t *) ETH_BASE)
////////////////////////////////////////////////////
// Settings Bus, Slave #7, Not Byte Addressable!
//
// Output-only from processor point-of-view.
// 1KB of address space (== 256 32-bit write-only regs)
////////////////////////////////////////////////////
#define SR_MISC 0 // 7 regs
#define SR_SIMTIMER 8 // 2
#define SR_TIME64 10 // 6
#define SR_BUF_POOL 16 // 4
#ifndef UMTRX
#define SR_RX_FRONT 24 // 5
#else
#define SR_RX_FRONT 20 // 5
#define SR_RX_FRONT1 25 // 5
#endif
#define SR_RX_CTRL0 32 // 9
#define SR_RX_DSP0 48 // 7
#define SR_RX_CTRL1 80 // 9
#define SR_RX_DSP1 96 // 7
#ifndef UMTRX
#define SR_TX_FRONT 128 // ?
#define SR_TX_CTRL 144 // 6
#define SR_TX_DSP 160 // 5
#else
#define SR_TX_FRONT0 110 // ?
#define SR_TX_CTRL0 126 // 6
#define SR_TX_DSP0 135 // 5
#define SR_TX_FRONT1 145 // ?
#define SR_TX_CTRL1 161 // 6
#define SR_TX_DSP1 170 // 5
#endif
#define SR_UDP_SM 192 // 64
#define _SR_ADDR(sr) (SETTING_REGS_BASE + (sr) * sizeof(uint32_t))
#define SR_ADDR_BLDRDONE _SR_ADDR(5)
// --- packet router control regs ---
typedef struct {
volatile uint32_t mode_ctrl;
volatile uint32_t ip_addr;
volatile uint32_t data_ports; //dsp0 (low 16) dsp1 (high 16)
volatile uint32_t iface_ctrl;
} router_ctrl_t;
#define router_ctrl ((router_ctrl_t *) _SR_ADDR(SR_BUF_POOL))
// --- misc outputs ---
typedef struct {
volatile uint32_t clk_ctrl;
volatile uint32_t serdes_ctrl;
volatile uint32_t adc_ctrl;
volatile uint32_t leds;
volatile uint32_t phy_ctrl; // LSB is reset line to eth phy
volatile uint32_t debug_mux_ctrl;
volatile uint32_t led_src; // HW or SW control for LEDs
volatile uint32_t flush_icache; // Flush the icache
} output_regs_t;
#define LMS1_RESET (1<<5)
#define LMS2_RESET (1<<6)
#define CLK_RESET (1<<4)
#define CLK_ENABLE (1<<3) | (1<<2)
#define CLK_SEL (1<<1) | (1<<0)
#define SERDES_ENABLE 8
#define SERDES_PRBSEN 4
#define SERDES_LOOPEN 2
#define SERDES_RXEN 1
#define ADC_CTRL_ON 0x0F
#define ADC_CTRL_OFF 0x00
// crazy order that matches the labels on the case
#define LED_A (1 << 4)
#define LED_B (1 << 1)
#define LED_E (1 << 2)
#define LED_D (1 << 0)
#define LED_C (1 << 3)
// LED_F // controlled by CPLD
// Note: the following LEDs are mutually exclusive, only one can lit.
#define LED_RJ45_ORANGE (1 << 5) // 1000Mbit connection LED (orange)
#define LED_RJ45_GREEN (1 << 6) // 100Mbit connection LED (green)
#define output_regs ((output_regs_t *) SETTING_REGS_BASE)
// --- protocol framer regs ---
typedef struct{
struct{
volatile uint32_t entry[16];
} table[4];
} sr_proto_framer_t;
#define sr_proto_framer_regs ((sr_proto_framer_t *) _SR_ADDR(SR_UDP_SM))
// --- VITA TX CTRL regs ---
typedef struct {
volatile uint32_t num_chan;
volatile uint32_t clear_state; // clears out state machine, fifos,
volatile uint32_t report_sid;
volatile uint32_t policy;
volatile uint32_t cyc_per_up;
volatile uint32_t packets_per_up;
} sr_tx_ctrl_t;
#define sr_tx_ctrl0 ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL0))
#define sr_tx_ctrl1 ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL1))
// --- VITA RX CTRL regs ---
typedef struct {
// The following 3 are logically a single command register.
// They are clocked into the underlying fifo when time_ticks is written.
volatile uint32_t cmd; // {now, chain, num_samples(30)
volatile uint32_t time_secs;
volatile uint32_t time_ticks;
} sr_rx_ctrl_t;
#define sr_rx_ctrl0 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL0))
#define sr_rx_ctrl1 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL1))
// ----------------------------------------------------------------
// VITA49 64 bit time (write only)
/*!
* \brief Time 64 flags
*
* <pre>
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------------------------------------------------------+-+-+
* | |S|P|
* +-----------------------------------------------------------+-+-+
*
* P - PPS edge selection (0=negedge, 1=posedge, default=0)
* S - Source (0=sma, 1=mimo, 0=default)
*
* </pre>
*/
typedef struct {
volatile uint32_t secs; // value to set absolute secs to on next PPS
volatile uint32_t ticks; // value to set absolute ticks to on next PPS
volatile uint32_t flags; // flags - see chart above
volatile uint32_t imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0)
} sr_time64_t;
#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64))
///////////////////////////////////////////////////////
// Simple Programmable Interrupt Controller, Slave 8
///////////////////////////////////////////////////////
// Interrupt request lines
// Bit numbers (LSB == 0) that correpond to interrupts into PIC
#define IRQ_BUFFER 0 // buffer manager
#define IRQ_GPSDO 1
#define IRQ_SPI 2
#define IRQ_I2C 3
#define IRQ_PHY 4 // ethernet PHY
#define IRQ_I2C_AUX 5
#define IRQ_UNDERRUN 5
#define IRQ_OVERRUN 6
#define IRQ_PPS 7 // pulse per second
#define IRQ_UART_RX 8
#define IRQ_UART_TX 9
#define IRQ_SERDES 10
#define IRQ_CLKSTATUS 11
#define IRQ_PERIODIC 12
#define IRQ_BUTTON 13
#define IRQ_LOCK_DETECT1 14
#define IRQ_LOCK_DETECT2 15
#define IRQ_TO_MASK(x) (1 << (x))
#define PIC_BUFFER_INT IRQ_TO_MASK(IRQ_BUFFER)
#define PIC_GPSDO_INT IRQ_TO_MASK(IRQ_GPSDO)
#define PIC_SPI_INT IRQ_TO_MASK(IRQ_SPI)
#define PIC_I2C_INT IRQ_TO_MASK(IRQ_I2C)
#define PIC_PHY_INT IRQ_TO_MASK(IRQ_PHY)
#define PIC_I2C_AUX_INT IRQ_TO_MASK(IRQ_I2C_AUX)
#define PIC_UNDERRUN_INT IRQ_TO_MASK(IRQ_UNDERRUN)
#define PIC_OVERRUN_INT IRQ_TO_MASK(IRQ_OVERRUN)
#define PIC_PPS_INT IRQ_TO_MASK(IRQ_PPS)
#define PIC_UART_RX_INT IRQ_TO_MASK(IRQ_UART_RX)
#define PIC_UART_TX_INT IRQ_TO_MASK(IRQ_UART_TX)
#define PIC_SERDES IRQ_TO_MASK(IRQ_SERDES)
#define PIC_CLKSTATUS IRQ_TO_MASK(IRQ_CLKSTATUS)
#define PIC_BUTTON IRQ_TO_MASK(IRQ_BUTTON)
#define PIC_LOCK_DETECT1 IRQ_TO_MASK(IRQ_LOCK_DETECT1)
#define PIC_LOCK_DETECT2 IRQ_TO_MASK(IRQ_LOCK_DETECT2)
typedef struct {
volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level
volatile uint32_t polarity; // mask: 1 -> rising edge
volatile uint32_t mask; // mask: 1 -> disabled
volatile uint32_t pending; // mask: 1 -> pending; write 1's to clear pending ints
} pic_regs_t;
#define pic_regs ((pic_regs_t *) PIC_BASE)
// ----------------------------------------------------------------
// WB_CLK_RATE is the time base for this
typedef struct {
volatile uint32_t onetime; // Number of wb clk cycles till the onetime interrupt
volatile uint32_t periodic; // Repeat rate of periodic interrupt
} sr_simple_timer_t;
#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER))
///////////////////////////////////////////////////
// UART, Slave 10
///////////////////////////////////////////////////
typedef struct {
// All elements are 8 bits except for clkdiv (16), but we use uint32 to make
// the hardware for decoding easier
volatile uint32_t clkdiv; // Set to 50e6 divided by baud rate (no x16 factor)
volatile uint32_t txlevel; // Number of spaces in the FIFO for writes
volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads
volatile uint32_t txchar; // Write characters to be sent here
volatile uint32_t rxchar; // Read received characters here
volatile uint32_t padding[3]; //what is this i don't even
} uart_regs_t;
#define uart_regs ((uart_regs_t *) UART_BASE)
///////////////////////////////////////////////////
// SD Card SPI interface, Slave 13
// All regs are 8 bits wide, but are accessed as if they are 32 bits
///////////////////////////////////////////////////
#ifdef USRP2
typedef struct {
volatile uint32_t status; // Write a 1 or 0 for controlling CS
volatile uint32_t clkdiv;
volatile uint32_t send_dat;
volatile uint32_t receive_dat;
} sdspi_regs_t;
#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE)
#endif //USRP2
///////////////////////////////////////////////////
// ICAP, Slave 13
///////////////////////////////////////////////////
#ifdef USRP2P
typedef struct {
uint32_t icap; //only the lower 8 bits matter
} icap_regs_t;
#define icap_regs ((icap_regs_t *) ICAP_BASE)
///////////////////////////////////////////////////
// SPI Flash interface, Slave 14
// Control register definitions are the same as SPI, so use SPI_CTRL_ASS, etc.
// Peripheral mask not needed since bus is dedicated (CE held low)
///////////////////////////////////////////////////
typedef struct {
volatile uint32_t txrx0;
volatile uint32_t txrx1;
volatile uint32_t txrx2;
volatile uint32_t txrx3;
volatile uint32_t ctrl;
volatile uint32_t div;
volatile uint32_t ss;
} spif_regs_t;
#define spif_regs ((spif_regs_t *) SPIF_BASE)
#endif //USRP2P
#endif /* INCLUDED_MEMORY_MAP_H */

45
zpu/lib/memset_wa.c Normal file
View File

@@ -0,0 +1,45 @@
/* -*- c++ -*- */
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "memset_wa.h"
#include <stdint.h>
#include <stdlib.h>
/*
* For setting non-byte-adressable memory, such as
* the buffers. dst and nbytes must all satisfy (x % 4 == 0)
*/
void *
memset_wa(void *dst, int c, size_t nbytes)
{
if (((intptr_t) dst & 0x3)
|| (nbytes & 0x3))
exit(1); /* die! */
int *dp = (int *) dst;
c &= 0xff;
int v = (c << 24) | (c << 16) | (c << 8) | c;
unsigned nw = nbytes/4;
unsigned i;
for (i = 0; i < nw; i++)
dp[i] = v;
return dst;
}

27
zpu/lib/memset_wa.h Normal file
View File

@@ -0,0 +1,27 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_MEMSET_WA_H
#define INCLUDED_MEMSET_WA_H
#include <stdlib.h>
void *memset_wa(void *s, int c, size_t n);
#endif /* INCLUDED_MEMSET_WA_H */

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ETH_MAC_ADDR_H
#define INCLUDED_ETH_MAC_ADDR_H
#include <stdint.h>
// Ethernet MAC address
typedef struct {
uint8_t addr[6];
} eth_mac_addr_t;
#endif /* INCLUDED_ETH_MAC_ADDR_H */

View File

@@ -0,0 +1,37 @@
/* -*- c++ -*- */
/*
* Copyright 2009,2010 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_PADDED_ETH_HDR_H
#define INCLUDED_PADDED_ETH_HDR_H
#include <compiler.h>
#include <net/eth_mac_addr.h>
/*!
* \brief Standard 14-byte ethernet header plus two leading bytes of padding.
*
* This is what a buffer contains in line 1 when using the "slow mode"
*/
typedef struct {
uint16_t pad;
eth_mac_addr_t dst;
eth_mac_addr_t src;
uint16_t ethertype;
} _AL4 padded_eth_hdr_t;
#endif /* INCLUDED_PADDED_ETH_HDR_H */

View File

@@ -0,0 +1,41 @@
/* -*- c -*- */
/*
* Copyright 2010 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SOCKET_ADDRESS_H
#define INCLUDED_SOCKET_ADDRESS_H
#include <lwip/ip_addr.h>
// port and address are in network byte order
typedef struct socket_address {
unsigned short port;
struct ip_addr addr;
} socket_address_t;
static inline struct socket_address
make_socket_address(struct ip_addr addr, int port)
{
struct socket_address r;
r.port = port;
r.addr = addr;
return r;
}
#endif /* INCLUDED_SOCKET_ADDRESS_H */

479
zpu/lib/net_common.c Normal file
View File

@@ -0,0 +1,479 @@
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "net_common.h"
#include "banal.h"
#include <hal_io.h>
#include <memory_map.h>
#include <memcpy_wa.h>
#include <ethernet.h>
#include <net/padded_eth_hdr.h>
#include <lwip/ip.h>
#include <lwip/udp.h>
#include <lwip/icmp.h>
#include <stdlib.h>
#include <nonstdio.h>
#include "arp_cache.h"
#include "if_arp.h"
#include <ethertype.h>
#include <string.h>
#include "pkt_ctrl.h"
/***********************************************************************
* Constants + Globals
**********************************************************************/
static const bool debug = false;
static const size_t out_buff_size = 2048;
static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
#define MAX_UDP_LISTENERS 10
/***********************************************************************
* 16-bit one's complement sum
**********************************************************************/
static uint32_t chksum_buffer(
uint16_t *buf, size_t nshorts,
uint32_t initial_chksum
){
uint32_t chksum = initial_chksum;
for (size_t i = 0; i < nshorts; i++) chksum += buf[i];
while (chksum >> 16) chksum = (chksum & 0xffff) + (chksum >> 16);
return chksum;
}
/***********************************************************************
* Listener registry
**********************************************************************/
static eth_mac_addr_t _local_mac_addr;
static struct ip_addr _local_ip_addr;
void register_addrs(const eth_mac_addr_t *mac_addr, const struct ip_addr *ip_addr){
_local_mac_addr = *mac_addr;
_local_ip_addr = *ip_addr;
}
struct listener_entry {
unsigned short port;
udp_receiver_t rcvr;
};
static struct listener_entry listeners[MAX_UDP_LISTENERS];
void init_udp_listeners(void){
for (int i = 0; i < MAX_UDP_LISTENERS; i++){
listeners[i].rcvr = NULL;
}
}
static struct listener_entry *
find_listener_by_port(unsigned short port)
{
for (int i = 0; i < MAX_UDP_LISTENERS; i++){
if (port == listeners[i].port)
return &listeners[i];
}
return 0;
}
static struct listener_entry *
find_free_listener(void)
{
for (int i = 0; i < MAX_UDP_LISTENERS; i++){
if (listeners[i].rcvr == NULL)
return &listeners[i];
}
abort();
}
void
register_udp_listener(int port, udp_receiver_t rcvr)
{
struct listener_entry *lx = find_listener_by_port(port);
if (lx)
lx->rcvr = rcvr;
else {
lx = find_free_listener();
lx->port = port;
lx->rcvr = rcvr;
}
}
/***********************************************************************
* Protocol framer
**********************************************************************/
void setup_framer(
eth_mac_addr_t eth_dst,
eth_mac_addr_t eth_src,
struct socket_address sock_dst,
struct socket_address sock_src,
size_t which
){
struct {
padded_eth_hdr_t eth;
struct ip_hdr ip;
struct udp_hdr udp;
} frame;
//-- load Ethernet header --//
frame.eth.dst = eth_dst;
frame.eth.src = eth_src;
frame.eth.ethertype = ETHERTYPE_IPV4;
//-- load IPv4 header --//
IPH_VHLTOS_SET(&frame.ip, 4, 5, 0);
IPH_LEN_SET(&frame.ip, 0);
IPH_ID_SET(&frame.ip, 0);
IPH_OFFSET_SET(&frame.ip, IP_DF); // don't fragment
IPH_TTL_SET(&frame.ip, 32);
IPH_PROTO_SET(&frame.ip, IP_PROTO_UDP);
IPH_CHKSUM_SET(&frame.ip, 0);
frame.ip.src = sock_src.addr;
frame.ip.dest = sock_dst.addr;
IPH_CHKSUM_SET(&frame.ip, chksum_buffer(
(unsigned short *) &frame.ip,
sizeof(frame.ip)/sizeof(short), 0
));
//-- load UDP header --//
frame.udp.src = sock_src.port;
frame.udp.dest = sock_dst.port;
frame.udp.len = 0;
frame.udp.chksum = 0;
//copy into the framer table registers
memcpy_wa((void *)(sr_proto_framer_regs->table[which].entry + 1), &frame, sizeof(frame));
}
/***********************************************************************
* Slow-path packet framing and transmission
**********************************************************************/
/*!
* low level routine to assembly an ethernet frame and send it.
*
* \param dst destination mac address
* \param ethertype ethertype field
* \param buf0 first part of data
* \param len0 length of first part of data
* \param buf1 second part of data
* \param len1 length of second part of data
* \param buf2 third part of data
* \param len2 length of third part of data
*/
static void
send_pkt(
eth_mac_addr_t dst, int ethertype,
const void *buf0, size_t len0,
const void *buf1, size_t len1,
const void *buf2, size_t len2
){
//control word for framed data
uint32_t ctrl_word = 0x0;
//assemble the ethernet header
padded_eth_hdr_t ehdr;
ehdr.pad = 0;
ehdr.dst = dst;
ehdr.src = _local_mac_addr;
ehdr.ethertype = ethertype;
//grab an out buffer and pointer
uint8_t *buff = (uint8_t *)pkt_ctrl_claim_outgoing_buffer();
uint8_t *p = buff;
size_t total_len = 0;
//create a list of all buffers to copy
const void *buffs[] = {&ctrl_word, &ehdr, buf0, buf1, buf2};
size_t lens[] = {sizeof(ctrl_word), sizeof(ehdr), len0, len1, (len2 + 3) & ~3};
//copy each buffer into the out buffer
for (size_t i = 0; i < sizeof(buffs)/sizeof(buffs[0]); i++){
total_len += lens[i]; //use full length (not clipped)
size_t bytes_remaining = out_buff_size - (size_t)(p - buff);
if (lens[i] > bytes_remaining) lens[i] = bytes_remaining;
if (lens[i] && ((lens[i] & 0x3) || (intptr_t) buffs[i] & 0x3))
printf("send_pkt: bad alignment of len and/or buf\n");
memcpy_wa(p, buffs[i], lens[i]);
p += lens[i];
}
//ensure that minimum length requirements are met
if (total_len < 64) total_len = 64; //60 + ctrl word
pkt_ctrl_commit_outgoing_buffer(total_len/sizeof(uint32_t));
if (debug) printf("sent %d bytes\n", (int)total_len);
}
void
send_ip_pkt(struct ip_addr dst, int protocol,
const void *buf0, size_t len0,
const void *buf1, size_t len1)
{
struct ip_hdr ip;
IPH_VHLTOS_SET(&ip, 4, 5, 0);
IPH_LEN_SET(&ip, IP_HLEN + len0 + len1);
IPH_ID_SET(&ip, 0);
IPH_OFFSET_SET(&ip, IP_DF); /* don't fragment */
IPH_TTL_SET(&ip, 32);
IPH_PROTO_SET(&ip, protocol);
IPH_CHKSUM_SET(&ip, 0);
ip.src = _local_ip_addr;
ip.dest = dst;
IPH_CHKSUM_SET(&ip, ~chksum_buffer(
(unsigned short *) &ip, sizeof(ip)/sizeof(short), 0
));
eth_mac_addr_t dst_mac;
bool found = arp_cache_lookup_mac(&ip.dest, &dst_mac);
if (!found){
printf("net_common: failed to hit cache looking for ");
print_ip_addr(&ip.dest);
newline();
return;
}
send_pkt(dst_mac, ETHERTYPE_IPV4,
&ip, sizeof(ip), buf0, len0, buf1, len1);
}
void
send_udp_pkt(int src_port, struct socket_address dst,
const void *buf, size_t len)
{
struct udp_hdr udp _AL4;
udp.src = src_port;
udp.dest = dst.port;
udp.len = UDP_HLEN + len;
udp.chksum = 0;
send_ip_pkt(dst.addr, IP_PROTO_UDP,
&udp, sizeof(udp), buf, len);
}
static void
handle_udp_packet(struct ip_addr src_ip, struct ip_addr dst_ip,
struct udp_hdr *udp, size_t len)
{
if (len != udp->len){
printf("UDP inconsistent lengths: %d %d\n", (int)len, udp->len);
return;
}
unsigned char *payload = ((unsigned char *) udp) + UDP_HLEN;
int payload_len = len - UDP_HLEN;
if (0){
printf("\nUDP: src = %d dst = %d len = %d\n",
udp->src, udp->dest, udp->len);
//print_bytes(0, payload, payload_len);
}
struct listener_entry *lx = find_listener_by_port(udp->dest);
if (lx){
struct socket_address src = make_socket_address(src_ip, udp->src);
struct socket_address dst = make_socket_address(dst_ip, udp->dest);
lx->rcvr(src, dst, payload, payload_len);
}
}
static void
handle_icmp_packet(struct ip_addr src, struct ip_addr dst,
struct icmp_echo_hdr *icmp, size_t len)
{
switch (icmp->type){
case ICMP_DUR: // Destinatino Unreachable
if (icmp->code == ICMP_DUR_PORT){ // port unreachable
//handle destination port unreachable (the host ctrl+c'd the app):
//filter out non udp data response
struct ip_hdr *ip = (struct ip_hdr *)(((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr));
struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN);
if (IPH_PROTO(ip) != IP_PROTO_UDP) break;
struct listener_entry *lx = find_listener_by_port(udp->src);
if (lx){
struct socket_address src = make_socket_address(ip->src, udp->src);
struct socket_address dst = make_socket_address(ip->dest, udp->dest);
lx->rcvr(src, dst, NULL, 0);
}
putchar('i');
}
else {
//printf("icmp dst unr (code: %d)", icmp->code);
putchar('i');
}
break;
case ICMP_ECHO:{
const void *icmp_data_buff = ((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr);
size_t icmp_data_len = len - sizeof(struct icmp_echo_hdr);
struct icmp_echo_hdr echo_reply;
echo_reply.type = 0;
echo_reply.code = 0;
echo_reply.chksum = 0;
echo_reply.id = icmp->id;
echo_reply.seqno = icmp->seqno;
echo_reply.chksum = ~chksum_buffer( //data checksum
(unsigned short *)icmp_data_buff,
icmp_data_len/sizeof(short),
chksum_buffer( //header checksum
(unsigned short *)&echo_reply,
sizeof(echo_reply)/sizeof(short),
0)
);
send_ip_pkt(
src, IP_PROTO_ICMP,
&echo_reply, sizeof(echo_reply),
icmp_data_buff, icmp_data_len
);
break;
}
default:
break;
}
}
static void
send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac)
{
struct arp_eth_ipv4 reply _AL4;
reply.ar_hrd = req->ar_hrd;
reply.ar_pro = req->ar_pro;
reply.ar_hln = req->ar_hln;
reply.ar_pln = req->ar_pln;
reply.ar_op = ARPOP_REPLY;
memcpy(reply.ar_sha, &our_mac, 6);
memcpy(reply.ar_sip, req->ar_tip, 4);
memcpy(reply.ar_tha, req->ar_sha, 6);
memcpy(reply.ar_tip, req->ar_sip, 4);
eth_mac_addr_t t;
memcpy(t.addr, reply.ar_tha, 6);
send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0);
}
void send_gratuitous_arp(void){
struct arp_eth_ipv4 req _AL4;
req.ar_hrd = ARPHRD_ETHER;
req.ar_pro = ETHERTYPE_IPV4;
req.ar_hln = sizeof(eth_mac_addr_t);
req.ar_pln = sizeof(struct ip_addr);
req.ar_op = ARPOP_REQUEST;
memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t));
memcpy(req.ar_sip, get_ip_addr(), sizeof(struct ip_addr));
memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t));
memcpy(req.ar_tip, get_ip_addr(), sizeof(struct ip_addr));
//send the request with a broadcast ethernet mac address
send_pkt(BCAST_MAC_ADDR, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0);
}
static void
handle_arp_packet(struct arp_eth_ipv4 *p, size_t size)
{
if (size < sizeof(struct arp_eth_ipv4)){
printf("\nhandle_arp: weird size = %d\n", (int)size);
return;
}
if (0){
printf("ar_hrd = %d\n", p->ar_hrd);
printf("ar_pro = %d\n", p->ar_pro);
printf("ar_hln = %d\n", p->ar_hln);
printf("ar_pln = %d\n", p->ar_pln);
printf("ar_op = %d\n", p->ar_op);
printf("ar_sha = "); print_mac_addr(p->ar_sha); newline();
printf("ar_sip = "); print_ip_addr (p->ar_sip); newline();
printf("ar_tha = "); print_mac_addr(p->ar_tha); newline();
printf("ar_tip = "); print_ip_addr (p->ar_tip); newline();
}
if (p->ar_hrd != ARPHRD_ETHER
|| p->ar_pro != ETHERTYPE_IPV4
|| p->ar_hln != 6
|| p->ar_pln != 4)
return;
if (p->ar_op != ARPOP_REQUEST)
return;
struct ip_addr sip;
struct ip_addr tip;
sip.addr = get_int32(p->ar_sip);
tip.addr = get_int32(p->ar_tip);
if (memcmp(&tip, &_local_ip_addr, sizeof(_local_ip_addr)) == 0){ // They're looking for us...
send_arp_reply(p, _local_mac_addr);
}
}
void
handle_eth_packet(uint32_t *p, size_t nlines)
{
static size_t bcount = 0;
if (debug) printf("===> %d\n", (int)bcount++);
if (debug) print_buffer(p, nlines);
padded_eth_hdr_t *eth_hdr = (padded_eth_hdr_t *)p;
if (eth_hdr->ethertype == ETHERTYPE_ARP){
struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(p + 4);
handle_arp_packet(arp, nlines*sizeof(uint32_t) - 14);
}
else if (eth_hdr->ethertype == ETHERTYPE_IPV4){
struct ip_hdr *ip = (struct ip_hdr *)(p + 4);
if (IPH_V(ip) != 4 || IPH_HL(ip) != 5) // ignore pkts w/ bad version or options
return;
if (IPH_OFFSET(ip) & (IP_MF | IP_OFFMASK)) // ignore fragmented packets
return;
// filter on dest ip addr (should be broadcast or for us)
bool is_bcast = memcmp(&eth_hdr->dst, &BCAST_MAC_ADDR, sizeof(BCAST_MAC_ADDR)) == 0;
bool is_my_ip = memcmp(&ip->dest, &_local_ip_addr, sizeof(_local_ip_addr)) == 0;
if (!is_bcast && !is_my_ip) return;
arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)p)+8));
int protocol = IPH_PROTO(ip);
int len = IPH_LEN(ip) - IP_HLEN;
switch (protocol){
case IP_PROTO_UDP:
handle_udp_packet(ip->src, ip->dest, (struct udp_hdr *)(((char *)ip) + IP_HLEN), len);
break;
case IP_PROTO_ICMP:
handle_icmp_packet(ip->src, ip->dest, (struct icmp_echo_hdr *)(((char *)ip) + IP_HLEN), len);
break;
default: // ignore
break;
}
}
else
return; // Not ARP or IPV4, ignore
}

58
zpu/lib/net_common.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright 2009-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_NET_COMMON_H
#define INCLUDED_NET_COMMON_H
#include <stdint.h>
#include <stddef.h>
#include <net/socket_address.h>
#include <net/eth_mac_addr.h>
/*!
* Setup an entry in the protocol framer for a UDP socket.
*
* \param eth_dst ethernet destination mac addr
* \param eth_src ethernet source mac addr
* \param sock_dst udp/ip socket destination
* \param sock_src udp/ip socket source
* \param which the index into the table
*/
void setup_framer(
eth_mac_addr_t eth_dst,
eth_mac_addr_t eth_src,
struct socket_address sock_dst,
struct socket_address sock_src,
size_t which
);
typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len);
void init_udp_listeners(void);
void register_addrs(const eth_mac_addr_t *mac_addr, const struct ip_addr *ip_addr);
void register_udp_listener(int port, udp_receiver_t rcvr);
void send_udp_pkt(int src_port, struct socket_address dst,
const void *buf, size_t len);
void handle_eth_packet(uint32_t *p, size_t nlines);
void send_gratuitous_arp(void);
#endif /* INCLUDED_NET_COMMON_H */

123
zpu/lib/nonstdio.c Normal file
View File

@@ -0,0 +1,123 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <nonstdio.h>
static const char hex[16] = "0123456789ABCDEF";
// %x
void
puthex4(unsigned long x)
{
putchar(hex[x & 0xf]);
}
// %02x
void
puthex8(unsigned long x)
{
putchar(hex[(x >> 4) & 0xf]);
putchar(hex[x & 0xf]);
}
// %04x
void
puthex16(unsigned long x)
{
puthex8(x >> 8);
puthex8(x);
}
// %08x
void
puthex32(unsigned long x)
{
puthex16(x >> 16);
puthex16(x);
}
void
puthex4_nl(unsigned long x)
{
puthex4(x);
newline();
}
void
puthex8_nl(unsigned long x)
{
puthex8(x);
newline();
}
void
puthex16_nl(unsigned long x)
{
puthex16(x);
newline();
}
void
puthex32_nl(unsigned long x)
{
puthex32(x);
newline();
}
/*
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
int abs(signed long value) {
return (value >= 0) ? value : 0-value;
}
//we'll keep the puthex functions above because they're way more lightweight. but sometimes you just want to print in decimal, you know?
char *itoa(signed long value, char *result, int base)
{
// check that the base if valid
if (base < 2 || base > 16) { *result = 0; return result; }
char* out = result;
signed long quotient = value;
do {
*out = hex[ abs(quotient % base) ];
++out;
quotient /= base;
} while ( quotient );
// Only apply negative sign for base 10
if ( value < 0 && base == 10) *out++ = '-';
*out = 0;
reverse( result );
return result;
}
*/

47
zpu/lib/nonstdio.h Normal file
View File

@@ -0,0 +1,47 @@
//
// Copyright 2010-2011 Ettus Research LLC
//
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_NONSTDIO_H
#define INCLUDED_NONSTDIO_H
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
void putstr(const char *s); // cf puts, no added newline
void puthex4(unsigned long x); // output 1 hex digit
void puthex8(unsigned long x); // output 2 hex digits
void puthex16(unsigned long x); // output 4 hex digits
void puthex32(unsigned long x); // output 8 hex digits
void puthex4_nl(unsigned long x); // ... followed by newline
void puthex8_nl(unsigned long x);
void puthex16_nl(unsigned long x);
void puthex32_nl(unsigned long x);
#define puthex puthex32
#define puthex_nl puthex32_nl
void newline(); // putchar('\n')
void print_mac_addr(const void *addr);
void print_ip_addr(const void *addr);
void print_buffer(uint32_t *buf, size_t n);
#endif /* INCLUDED_NONSTDIO_H */

89
zpu/lib/pic.c Normal file
View File

@@ -0,0 +1,89 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pic.h"
#include "hal_io.h"
#include "memory_map.h"
#define NVECTORS 8
/*
* Our secondary interrupt vector.
*/
irq_handler_t pic_vector[NVECTORS];
void
pic_init(void)
{
// uP is level triggered
pic_regs->mask = ~0; // mask all interrupts
pic_regs->edge_enable = PIC_UNDERRUN_INT | PIC_OVERRUN_INT | PIC_PPS_INT;
pic_regs->polarity = ~0 & ~PIC_PHY_INT; // rising edge
pic_regs->pending = ~0; // clear all pending ints
for (int i = 0; i < NVECTORS; i++){
pic_vector[i] = pic_nop_handler;
}
}
/*
* This magic gets pic_interrupt_handler wired into the
* system interrupt handler with the appropriate prologue and
* epilogue.
*/
//FIXME zpu-gcc does not install interrupt_handler like this
//void pic_interrupt_handler() __attribute__ ((interrupt_handler));
void pic_interrupt_handler()
{
// pending and not masked interrupts
int live = pic_regs->pending & ~pic_regs->mask;
// FIXME loop while there are interrupts to service.
// That will reduce our overhead.
// handle the first one set
int i;
int mask;
for (i=0, mask=1; i < NVECTORS; i++, mask <<= 1){
if (mask & live){ // handle this one
// puthex_nl(i);
(*pic_vector[i])(i);
pic_regs->pending = mask; // clear pending interrupt
return;
}
}
}
void
pic_register_handler(unsigned irq, irq_handler_t handler)
{
if (irq >= NVECTORS)
return;
pic_vector[irq] = handler;
pic_regs->mask &= ~IRQ_TO_MASK(irq);
}
void
pic_nop_handler(unsigned irq)
{
// nop
}

36
zpu/lib/pic.h Normal file
View File

@@ -0,0 +1,36 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_PIC_H
#define INCLUDED_PIC_H
typedef void (*irq_handler_t)(unsigned irq);
void pic_init(void);
void pic_register_handler(unsigned irq, irq_handler_t handler);
void pic_nop_handler(unsigned irq); // default handler does nothing
// FIXME inline assembler
int pic_disable_interrupts();
int pic_enable_interrupts();
void pic_restore_interrupts(int prev_status);
void pic_interrupt_handler();
#endif /* INCLUDED_PIC_H */

100
zpu/lib/pkt_ctrl.c Normal file
View File

@@ -0,0 +1,100 @@
/*
* Copyright 2010-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pkt_ctrl.h"
#include "memory_map.h"
#include <nonstdio.h>
//status signals from WB into PR
#define CPU_STAT_RD_DONE (1 << 0)
#define CPU_STAT_RD_EROR (1 << 1)
#define CPU_STAT_RD_IDLE (1 << 2)
//status signals from PR into WB
#define CPU_STAT_WR_DONE (1 << 4)
#define CPU_STAT_WR_EROR (1 << 5)
#define CPU_STAT_WR_IDLE (1 << 6)
//control signals from WB into PR
#define CPU_CTRL_RD_CLEAR (1 << 0)
#define CPU_CTRL_RD_START (1 << 1)
//control signals from PR into WB
#define CPU_CTRL_WR_CLEAR (1 << 2)
#define CPU_CTRL_WR_START (1 << 3)
void pkt_ctrl_program_inspector(
const struct ip_addr *ip_addr, uint16_t data_port0, uint16_t data_port1
){
router_ctrl->ip_addr = ip_addr->addr;
router_ctrl->data_ports = data_port0 | ((uint32_t)(data_port1) << 16);
}
void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode){
//About to change the mode; ensure that we are accepting packets.
//The plumbing will not switch if it cannot pass an end of packet.
pkt_ctrl_release_incoming_buffer();
//Change the mode; this switches the valves and crossbars.
router_ctrl->mode_ctrl = mode;
}
static inline void cpu_stat_wait_for(int bm){
while((router_status->status & bm) == 0){
/* NOP */
}
}
void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines){
uint32_t status = router_status->status;
//if done: clear the read and return the buffer
if (status & CPU_STAT_RD_DONE){
*num_lines = (router_status->status >> 16) & 0xffff;
return ((uint32_t *) ROUTER_RAM_BASE);
}
//if error: drop the packet and start a new read
if (status & CPU_STAT_RD_EROR){
putstr("E");
pkt_ctrl_release_incoming_buffer();
}
//otherwise null for nothing ready
return NULL;
}
void pkt_ctrl_release_incoming_buffer(void){
//clear, wait for idle, and start a new read
router_ctrl->iface_ctrl = CPU_CTRL_RD_CLEAR;
cpu_stat_wait_for(CPU_STAT_RD_IDLE);
router_ctrl->iface_ctrl = CPU_CTRL_RD_START;
}
void *pkt_ctrl_claim_outgoing_buffer(void){
//wait for idle and return the buffer
cpu_stat_wait_for(CPU_STAT_WR_IDLE);
return ((uint32_t *) ROUTER_RAM_BASE);
}
void pkt_ctrl_commit_outgoing_buffer(size_t num_lines){
//start a new write with the given length
router_ctrl->iface_ctrl = ((num_lines & 0xffff) << 16) | CPU_CTRL_WR_START;
//wait for the write to become done
cpu_stat_wait_for(CPU_STAT_WR_DONE);
router_ctrl->iface_ctrl = CPU_CTRL_WR_CLEAR;
}

63
zpu/lib/pkt_ctrl.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright 2010-2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_PKT_CTRL_H
#define INCLUDED_PKT_CTRL_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <lwip/ip_addr.h>
typedef enum {
PKT_CTRL_ROUTING_MODE_SLAVE = 0,
PKT_CTRL_ROUTING_MODE_MASTER = 1
} pkt_ctrl_routing_mode_t;
//! Program the decision values into the packet inspector
void pkt_ctrl_program_inspector(
const struct ip_addr *ip_addr, uint16_t data_port0, uint16_t data_port1
);
//! Set the routing mode for this device
void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode);
/*!
* Try to claim an incomming buffer.
* \param num_lines filled with the buffer size
* \return a pointer to the buffer memory or NULL
*/
void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines);
/*!
* Release the incoming buffer. Call when done.
*/
void pkt_ctrl_release_incoming_buffer(void);
/*!
* Claim an outgoing buffer.
* \return a pointer to the buffer
*/
void *pkt_ctrl_claim_outgoing_buffer(void);
/*!
* Commit the outgoing buffer.
* \param num_lines how many lines written.
*/
void pkt_ctrl_commit_outgoing_buffer(size_t num_lines);
#endif /* INCLUDED_PKT_CTRL_H */

33
zpu/lib/print_addrs.c Normal file
View File

@@ -0,0 +1,33 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nonstdio.h"
void
print_mac_addr(const void *addr)
{
uint8_t *p = (uint8_t *)addr;
for(size_t i = 0; i < 6; i++){
if(i) putchar(':');
puthex8(p[i]);
}
}
void print_ip_addr(const void *addr){
uint8_t *p = (uint8_t *)addr;
printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
}

36
zpu/lib/print_buffer.c Normal file
View File

@@ -0,0 +1,36 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <nonstdio.h>
void
print_buffer(uint32_t *buf, size_t n)
{
size_t i;
for (i = 0; i < n; i++){
if (i % 4 == 0)
puthex16(i * 4);
putchar(' ');
puthex32(buf[i]);
if (i % 4 == 3)
newline();
}
newline();
}

44
zpu/lib/print_rmon_regs.c Normal file
View File

@@ -0,0 +1,44 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "print_rmon_regs.h"
#include "eth_mac.h"
#include "nonstdio.h"
void
print_rmon_regs(void)
{
int i;
for (i=0; i <= 0x10; i++){
putstr("RMON[0x");
puthex8(i);
putstr("] = ");
printf("%d\n", eth_mac_read_rmon(i));
}
for (i=0x20; i <= 0x30; i++){
putstr("RMON[0x");
puthex8(i);
putstr("] = ");
printf("%d\n", eth_mac_read_rmon(i));
}
}

24
zpu/lib/print_rmon_regs.h Normal file
View File

@@ -0,0 +1,24 @@
/* -*- c++ -*- */
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_PRINT_RMON_REGS_H
#define INCLUDED_PRINT_RMON_REGS_H
void print_rmon_regs(void);
#endif /* INCLUDED_PRINT_RMON_REGS_H */

134
zpu/lib/printf.c Normal file
View File

@@ -0,0 +1,134 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Based on code from the SDCC z80 library ;)
*/
#include <stdarg.h>
#include <stdio.h>
static void
_printn(unsigned u, unsigned base, char issigned,
void (*emitter)(char, void *), void *pData)
{
const char *_hex = "0123456789ABCDEF";
if (issigned && ((int)u < 0)) {
(*emitter)('-', pData);
u = (unsigned)-((int)u);
}
if (u >= base)
_printn(u/base, base, 0, emitter, pData);
(*emitter)(_hex[u%base], pData);
}
static void
_printf(const char *format, void (*emitter)(char, void *),
void *pData, va_list va)
{
while (*format) {
if (*format != '%')
(*emitter)(*format, pData);
else {
switch (*++format) {
case 0: /* hit end of format string */
return;
case 'c':
{
char c = (char)va_arg(va, int);
(*emitter)(c, pData);
break;
}
case 'u':
{
unsigned u = va_arg(va, unsigned);
_printn(u, 10, 0, emitter, pData);
break;
}
case 'd':
{
unsigned u = va_arg(va, unsigned);
_printn(u, 10, 1, emitter, pData);
break;
}
case 'x':
case 'p':
{
unsigned u = va_arg(va, unsigned);
_printn(u, 16, 0, emitter, pData);
break;
}
case 's':
{
char *s = va_arg(va, char *);
while (*s) {
(*emitter)(*s, pData);
s++;
}
break;
}
}
}
format++;
}
}
static void
_char_emitter(char c, void *pData __attribute__((unused)))
{
putchar(c);
}
int
printf(const char *format, ...)
{
va_list va;
va_start(va, format);
_printf(format, _char_emitter, NULL, va);
va_end(va);
// wrong return value...
return 0;
}
#if 0
// Totally dangerous. Don't use
static void
_buf_emitter(char c, void *pData)
{
*((*((char **)pData)))++ = c;
}
int sprintf(char *pInto, const char *format, ...)
{
va_list va;
va_start(va, format);
_printf(format, _buf_emitter, &pInto, va);
*pInto++ = '\0';
va_end(va);
// FIXME wrong return value
return 0;
}
#endif

134
zpu/lib/printf.c.smaller Normal file
View File

@@ -0,0 +1,134 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Based on code from the SDCC z80 library ;)
*/
#include <stdarg.h>
#include <stdio.h>
#include <hal_io.h> /* FIXME refactor into stdio */
#define PUTCHAR(x) hal_putc(x)
static void
_printn(unsigned u, unsigned base, char issigned)
{
const char *_hex = "0123456789ABCDEF";
if (issigned && ((int)u < 0)) {
PUTCHAR('-');
u = (unsigned)-((int)u);
}
if (u >= base)
_printn(u/base, base, 0);
PUTCHAR(_hex[u%base]);
}
static void
_printf(const char *format, va_list va)
{
while (*format) {
if (*format != '%')
PUTCHAR(*format);
else {
switch (*++format) {
case 0: /* hit end of format string */
return;
case 'c':
{
char c = (char)va_arg(va, int);
PUTCHAR(c);
break;
}
case 'u':
{
unsigned u = va_arg(va, unsigned);
_printn(u, 10, 0);
break;
}
case 'd':
{
unsigned u = va_arg(va, unsigned);
_printn(u, 10, 1);
break;
}
case 'x':
case 'p':
{
unsigned u = va_arg(va, unsigned);
_printn(u, 16, 0);
break;
}
case 's':
{
char *s = va_arg(va, char *);
while (*s) {
PUTCHAR(*s);
s++;
}
break;
}
}
}
format++;
}
}
#if 0
static void
_char_emitter(char c, void *pData __attribute__((unused)))
{
hal_putc(c);
}
#endif
int
printf(const char *format, ...)
{
va_list va;
va_start(va, format);
_printf(format, va);
// wrong return value...
return 0;
}
#if 0
// Totally dangerous. Don't use
static void
_buf_emitter(char c, void *pData)
{
*((*((char **)pData)))++ = c;
}
int sprintf(char *pInto, const char *format, ...)
{
va_list va;
va_start(va, format);
_printf(format, _buf_emitter, &pInto, va);
*pInto++ = '\0';
// FIXME wrong return value
return 0;
}
#endif

110
zpu/lib/spi.c Normal file
View File

@@ -0,0 +1,110 @@
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "spi.h"
#include "memory_map.h"
#include "pic.h"
#include "nonstdio.h"
//void (*volatile spi_callback)(void); //SPI callback when xfer complete.
//static void spi_irq_handler(unsigned irq);
void
spi_init(void)
{
/*
* f_sclk = f_wb / ((div + 1) * 2)
*/
spi_regs->div = 1; // 0 = Div by 2 (25 MHz); 1 = Div-by-4 (12.5 MHz)
}
void
spi_wait(void)
{
while (spi_regs->ctrl & SPI_CTRL_GO_BSY)
;
}
uint32_t
spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)
{
flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG);
int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags;
spi_wait();
// Tell it which SPI slave device to access
spi_regs->ss = slave & 0xffff;
// Data we will send
spi_regs->txrx0 = data;
// Run it -- write once and rewrite with GO set
spi_regs->ctrl = ctrl;
spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY;
if(readback) {
spi_wait();
return spi_regs->txrx0;
}
else
return 0;
}
/*
void spi_register_callback(void (*volatile callback)(void)) {
spi_callback = callback;
}
static void spi_irq_handler(unsigned irq) {
// printf("SPI IRQ handler\n");
// uint32_t wat = spi_regs->ctrl; //read a register just to clear the interrupt
//spi_regs->ctrl &= ~SPI_CTRL_IE;
if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later
}
uint32_t spi_get_data(void) {
return spi_regs->txrx0;
}
bool
spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) {
flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG);
int ctrl = SPI_CTRL_ASS | SPI_CTRL_IE | (SPI_CTRL_CHAR_LEN_MASK & length) | flags;
if(spi_regs->ctrl & SPI_CTRL_GO_BSY) {
printf("Async SPI busy!\n");
return false; //we don't wait on busy, we just return failure. we count on the host to not set up another transaction before the last one finishes.
}
// Tell it which SPI slave device to access
spi_regs->ss = slave & 0xffff;
// Data we will send
spi_regs->txrx0 = data;
spi_register_callback(callback);
pic_register_handler(IRQ_SPI, spi_irq_handler);
// Run it -- write once and rewrite with GO set
spi_regs->ctrl = ctrl;
spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY;
return true;
}
*/

77
zpu/lib/spi.h Normal file
View File

@@ -0,0 +1,77 @@
/* -*- c -*- */
/*
* Copyright 2006,2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SPI_H
#define INCLUDED_SPI_H
#include <memory_map.h>
#include <stdbool.h>
/*!
* \brief One time call to initialize SPI
*/
void spi_init(void);
/*!
* \brief Wait for last SPI transaction to complete.
* Unless you need to know it completed, it's not necessary to call this.
*/
void spi_wait(void);
#define SPI_TXONLY false // readback: no
#define SPI_TXRX true // readback: yes
/*
* Flags for spi_transact
*/
#define SPIF_PUSH_RISE 0 // push tx data on rising edge of SCLK
#define SPIF_PUSH_FALL SPI_CTRL_TXNEG // push tx data on falling edge of SCLK
#define SPIF_LATCH_RISE 0 // latch rx data on rising edge of SCLK
#define SPIF_LATCH_FALL SPI_CTRL_RXNEG // latch rx data on falling edge of SCLK
uint32_t
spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags);
//uint32_t spi_get_data(void);
//static void spi_irq_handler(unsigned irq);
//void spi_register_callback(void (*volatile callback)(void));
//bool
//spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void));
// ----------------------------------------------------------------
// Routines that manipulate the FLASH SPI BUS
// ----------------------------------------------------------------
/*!
* \brief One time call to initialize SPI
*/
void spif_init(void);
/*!
* \brief Wait for last SPI transaction to complete.
* Unless you need to know it completed, it's not necessary to call this.
*/
void spif_wait(void);
uint32_t
spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags);
#endif /* INCLUDED_SPI_H */

34
zpu/lib/stdint.h Normal file
View File

@@ -0,0 +1,34 @@
/* -*- c -*- */
/*
* Copyright 2007,2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_STDINT_H
#define INCLUDED_STDINT_H
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
typedef int intptr_t;
typedef unsigned int uintptr_t;
#endif /* INCLUDED_STDINT_H */

38
zpu/lib/stdio.h Normal file
View File

@@ -0,0 +1,38 @@
/* -*- c -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_STDIO_H
#define INCLUDED_STDIO_H
// very trimmed down stdio.h See also nonstdio.h
#ifndef NULL
#define NULL 0
#endif
#ifndef EOF
#define EOF (-1)
#endif
int putchar(int c);
int puts(const char *s);
int printf(const char *format, ...);
int getchar(void);
#endif /* INCLUDED_STDIO_H */

88
zpu/lib/u2_init.c Normal file
View File

@@ -0,0 +1,88 @@
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "u2_init.h"
#include "memory_map.h"
#include "spi.h"
#include "pic.h"
#include "hal_io.h"
#include "hal_uart.h"
#include "i2c.h"
#include "mdelay.h"
#include "clocks.h"
#include "usrp2/fw_common.h"
#include "nonstdio.h"
/*
* We ought to arrange for this to be called before main, but for now,
* we require that the user's main call u2_init as the first thing...
*/
bool
u2_init(void)
{
hal_disable_ints();
hal_io_init();
#ifndef NO_SPI_I2C
// init spi, so that we can switch over to the high-speed clock
spi_init();
#ifndef UMTRX
// set up the default clocks
clocks_init();
#endif // UMTRX
#endif
hal_uart_init();
// init i2c so we can read our rev
pic_init(); // progammable interrupt controller
#ifndef NO_SPI_I2C
i2c_init();
#endif
hal_enable_ints();
// flash all leds to let us know board is alive
hal_set_led_src(0x0, 0x1f); /* software ctrl */
hal_set_leds(0x0, 0x1f); mdelay(300);
hal_set_leds(LED_E, LED_E); mdelay(300);
hal_set_leds(LED_C, LED_C); mdelay(300);
hal_set_leds(LED_A, LED_A); mdelay(300);
for (int i = 0; i < 3; i++){ //blink all
static const int blinks = LED_E | LED_C | LED_A;
hal_set_leds(0x0, 0x1f); mdelay(100);
hal_set_leds(blinks, 0x1f); mdelay(100);
}
hal_set_led_src(0x1f & ~LED_D, 0x1f); /* hardware ctrl */
hal_set_leds(LED_D, 0x1f); // Leave one on
#if 0
// test register readback
int rr, vv;
vv = ad9777_read_reg(0);
printf("ad9777 reg[0] = 0x%x\n", vv);
for (rr = 0x04; rr <= 0x0d; rr++){
vv = ad9510_read_reg(rr);
printf("ad9510 reg[0x%x] = 0x%x\n", rr, vv);
}
#endif
output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN);
return true;
}

28
zpu/lib/u2_init.h Normal file
View File

@@ -0,0 +1,28 @@
/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_U2_INIT_H
#define INCLUDED_U2_INIT_H
#include <stdbool.h>
/*!
* one-time init
*/
bool u2_init(void);
#endif /* INCLUDED_U2_INIT_H */

75
zpu/lib/udp_fw_update.h Normal file
View File

@@ -0,0 +1,75 @@
/* -*- c++ -*- */
/*
* Copyright 2010 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "net_common.h"
#define USRP2_UDP_UPDATE_PORT 49154
typedef enum {
USRP2_FW_UPDATE_ID_WAT = ' ',
USRP2_FW_UPDATE_ID_OHAI_LOL = 'a',
USRP2_FW_UPDATE_ID_OHAI_OMG = 'A',
USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = 'f',
USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = 'F',
USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = 'e',
USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = 'E',
USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = 'd',
USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = 'D',
USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = 'B',
USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = 'w',
USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = 'W',
USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = 'r',
USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = 'R',
USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = 's',
USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = 'S',
USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = 'v',
USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = 'V',
USRP2_FW_UPDATE_ID_KTHXBAI = '~'
} usrp2_fw_update_id_t;
typedef struct {
uint32_t proto_ver;
uint32_t id;
uint32_t seq;
union {
uint32_t ip_addr;
uint32_t hw_rev;
struct {
uint32_t flash_addr;
uint32_t length;
uint8_t data[256];
} flash_args;
struct {
uint32_t sector_size_bytes;
uint32_t memory_size_bytes;
} flash_info_args;
} data;
} usrp2_fw_update_data_t;
void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len);

116
zpu/lib/udp_uart.c Normal file
View File

@@ -0,0 +1,116 @@
/*
* Copyright 2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "udp_uart.h"
#include "hal_uart.h"
#include "net_common.h"
#include "compiler.h"
#include <stdbool.h>
/***********************************************************************
* Constants
**********************************************************************/
#define MAX_NUM_UARTS 4
#ifndef UDP_UART_MASK
#error missing definition for UDP_UART_MASK enable mask
#endif
static const size_t num_idle_cyc_b4_flush = 11; //small but lucky number
/***********************************************************************
* Globals
**********************************************************************/
static uint16_t _base_port;
typedef struct{
struct socket_address dst;
_AL4 uint8_t buf[256];
size_t len; //length of buffer
size_t cyc; //idle cycle count
} udp_uart_state_t;
static udp_uart_state_t _states[MAX_NUM_UARTS];
/***********************************************************************
* UDP handler for UARTs
**********************************************************************/
static void handle_uart_data_packet(
struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len
){
//handle ICMP destination unreachable
if (payload == NULL){
const size_t which = src.port-_base_port;
if (which >= MAX_NUM_UARTS) return;
_states[which].dst.port = 0;
}
//handle a regular blocking UART write
else{
const size_t which = dst.port-_base_port;
if (which >= MAX_NUM_UARTS) return;
_states[which].dst = src;
for (size_t i = 0; i < payload_len; i++){
hal_uart_putc((hal_uart_name_t)which, (int)payload[i]);
}
}
}
/***********************************************************************
* Public init function
**********************************************************************/
void udp_uart_init(const uint16_t base_port){
_base_port = base_port;
for(size_t i = 0; i < MAX_NUM_UARTS; i++){
_states[i].dst.port = 0; //reset to null port
_states[i].len = 0;
_states[i].cyc = 0;
register_udp_listener(_base_port+i, handle_uart_data_packet);
}
}
/***********************************************************************
* Public poll function
**********************************************************************/
void udp_uart_poll(void){
for (size_t i = 0; i < MAX_NUM_UARTS; i++){
if (((UDP_UART_MASK) & (1 << i)) == 0) continue;
bool newline = false;
udp_uart_state_t *state = &_states[i];
//read all characters we can without blocking
for (size_t j = state->len; j < sizeof(_states[0].buf); j++){
int ret = hal_uart_getc_noblock((hal_uart_name_t)i);
if (ret == -1) break;
char ch = (char) ret;
if (ch == '\n' || ch == '\r') newline = true;
state->buf[j] = ch;
state->len++;
state->cyc = 0; //reset idle cycles
}
//nothing in buffer, continue to next uart
if (state->len == 0) continue;
//send out a message if newline or forced flush
if (newline || state->cyc++ > num_idle_cyc_b4_flush){
if (state->dst.port != 0) send_udp_pkt(_base_port+i, state->dst, state->buf, state->len);
state->len = 0;
state->cyc = 0;
}
}
}

36
zpu/lib/udp_uart.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyright 2011 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_UDP_UART_H
#define INCLUDED_UDP_UART_H
#include <stdint.h>
/*!
* Initialize the UDP/UART module.
* Registers handler into the network.
* \param base_port the source port for UART0
*/
void udp_uart_init(const uint16_t base_port);
/*!
* Polls the UART state machine,
* and sends messages over UDP.
*/
void udp_uart_poll(void);
#endif /* INCLUDED_UDP_UART_H */

70
zpu/lib/umtrx_init.c Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright 2012 Alexander Chemeris <Alexander.Chemeris@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "umtrx_init.h"
#include "memory_map.h"
#include "spi.h"
#include "gpsdo.h"
//#include "pic.h"
//#include "hal_io.h"
//#include "hal_uart.h"
//#include "i2c.h"
#include "mdelay.h"
//#include "clocks.h"
//#include "usrp2/fw_common.h"
#include "nonstdio.h"
/*
* UmTRX specific initialization steps
*/
bool
umtrx_init(void)
{
uint8_t val;
uint32_t res;
//issue a reset to the LMS chips
output_regs->clk_ctrl |= LMS1_RESET | LMS2_RESET; // reset pins of lms chips switched to 1
mdelay(100);
output_regs->clk_ctrl &= 0xcf; // reset pins of lms chips switched to 0
mdelay(100);
output_regs->clk_ctrl |= LMS1_RESET | LMS2_RESET; // reset pins of lms chips switched to 1
// Check LMS presense
res = spi_transact(SPI_TXRX, SPI_SS_LMS1, LMS_RD_CMD(0x04), 16, SPIF_PUSH_FALL|SPIF_LATCH_RISE);
printf("LMS1 chip version = 0x%x\n", res);
res = spi_transact(SPI_TXRX, SPI_SS_LMS2, LMS_RD_CMD(0x04), 16, SPIF_PUSH_FALL|SPIF_LATCH_RISE);
printf("LMS2 chip version = 0x%x\n", res);
// Init GPSDO
gpsdo_init();
/*
// Enable RX and TX
putstr("\nEnabling Tx and Rx on LMS1 and LMS2\n");
// register 5:
// DECODE 0, SRESET 1, EN 1, STXEN 1, SRXEN 1, TFWMODE 1
val = 0x3E;
spi_transact(SPI_TXONLY, SPI_SS_LMS1, LMS_WR_CMD(0x05, val), 16, SPIF_PUSH_FALL|SPIF_LATCH_RISE);
res = spi_transact(SPI_TXRX, SPI_SS_LMS1, LMS_RD_CMD(0x05), 16, SPIF_PUSH_FALL|SPIF_LATCH_RISE);
printf("LMS1 register readback = 0x%x\n", res);
spi_transact(SPI_TXONLY, SPI_SS_LMS2, LMS_WR_CMD(0x05, val), 16, SPIF_PUSH_FALL|SPIF_LATCH_RISE);
res = spi_transact(SPI_TXRX, SPI_SS_LMS2, LMS_RD_CMD(0x05), 16, SPIF_PUSH_FALL|SPIF_LATCH_RISE);
printf("LMS2 register readback = 0x%x\n", res);
*/
return true;
}

28
zpu/lib/umtrx_init.h Normal file
View File

@@ -0,0 +1,28 @@
/* -*- c++ -*- */
/*
* Copyright 2012 Alexander Chemeris <Alexander.Chemeris@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_UMTRX_INIT_H
#define INCLUDED_UMTRX_INIT_H
#include <stdbool.h>
/*!
* one-time init
*/
bool umtrx_init(void);
#endif /* INCLUDED_UMTRX_INIT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/

View File

@@ -0,0 +1,4 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
See also the FILES file in each subdirectory.

View File

@@ -0,0 +1,89 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol
suite that has been developed by Adam Dunkels at the Computer and
Networks Architectures (CNA) lab at the Swedish Institute of Computer
Science (SICS).
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tens of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
FEATURES
* IP (Internet Protocol) including packet forwarding over multiple network
interfaces
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
* IGMP (Internet Group Management Protocol) for multicast traffic management
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
and fast recovery/fast retransmit
* Specialized raw/native API for enhanced performance
* Optional Berkeley-like socket API
* DNS (Domain names resolver)
* SNMP (Simple Network Management Protocol)
* DHCP (Dynamic Host Configuration Protocol)
* AUTOIP (for IPv4, conform with RFC 3927)
* PPP (Point-to-Point Protocol)
* ARP (Address Resolution Protocol) for Ethernet
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
and developers using the stack often submit bug fixes, improvements,
and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, CVS and the
mailing list. A core team of developers will commit changes to the
CVS source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
contributions (such as platform ports) are in the 'contrib' module.
See doc/savannah.txt for details on CVS server access for users and
developers.
Last night's CVS tar ball can be downloaded from:
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
The current CVS trees are web-browsable:
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
DOCUMENTATION
The original out-dated homepage of lwIP and Adam Dunkels' papers on
lwIP are at the official lwIP home page:
http://www.sics.se/~adam/lwip/
Self documentation of the source code is regularly extracted from the
current CVS sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growin wiki about lwIP at
http://lwip.scribblewiki.com/
Also, there are mailing lists you can subscribe at
http://savannah.nongnu.org/mail/?group=lwip
plus searchable archives:
http://lists.nongnu.org/archive/html/lwip-users/
http://lists.nongnu.org/archive/html/lwip-devel/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

View File

@@ -0,0 +1,6 @@
savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading.
snmp_agent.txt - The documentation for the lwIP SNMP agent.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.

View File

@@ -0,0 +1,63 @@
1 Introduction
This document describes some guidelines for people participating
in lwIP development.
2 How to contribute to lwIP
Here is a short list of suggestions to anybody working with lwIP and
trying to contribute bug reports, fixes, enhancements, platform ports etc.
First of all as you may already know lwIP is a volunteer project so feedback
to fixes or questions might often come late. Hopefully the bug and patch tracking
features of Savannah help us not lose users' input.
2.1 Source code style:
1. do not use tabs.
2. indentation is two spaces per level (i.e. per tab).
3. end debug messages with a trailing newline (\n).
4. one space between keyword and opening bracket.
5. no space between function and opening bracket.
6. one space and no newline before opening curly braces of a block.
7. closing curly brace on a single line.
8. spaces surrounding assignment and comparisons.
9. don't initialize static and/or global variables to zero, the compiler takes care of that.
10. use current source code style as further reference.
2.2 Source code documentation style:
1. JavaDoc compliant and Doxygen compatible.
2. Function documentation above functions in .c files, not .h files.
(This forces you to synchronize documentation and implementation.)
3. Use current documentation style as further reference.
2.3 Bug reports and patches:
1. Make sure you are reporting bugs or send patches against the latest
sources. (From the latest release and/or the current CVS sources.)
2. If you think you found a bug make sure it's not already filed in the
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The prefered way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
or a patch will be enough.
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
for reporting a compiler warning fix.
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
if it's not to the point and long :) so the chances for it to be applied are greater.
2.4 Platform porters:
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for CVS access to submit and maintain your port in the contrib CVS module.

View File

@@ -0,0 +1,478 @@
Raw TCP/IP interface for lwIP
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
lwIP provides three Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
* BSD-style socket API.
The sequential API provides a way for ordinary, sequential, programs
to use the lwIP stack. It is quite similar to the BSD socket API. The
model of execution is based on the blocking open-read-write-close
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
code and the application program must reside in different execution
contexts (threads).
The socket API is a compatibility API for existing applications,
currently it is built on top of the sequential API. It is meant to
provide all functions needed to run socket API applications running
on other platforms (e.g. unix / windows etc.). However, due to limitations
in the specification of this API, there might be incompatibilities
that require small modifications of existing programs.
** Threading
lwIP started targeting single-threaded environments. When adding multi-
threading support, instead of making the core thread-safe, another
approach was chosen: there is one main thread running the lwIP core
(also known as the "tcpip_thread"). The raw API may only be used from
this thread! Application threads using the sequential- or socket API
communicate with this main thread through message passing.
As such, the list of functions that may be called from
other threads or an ISR is very limited! Only functions
from these API header files are thread-safe:
- api.h
- netbuf.h
- netdb.h
- netifapi.h
- sockets.h
- sys.h
Additionaly, memory (de-)allocation functions may be
called from multiple threads (not ISR!) with NO_SYS=0
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
semaphores.
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
pbuf_free() may also be called from another thread or
an ISR (since only then, mem_free - for PBUF_RAM - may
be called from an ISR: otherwise, the HEAP is only
protected by semaphores).
** The remainder of this document discusses the "raw" API. **
The raw TCP/IP interface allows the application program to integrate
better with the TCP/IP code. Program execution is event based by
having callback functions being called from within the TCP/IP
code. The TCP/IP code and the application program both run in the same
thread. The sequential API has a much higher overhead and is not very
well suited for small systems since it forces a multithreaded paradigm
on the application.
The raw TCP/IP interface is not only faster in terms of code execution
time but is also less memory intensive. The drawback is that program
development is somewhat harder and application programs written for
the raw TCP/IP interface are more difficult to understand. Still, this
is the preferred way of writing applications that should be small in
code size and memory usage.
Both APIs can be used simultaneously by different application
programs. In fact, the sequential API is implemented as an application
program using the raw TCP/IP interface.
--- Callbacks
Program execution is driven by callbacks. Each callback is an ordinary
C function that is called from within the TCP/IP code. Every callback
function is passed the current TCP or UDP connection state as an
argument. Also, in order to be able to keep program specific state,
the callback functions are called with a program specified argument
that is independent of the TCP/IP state.
The function for setting the application connection state is:
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
Specifies the program specific state that should be passed to all
other callback functions. The "pcb" argument is the current TCP
connection control block, and the "arg" argument is the argument
that will be passed to the callbacks.
--- TCP connection setup
The functions used for setting up connections is similar to that of
the sequential API and of the BSD socket API. A new TCP connection
identifier (i.e., a protocol control block - PCB) is created with the
tcp_new() function. This PCB can then be either set to listen for new
incoming connections or be explicitly connected to another host.
- struct tcp_pcb *tcp_new(void)
Creates a new connection identifier (PCB). If memory is not
available for creating the new pcb, NULL is returned.
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Binds the pcb to a local IP address and port number. The IP address
can be specified as IP_ADDR_ANY in order to bind the connection to
all local IP addresses.
If another connection is bound to the same port, the function will
return ERR_USE, otherwise ERR_OK is returned.
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
Commands a pcb to start listening for incoming connections. When an
incoming connection is accepted, the function specified with the
tcp_accept() function will be called. The pcb will have to be bound
to a local port with the tcp_bind() function.
The tcp_listen() function returns a new connection identifier, and
the one passed as an argument to the function will be
deallocated. The reason for this behavior is that less memory is
needed for a connection that is listening, so tcp_listen() will
reclaim the memory needed for the original connection and allocate a
new smaller memory block for the listening connection.
tcp_listen() may return NULL if no memory was available for the
listening connection. If so, the memory associated with the pcb
passed as an argument to tcp_listen() will not be deallocated.
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
Same as tcp_listen, but limits the number of outstanding connections
in the listen queue to the value specified by the backlog argument.
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
- void tcp_accepted(struct tcp_pcb *pcb)
Inform lwIP that an incoming connection has been accepted. This would
usually be called from the accept callback. This allows lwIP to perform
housekeeping tasks, such as allowing further incoming connections to be
queued in the listen backlog.
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err))
Specified the callback function that should be called when a new
connection arrives on a listening connection.
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
Sets up the pcb to connect to the remote host and sends the
initial SYN segment which opens the connection.
The tcp_connect() function returns immediately; it does not wait for
the connection to be properly setup. Instead, it will call the
function specified as the fourth argument (the "connected" argument)
when the connection is established. If the connection could not be
properly established, either because the other host refused the
connection or because the other host didn't answer, the "err"
callback function of this pcb (registered with tcp_err, see below)
will be called.
The tcp_connect() function can return ERR_MEM if no memory is
available for enqueueing the SYN segment. If the SYN indeed was
enqueued successfully, the tcp_connect() function returns ERR_OK.
--- Sending TCP data
TCP data is sent by enqueueing the data with a call to
tcp_write(). When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
u8_t copy)
Enqueues the data pointed to by the argument dataptr. The length of
the data is passed as the len parameter. The copy argument is either
0 or 1 and indicates whether the new memory should be allocated for
the data to be copied into. If the argument is 0, no new memory
should be allocated and the data should only be referenced by
pointer.
The tcp_write() function will fail and return ERR_MEM if the length
of the data exceeds the current send buffer size or if the length of
the queue of outgoing segment is larger than the upper limit defined
in lwipopts.h. The number of bytes available in the output queue can
be retrieved with the tcp_sndbuf() function.
The proper way to use this function is to call the function with at
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
the application should wait until some of the currently enqueued
data has been successfully received by the other host and try again.
- void tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len))
Specifies the callback function that should be called when data has
successfully been received (i.e., acknowledged) by the remote
host. The len argument passed to the callback function gives the
amount bytes that was acknowledged by the last acknowledgment.
--- Receiving TCP data
TCP data reception is callback based - an application specified
callback function is called when new data arrives. When the
application has taken the data, it has to call the tcp_recved()
function to indicate that TCP can advertise increase the receive
window.
- void tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err))
Sets the callback function that will be called when new data
arrives. The callback function will be passed a NULL pbuf to
indicate that the remote host has closed the connection. If
there are no errors and the callback function is to return
ERR_OK, then it must free the pbuf. Otherwise, it must not
free the pbuf so that lwIP core code can store it.
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
Must be called when the application has received the data. The len
argument indicates the length of the received data.
--- Application polling
When a connection is idle (i.e., no data is either transmitted or
received), lwIP will repeatedly poll the application by calling a
specified callback function. This can be used either as a watchdog
timer for killing connections that have stayed idle for too long, or
as a method of waiting for memory to become available. For instance,
if a call to tcp_write() has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb))
Specifies the polling interval and the callback function that should
be called to poll the application. The interval is specified in
number of TCP coarse grained timer shots, which typically occurs
twice a second. An interval of 10 means that the application would
be polled every 5 seconds.
--- Closing and aborting connections
- err_t tcp_close(struct tcp_pcb *pcb)
Closes the connection. The function may return ERR_MEM if no memory
was available for closing the connection. If so, the application
should wait and try again either by using the acknowledgment
callback or the polling functionality. If the close succeeds, the
function returns ERR_OK.
The pcb is deallocated by the TCP code after a call to tcp_close().
- void tcp_abort(struct tcp_pcb *pcb)
Aborts the connection by sending a RST (reset) segment to the remote
host. The pcb is deallocated. This function never fails.
If a connection is aborted because of an error, the application is
alerted of this event by the err callback. Errors that might abort a
connection are when there is a shortage of memory. The callback
function to be called is set using the tcp_err() function.
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
err_t err))
The error callback function does not get the pcb passed to it as a
parameter since the pcb may already have been deallocated.
--- Lower layer TCP interface
TCP provides a simple interface to the lower layers of the
system. During system initialization, the function tcp_init() has
to be called before any other TCP function is called. When the system
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
must be called with regular intervals. The tcp_fasttmr() should be
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
--- UDP interface
The UDP interface is similar to that of TCP, but due to the lower
level of complexity of UDP, the interface is significantly simpler.
- struct udp_pcb *udp_new(void)
Creates a new UDP pcb which can be used for UDP communication. The
pcb is not active until it has either been bound to a local address
or connected to a remote address.
- void udp_remove(struct udp_pcb *pcb)
Removes and deallocates the pcb.
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Binds the pcb to a local address. The IP-address argument "ipaddr"
can be IP_ADDR_ANY to indicate that it should listen to any local IP
address. The function currently always return ERR_OK.
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Sets the remote end of the pcb. This function does not generate any
network traffic, but only set the remote address of the pcb.
- err_t udp_disconnect(struct udp_pcb *pcb)
Remove the remote end of the pcb. This function does not generate
any network traffic, but only removes the remote address of the pcb.
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
Sends the pbuf p. The pbuf is not deallocated.
- void udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
struct ip_addr *addr,
u16_t port),
void *recv_arg)
Specifies a callback function that should be called when a UDP
datagram is received.
--- System initalization
A truly complete and generic sequence for initializing the lwip stack
cannot be given because it depends on the build configuration (lwipopts.h)
and additional initializations for your runtime environment (e.g. timers).
We can give you some idea on how to proceed when using the raw API.
We assume a configuration using a single Ethernet netif and the
UDP and TCP transport layers, IPv4 and the DHCP client.
Call these functions in the order of appearance:
- stats_init()
Clears the structure where runtime statistics are gathered.
- sys_init()
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
to be called for easy configuration changes.
- mem_init()
Initializes the dynamic memory heap defined by MEM_SIZE.
- memp_init()
Initializes the memory pools defined by MEMP_NUM_x.
- pbuf_init()
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
- etharp_init()
Initializes the ARP table and queue.
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
after this initialization.
- ip_init()
Doesn't do much, it should be called to handle future changes.
- udp_init()
Clears the UDP PCB list.
- tcp_init()
Clears the TCP PCB list and clears some internal TCP timers.
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
predefined regular intervals after this initialization.
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
struct ip_addr *netmask, struct ip_addr *gw,
void *state, err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif))
Adds your network interface to the netif_list. Allocate a struct
netif and pass a pointer to this structure as the first argument.
Give pointers to cleared ip_addr structures when using DHCP,
or fill them with sane numbers otherwise. The state pointer may be NULL.
The init function pointer must point to a initialization function for
your ethernet netif interface. The following code illustrates it's use.
err_t netif_if_init(struct netif *netif)
{
u8_t i;
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
init_my_eth_device();
return ERR_OK;
}
For ethernet drivers, the input function pointer must point to the lwip
function ethernet_input() declared in "netif/etharp.h". Other drivers
must use ip_input() declared in "lwip/ip.h".
- netif_set_default(struct netif *netif)
Registers the default network interface.
- netif_set_up(struct netif *netif)
When the netif is fully configured this function must be called.
- dhcp_start(struct netif *netif)
Creates a new DHCP client for this interface on the first call.
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
the predefined regular intervals after starting the client.
You can peek in the netif->dhcp struct for the actual DHCP status.
--- Optimalization hints
The first thing you want to optimize is the lwip_standard_checksum()
routine from src/core/inet.c. You can override this standard
function with the #define LWIP_CHKSUM <your_checksum_routine>.
There are C examples given in inet.c or you might want to
craft an assembly function for this. RFC1071 is a good
introduction to this subject.
Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture.
#define LWIP_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x) <your_htons>
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the
hardware isn't serviced frequently and fast enough
buffer overflows are likely to occur.
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
as frequently as possible. When using an RTOS let the cs8900 interrupt
wake a high priority task that services your driver using a binary
semaphore or event flag. Some drivers might allow additional tuning
to match your application and network.
For a production release it is recommended to set LWIP_STATS to 0.
Note that speed performance isn't influenced much by simply setting
high values to the memory options.

View File

@@ -0,0 +1,135 @@
Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the CVS repository
2 - Committers/developers CVS access using SSH (to be written)
3 - Merging from DEVEL branch to main trunk (stable branch)
4 - How to release lwIP
1 Obtaining lwIP from the CVS repository
----------------------------------------
To perform an anonymous CVS checkout of the main trunk (this is where
bug fixes and incremental enhancements occur), do this:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
Or, obtain a stable branch (updated with bug fixes only) as follows:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7 -d lwip-0.7 lwip
Or, obtain a specific (fixed) release as follows:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
3 Committers/developers CVS access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, CVS commits to the server occur through a SSH tunnel for project members.
To create a SSH2 key pair in UNIX-like environments, do this:
ssh-keygen -t dsa
Under Windows, a recommended SSH client is "PuTTY", freely available with good
documentation and a graphic user interface. Use its key generator.
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
a while so that Savannah can update its configuration (This can take minutes).
Try to login using SSH:
ssh -v your_login@cvs.sv.gnu.org
If it tells you:
Authenticating with public key "your_key_name"...
Server refused to allocate pty
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for CVS only. Now, you should be able to do this:
export CVS_RSH=ssh
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
after which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using CVS to make
changes on the repository. If in doubt, ask on the lwip-members mailing list.
(If SSH asks about authenticity of the host, you can check the key
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
3 Merging from DEVEL branch to main trunk (stable)
--------------------------------------------------
Merging is a delicate process in CVS and requires the
following disciplined steps in order to prevent conflicts
in the future. Conflicts can be hard to solve!
Merging from branch A to branch B requires that the A branch
has a tag indicating the previous merger. This tag is called
'merged_from_A_to_B'. After merging, the tag is moved in the
A branch to remember this merger for future merge actions.
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
Merge all changes in DEVEL since our last merge to main:
In the working copy of the main trunk:
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
(This will apply the changes between 'merged_from_DEVEL_to_main'
and 'DEVEL' to your work set of files)
We can now commit the merge result.
cvs commit -R -m "Merged from DEVEL to main."
If this worked out OK, we now move the tag in the DEVEL branch
to this merge point, so we can use this point for future merges:
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
4 How to release lwIP
---------------------
First, checkout a clean copy of the branch to be released. Tag this set with
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
Login CVS using pserver authentication, then export a clean copy of the
tagged tree. Export is similar to a checkout, except that the CVS metadata
is not created locally.
export CVS_RSH=ssh
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
zip -r lwip-0.6.3.zip lwip-0.6.3
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-0.6.3.tar.gz
gpg -b lwip-0.6.3.tar.bz2
gpg -b lwip-0.6.3.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp>mput *0.6.3.*
Additionally, you may post a news item on Savannah, like this:
A new 0.6.3 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.

View File

@@ -0,0 +1,181 @@
SNMPv1 agent for lwIP
Author: Christiaan Simons
This is a brief introduction how to use and configure the SNMP agent.
Note the agent uses the raw-API UDP interface so you may also want to
read rawapi.txt to gain a better understanding of the SNMP message handling.
0 Agent Capabilities
====================
SNMPv1 per RFC1157
This is an old(er) standard but is still widely supported.
For SNMPv2c and v3 have a greater complexity and need many
more lines of code. IMHO this breaks the idea of "lightweight IP".
Note the S in SNMP stands for "Simple". Note that "Simple" is
relative. SNMP is simple compared to the complex ISO network
management protocols CMIP (Common Management Information Protocol)
and CMOT (CMip Over Tcp).
MIB II per RFC1213
The standard lwIP stack management information base.
This is a required MIB, so this is always enabled.
When builing lwIP without TCP, the mib-2.tcp group is omitted.
The groups EGP, CMOT and transmission are disabled by default.
Most mib-2 objects are not writable except:
sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
Writing to or changing the ARP and IP address and route
tables is not possible.
Note lwIP has a very limited notion of IP routing. It currently
doen't have a route table and doesn't have a notion of the U,G,H flags.
Instead lwIP uses the interface list with only one default interface
acting as a single gateway interface (G) for the default route.
The agent returns a "virtual table" with the default route 0.0.0.0
for the default interface and network routes (no H) for each
network interface in the netif_list.
All routes are considered to be up (U).
Loading additional MIBs
MIBs can only be added in compile-time, not in run-time.
There is no MIB compiler thus additional MIBs must be hand coded.
Large SNMP message support
The packet decoding and encoding routines are designed
to use pbuf-chains. Larger payloads then the minimum
SNMP requirement of 484 octets are supported if the
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
local requirement.
1 Building the Agent
====================
First of all you'll need to add the following define
to your local lwipopts.h:
#define LWIP_SNMP 1
and add the source files in lwip/src/core/snmp
and some snmp headers in lwip/src/include/lwip to your makefile.
Note you'll might need to adapt you network driver to update
the mib2 variables for your interface.
2 Running the Agent
===================
The following function calls must be made in your program to
actually get the SNMP agent running.
Before starting the agent you should supply pointers
to non-volatile memory for sysContact, sysLocation,
and snmpEnableAuthenTraps. You can do this by calling
snmp_set_syscontact()
snmp_set_syslocation()
snmp_set_snmpenableauthentraps()
Additionally you may want to set
snmp_set_sysdescr()
snmp_set_sysobjid() (if you have a private MIB)
snmp_set_sysname()
Also before starting the agent you need to setup
one or more trap destinations using these calls:
snmp_trap_dst_enable();
snmp_trap_dst_ip_set();
In the lwIP initialisation sequence call snmp_init() just after
the call to udp_init().
Exactly every 10 msec the SNMP uptime timestamp must be updated with
snmp_inc_sysuptime(). You should call this from a timer interrupt
or a timer signal handler depending on your runtime environment.
An alternative way to update the SNMP uptime timestamp is to do a call like
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
when it's queried (any function which need "sysuptime" have to call
snmp_get_sysuptime).
3 Private MIBs
==============
If want to extend the agent with your own private MIB you'll need to
add the following define to your local lwipopts.h:
#define SNMP_PRIVATE_MIB 1
You must provide the private_mib.h and associated files yourself.
Note we don't have a "MIB compiler" that generates C source from a MIB,
so you're required to do some serious coding if you enable this!
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
MAINTAINERS!
If you need to create your own private MIB you'll need
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
You can set it by passing a struct snmp_obj_id to the agent
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
Note the object identifiers for thes MIB-2 and your private MIB
tree must be kept in sorted ascending (lexicographical) order.
This to ensure correct getnext operation.
An example for a private MIB is part of the "minimal Unix" project:
contrib/ports/unix/proj/minimal/lwip_prvmib.c
The next chapter gives a more detailed description of the
MIB-2 tree and the optional private MIB.
4 The Gory Details
==================
4.0 Object identifiers and the MIB tree.
We have three distinct parts for all object identifiers:
The prefix
.iso.org.dod.internet
the middle part
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
and the index part
.1.192.168.0.1
Objects located above the .internet hierarchy aren't supported.
Currently only the .mgmt sub-tree is available and
when the SNMP_PRIVATE_MIB is enabled the .private tree
becomes available too.
Object identifiers from incoming requests are checked
for a matching prefix, middle part and index part
or are expanded(*) for GetNext requests with short
or inexisting names in the request.
(* we call this "expansion" but this also
resembles the "auto-completion" operation)
The middle part is usually located in ROM (const)
to preserve precious RAM on small microcontrollers.
However RAM location is possible for an dynamically
changing private tree.
The index part is handled by functions which in
turn use dynamically allocated index trees from RAM.
These trees are updated by e.g. the etharp code
when new entries are made or removed form the ARP cache.
/** @todo more gory details */

View File

@@ -0,0 +1,228 @@
sys_arch interface for lwIP 0.6++
Author: Adam Dunkels
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
general idea is that porting lwIP to new architectures requires only
small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores and mailboxes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Previous versions of lwIP required the sys_arch to
implement timer scheduling as well but as of lwIP 0.5 this is
implemented in a higher layer.
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes are used for message passing and can be implemented
either as a queue which allows multiple messages to be posted to a
mailbox, or as a rendez-vous point where only one message can be
posted at a time. lwIP works with both kinds, but the former type will
be more efficient. A message in a mailbox is just a pointer, nothing
more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how
sys_sem_t or sys_mbox_t are represented internally.
The following functions must be implemented by the sys_arch:
- void sys_init(void)
Is called to initialize the sys_arch layer.
- sys_sem_t sys_sem_new(u8_t count)
Creates and returns a new semaphore. The "count" argument specifies
the initial state of the semaphore.
- void sys_sem_free(sys_sem_t sem)
Deallocates a semaphore.
- void sys_sem_signal(sys_sem_t sem)
Signals a semaphore.
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds). If the "timeout" argument is zero, the thread should be
blocked until the semaphore is signalled.
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
- sys_mbox_t sys_mbox_new(int size)
Creates an empty mailbox for maximum "size" elements. Elements stored
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
in your lwipopts.h, or ignore this parameter in your implementation
and use a default size.
- void sys_mbox_free(sys_mbox_t mbox)
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
Posts the "msg" to the mailbox. This function have to block until
the "msg" is really posted.
- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
is full, else, ERR_OK if the "msg" is posted.
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
be blocked until a message arrives. The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
This is similar to sys_arch_mbox_fetch, however if a message is not
present in the mailbox, it immediately returns with the code
SYS_MBOX_EMPTY. On success 0 is returned.
To allow for efficient implementations, this can be defined as a
function-like macro in sys_arch.h instead of a normal function. For
example, a naive implementation could be:
#define sys_arch_mbox_tryfetch(mbox,msg) \
sys_arch_mbox_fetch(mbox,msg,1)
although this would introduce unnecessary delays.
- struct sys_timeouts *sys_arch_timeouts(void)
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
each thread has a list of timeouts which is repressented as a linked
list of sys_timeout structures. The sys_timeouts structure holds a
pointer to a linked list of timeouts. This function is called by
the lwIP timeout scheduler and must not return a NULL value.
In a single thread sys_arch implementation, this function will
simply return a pointer to a global sys_timeouts variable stored in
the sys_arch module.
If threads are supported by the underlying operating system and if
such functionality is needed in lwIP, the following function will have
to be implemented as well:
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
Starts a new thread named "name" with priority "prio" that will begin its
execution in the function "thread()". The "arg" argument will be passed as an
argument to the thread() function. The stack size to used for this thread is
the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent.
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
- void sys_arch_unprotect(sys_prot_t pval)
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
Note:
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
mem_malloc() you can run into a circular function call problem. In mem.c
mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc.
-------------------------------------------------------------------------------
Additional files required for the "OS support" emulation layer:
-------------------------------------------------------------------------------
cc.h - Architecture environment, some compiler specific, some
environment specific (probably should move env stuff
to sys_arch.h.)
Typedefs for the types used by lwip -
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
Compiler hints for packing lwip's structures -
PACK_STRUCT_FIELD(x)
PACK_STRUCT_STRUCT
PACK_STRUCT_BEGIN
PACK_STRUCT_END
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
Portability defines for printf formatters:
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
"lightweight" synchronization mechanisms -
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
SYS_ARCH_PROTECT(x) - enter protection mode.
SYS_ARCH_UNPROTECT(x) - leave protection mode.
If the compiler does not provide memset() this file must include a
definition of it, or include a file which defines it.
This file must either include a system-local <errno.h> which defines
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
to make lwip/arch.h define the codes which are used throughout.
perf.h - Architecture specific performance measurement.
Measurement calls made throughout lwip, these can be defined to nothing.
PERF_START - start measuring something.
PERF_STOP(x) - stop measuring something, and record the result.
sys_arch.h - Tied to sys_arch.c
Arch dependent types for the following objects:
sys_sem_t, sys_mbox_t, sys_thread_t,
And, optionally:
sys_prot_t
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
SYS_MBOX_NULL NULL
SYS_SEM_NULL NULL

View File

@@ -0,0 +1,26 @@
syntax: glob
*.pyc
*.orig
*.rej
*~
TAGS
Module.symvers
*.ncb
*.suo
*.bak
*.orig
*.rej
syntax: regexp
\.\#.+
[\\/]CVS$
^CVS$
^build$
^install$
^logs.build_tree$
[\\/]bin$
^bin$
[\\/]obj$
^obj$
\.cvsignore

View File

@@ -0,0 +1,13 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here,
as well as the ARP module.
For more information on the various subdirectories, check the FILES
file in each directory.

View File

@@ -0,0 +1,557 @@
/**
* @file
* Sequential API External module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* This is the part of the API that is linked with
the application */
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include <string.h>
/**
* Create a new netconn (of a specific type) that has a callback function.
* The corresponding pcb is also created.
*
* @param t the type of 'connection' to create (@see enum netconn_type)
* @param proto the IP protocol for RAW IP pcbs
* @param callback a function to call on status changes (RX available, TX'ed)
* @return a newly allocated struct netconn or
* NULL on memory error
*/
struct netconn*
netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
{
struct netconn *conn;
struct api_msg msg;
conn = netconn_alloc(t, callback);
if (conn != NULL ) {
msg.function = do_newconn;
msg.msg.msg.n.proto = proto;
msg.msg.conn = conn;
TCPIP_APIMSG(&msg);
if (conn->err != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);
sys_sem_free(conn->op_completed);
sys_mbox_free(conn->recvmbox);
memp_free(MEMP_NETCONN, conn);
return NULL;
}
}
return conn;
}
/**
* Close a netconn 'connection' and free its resources.
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
* after this returns.
*
* @param conn the netconn to delete
* @return ERR_OK if the connection was deleted
*/
err_t
netconn_delete(struct netconn *conn)
{
struct api_msg msg;
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
if (conn == NULL) {
return ERR_OK;
}
msg.function = do_delconn;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
conn->pcb.tcp = NULL;
netconn_free(conn);
return ERR_OK;
}
/**
* Get the local or remote IP address and port of a netconn.
* For RAW netconns, this returns the protocol instead of a port!
*
* @param conn the netconn to query
* @param addr a pointer to which to save the IP address
* @param port a pointer to which to save the port (or protocol for RAW)
* @param local 1 to get the local IP address, 0 to get the remote one
* @return ERR_CONN for invalid connections
* ERR_OK if the information was retrieved
*/
err_t
netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)
{
struct api_msg msg;
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
msg.function = do_getaddr;
msg.msg.conn = conn;
msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.port = port;
msg.msg.msg.ad.local = local;
TCPIP_APIMSG(&msg);
return conn->err;
}
/**
* Bind a netconn to a specific local IP address and port.
* Binding one netconn twice might not always be checked correctly!
*
* @param conn the netconn to bind
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
* to bind to all addresses)
* @param port the local port to bind the netconn to (not used for RAW)
* @return ERR_OK if bound, any other err_t on failure
*/
err_t
netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
{
struct api_msg msg;
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_bind;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
TCPIP_APIMSG(&msg);
return conn->err;
}
/**
* Connect a netconn to a specific remote IP address and port.
*
* @param conn the netconn to connect
* @param addr the remote IP address to connect to
* @param port the remote port to connect to (no used for RAW)
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
*/
err_t
netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
{
struct api_msg msg;
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_connect;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
/* This is the only function which need to not block tcpip_thread */
tcpip_apimsg(&msg);
return conn->err;
}
/**
* Disconnect a netconn from its current peer (only valid for UDP netconns).
*
* @param conn the netconn to disconnect
* @return TODO: return value is not set here...
*/
err_t
netconn_disconnect(struct netconn *conn)
{
struct api_msg msg;
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_disconnect;
msg.msg.conn = conn;
TCPIP_APIMSG(&msg);
return conn->err;
}
/**
* Set a TCP netconn into listen mode
*
* @param conn the tcp netconn to set to listen mode
* @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
* @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
* don't return any error (yet?))
*/
err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
struct api_msg msg;
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_listen;
msg.msg.conn = conn;
#if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */
TCPIP_APIMSG(&msg);
return conn->err;
}
/**
* Accept a new connection on a TCP listening netconn.
*
* @param conn the TCP listen netconn
* @return the newly accepted netconn or NULL on timeout
*/
struct netconn *
netconn_accept(struct netconn *conn)
{
struct netconn *newconn;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
newconn = NULL;
} else
#else
sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/
{
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
#if TCP_LISTEN_BACKLOG
if (newconn != NULL) {
/* Let the stack know that we have accepted the connection. */
struct api_msg msg;
msg.function = do_recv;
msg.msg.conn = conn;
TCPIP_APIMSG(&msg);
}
#endif /* TCP_LISTEN_BACKLOG */
}
return newconn;
}
/**
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
*
* @param conn the netconn from which to receive data
* @return a new netbuf containing received data or NULL on memory error or timeout
*/
struct netbuf *
netconn_recv(struct netconn *conn)
{
struct api_msg msg;
struct netbuf *buf = NULL;
struct pbuf *p;
u16_t len;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;);
if (conn->recvmbox == SYS_MBOX_NULL) {
/* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */
/* TCP listen conns don't have a recvmbox! */
conn->err = ERR_CONN;
return NULL;
}
if (ERR_IS_FATAL(conn->err)) {
return NULL;
}
if (conn->type == NETCONN_TCP) {
#if LWIP_TCP
if (conn->state == NETCONN_LISTEN) {
/* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */
conn->err = ERR_CONN;
return NULL;
}
buf = memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
conn->err = ERR_MEM;
return NULL;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
conn->err = ERR_TIMEOUT;
p = NULL;
}
#else
sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
#endif /* LWIP_SO_RCVTIMEO*/
if (p != NULL) {
len = p->tot_len;
SYS_ARCH_DEC(conn->recv_avail, len);
} else {
len = 0;
}
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
/* If we are closed, we indicate that we no longer wish to use the socket */
if (p == NULL) {
memp_free(MEMP_NETBUF, buf);
/* Avoid to lose any previous error code */
if (conn->err == ERR_OK) {
conn->err = ERR_CLSD;
}
return NULL;
}
buf->p = p;
buf->ptr = p;
buf->port = 0;
buf->addr = NULL;
/* Let the stack know that we have taken the data. */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = buf->p->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
TCPIP_APIMSG(&msg);
#endif /* LWIP_TCP */
} else {
#if (LWIP_UDP || LWIP_RAW)
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
buf = NULL;
}
#else
sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);
#endif /* LWIP_SO_RCVTIMEO*/
if (buf!=NULL) {
SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
}
#endif /* (LWIP_UDP || LWIP_RAW) */
}
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
return buf;
}
/**
* Send data (in form of a netbuf) to a specific remote IP address and port.
* Only to be used for UDP and RAW netconns (not TCP).
*
* @param conn the netconn over which to send data
* @param buf a netbuf containing the data to send
* @param addr the remote IP address to which to send the data
* @param port the remote port to which to send the data
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)
{
if (buf != NULL) {
buf->addr = addr;
buf->port = port;
return netconn_send(conn, buf);
}
return ERR_VAL;
}
/**
* Send data over a UDP or RAW netconn (that is already connected).
*
* @param conn the UDP or RAW netconn over which to send data
* @param buf a netbuf containing the data to send
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_send(struct netconn *conn, struct netbuf *buf)
{
struct api_msg msg;
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
msg.function = do_send;
msg.msg.conn = conn;
msg.msg.msg.b = buf;
TCPIP_APIMSG(&msg);
return conn->err;
}
/**
* Send data over a TCP netconn.
*
* @param conn the TCP netconn over which to send data
* @param dataptr pointer to the application buffer that contains the data to send
* @param size size of the application data to send
* @param apiflags combination of following flags :
* - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack
* - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
{
struct api_msg msg;
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
msg.function = do_write;
msg.msg.conn = conn;
msg.msg.msg.w.dataptr = dataptr;
msg.msg.msg.w.apiflags = apiflags;
msg.msg.msg.w.len = size;
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
but if it is, this is done inside api_msg.c:do_write(), so we can use the
non-blocking version here. */
TCPIP_APIMSG(&msg);
return conn->err;
}
/**
* Close a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to close
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
err_t
netconn_close(struct netconn *conn)
{
struct api_msg msg;
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
return conn->err;
}
#if LWIP_IGMP
/**
* Join multicast groups for UDP netconns.
*
* @param conn the UDP netconn for which to change multicast addresses
* @param multiaddr IP address of the multicast group to join or leave
* @param interface the IP address of the network interface on which to send
* the igmp message
* @param join_or_leave flag whether to send a join- or leave-message
* @return ERR_OK if the action was taken, any err_t on error
*/
err_t
netconn_join_leave_group(struct netconn *conn,
struct ip_addr *multiaddr,
struct ip_addr *interface,
enum netconn_igmp join_or_leave)
{
struct api_msg msg;
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_join_leave_group;
msg.msg.conn = conn;
msg.msg.msg.jl.multiaddr = multiaddr;
msg.msg.msg.jl.interface = interface;
msg.msg.msg.jl.join_or_leave = join_or_leave;
TCPIP_APIMSG(&msg);
return conn->err;
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Execute a DNS query, only one IP address is returned
*
* @param name a string representation of the DNS host name to query
* @param addr a preallocated struct ip_addr where to store the resolved IP address
* @return ERR_OK: resolving succeeded
* ERR_MEM: memory error, try again later
* ERR_ARG: dns client not initialized or invalid hostname
* ERR_VAL: dns server response was invalid
*/
err_t
netconn_gethostbyname(const char *name, struct ip_addr *addr)
{
struct dns_api_msg msg;
err_t err;
sys_sem_t sem;
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
sem = sys_sem_new(0);
if (sem == SYS_SEM_NULL) {
return ERR_MEM;
}
msg.name = name;
msg.addr = addr;
msg.err = &err;
msg.sem = sem;
tcpip_callback(do_gethostbyname, &msg);
sys_sem_wait(sem);
sys_sem_free(sem);
return err;
}
#endif /* LWIP_DNS*/
#endif /* LWIP_NETCONN */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
/**
* @file
* Error Management module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/err.h"
#ifdef LWIP_DEBUG
static const char *err_strerr[] = {
"Ok.", /* ERR_OK 0 */
"Out of memory error.", /* ERR_MEM -1 */
"Buffer error.", /* ERR_BUF -2 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Routing problem.", /* ERR_RTE -4 */
"Connection aborted.", /* ERR_ABRT -5 */
"Connection reset.", /* ERR_RST -6 */
"Connection closed.", /* ERR_CLSD -7 */
"Not connected.", /* ERR_CONN -8 */
"Illegal value.", /* ERR_VAL -9 */
"Illegal argument.", /* ERR_ARG -10 */
"Address in use.", /* ERR_USE -11 */
"Low-level netif error.", /* ERR_IF -12 */
"Already connected.", /* ERR_ISCONN -13 */
"Operation in progress." /* ERR_INPROGRESS -14 */
};
/**
* Convert an lwip internal error to a string representation.
*
* @param err an lwip internal err_t
* @return a string representation for err
*/
const char *
lwip_strerr(err_t err)
{
return err_strerr[-err];
}
#endif /* LWIP_DEBUG */

View File

@@ -0,0 +1,235 @@
/**
* @file
* Network buffer management
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include "lwip/netbuf.h"
#include "lwip/memp.h"
#include <string.h>
/**
* Create (allocate) and initialize a new netbuf.
* The netbuf doesn't yet contain a packet buffer!
*
* @return a pointer to a new netbuf
* NULL on lack of memory
*/
struct
netbuf *netbuf_new(void)
{
struct netbuf *buf;
buf = memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
buf->addr = NULL;
return buf;
} else {
return NULL;
}
}
/**
* Deallocate a netbuf allocated by netbuf_new().
*
* @param buf pointer to a netbuf allocated by netbuf_new()
*/
void
netbuf_delete(struct netbuf *buf)
{
if (buf != NULL) {
if (buf->p != NULL) {
pbuf_free(buf->p);
buf->p = buf->ptr = NULL;
}
memp_free(MEMP_NETBUF, buf);
}
}
/**
* Allocate memory for a packet buffer for a given netbuf.
*
* @param buf the netbuf for which to allocate a packet buffer
* @param size the size of the packet buffer to allocate
* @return pointer to the allocated memory
* NULL if no memory could be allocated
*/
void *
netbuf_alloc(struct netbuf *buf, u16_t size)
{
LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
/* Deallocate any previously allocated memory. */
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
if (buf->p == NULL) {
return NULL;
}
LWIP_ASSERT("check that first pbuf can hold size",
(buf->p->len >= size));
buf->ptr = buf->p;
return buf->p->payload;
}
/**
* Free the packet buffer included in a netbuf
*
* @param buf pointer to the netbuf which contains the packet buffer to free
*/
void
netbuf_free(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = buf->ptr = NULL;
}
/**
* Let a netbuf reference existing (non-volatile) data.
*
* @param buf netbuf which should reference the data
* @param dataptr pointer to the data to reference
* @param size size of the data
* @return ERR_OK if data is referenced
* ERR_MEM if data couldn't be referenced due to lack of memory
*/
err_t
netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
{
LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
if (buf->p == NULL) {
buf->ptr = NULL;
return ERR_MEM;
}
buf->p->payload = (void*)dataptr;
buf->p->len = buf->p->tot_len = size;
buf->ptr = buf->p;
return ERR_OK;
}
/**
* Chain one netbuf to another (@see pbuf_chain)
*
* @param head the first netbuf
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
*/
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_cat(head->p, tail->p);
head->ptr = head->p;
memp_free(MEMP_NETBUF, tail);
}
/**
* Get the data pointer and length of the data inside a netbuf.
*
* @param buf netbuf to get the data from
* @param dataptr pointer to a void pointer where to store the data pointer
* @param len pointer to an u16_t where the length of the data is stored
* @return ERR_OK if the information was retreived,
* ERR_BUF on error.
*/
err_t
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
{
LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
if (buf->ptr == NULL) {
return ERR_BUF;
}
*dataptr = buf->ptr->payload;
*len = buf->ptr->len;
return ERR_OK;
}
/**
* Move the current data pointer of a packet buffer contained in a netbuf
* to the next part.
* The packet buffer itself is not modified.
*
* @param buf the netbuf to modify
* @return -1 if there is no next part
* 1 if moved to the next part but now there is no next part
* 0 if moved to the next part and there are still more parts
*/
s8_t
netbuf_next(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
if (buf->ptr->next == NULL) {
return -1;
}
buf->ptr = buf->ptr->next;
if (buf->ptr->next == NULL) {
return 1;
}
return 0;
}
/**
* Move the current data pointer of a packet buffer contained in a netbuf
* to the beginning of the packet.
* The packet buffer itself is not modified.
*
* @param buf the netbuf to modify
*/
void
netbuf_first(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
buf->ptr = buf->p;
}
#endif /* LWIP_NETCONN */

View File

@@ -0,0 +1,356 @@
/**
* @file
* API functions for name resolving
*
*/
/*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#include "lwip/netdb.h"
#if LWIP_DNS && LWIP_SOCKET
#include "lwip/err.h"
#include "lwip/mem.h"
#include "lwip/ip_addr.h"
#include "lwip/api.h"
#include <string.h>
#include <stdlib.h>
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
struct ip_addr *addrs;
struct ip_addr addr;
char *aliases;
};
/** h_errno is exported in netdb.h for access by applications. */
#if LWIP_DNS_API_DECLARE_H_ERRNO
int h_errno;
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
/** define "hostent" variables storage: 0 if we use a static (but unprotected)
* set of variables for lwip_gethostbyname, 1 if we use a local storage */
#ifndef LWIP_DNS_API_HOSTENT_STORAGE
#define LWIP_DNS_API_HOSTENT_STORAGE 0
#endif
/** define "hostent" variables storage */
#if LWIP_DNS_API_HOSTENT_STORAGE
#define HOSTENT_STORAGE
#else
#define HOSTENT_STORAGE static
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
/**
* Returns an entry containing addresses of address family AF_INET
* for the host with name name.
* Due to dns_gethostbyname limitations, only one address is returned.
*
* @param name the hostname to resolve
* @return an entry containing addresses of address family AF_INET
* for the host with name name
*/
struct hostent*
lwip_gethostbyname(const char *name)
{
err_t err;
struct ip_addr addr;
/* buffer variables for lwip_gethostbyname() */
HOSTENT_STORAGE struct hostent s_hostent;
HOSTENT_STORAGE char *s_aliases;
HOSTENT_STORAGE struct ip_addr s_hostent_addr;
HOSTENT_STORAGE struct ip_addr *s_phostent_addr;
/* query host IP address */
err = netconn_gethostbyname(name, &addr);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
h_errno = HOST_NOT_FOUND;
return NULL;
}
/* fill hostent */
s_hostent_addr = addr;
s_phostent_addr = &s_hostent_addr;
s_hostent.h_name = (char*)name;
s_hostent.h_aliases = &s_aliases;
s_hostent.h_addrtype = AF_INET;
s_hostent.h_length = sizeof(struct ip_addr);
s_hostent.h_addr_list = (char**)&s_phostent_addr;
#if DNS_DEBUG
/* dump hostent */
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
if (s_hostent.h_aliases != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
}
}
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
if (s_hostent.h_addr_list != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
}
}
#endif /* DNS_DEBUG */
#if LWIP_DNS_API_HOSTENT_STORAGE
/* this function should return the "per-thread" hostent after copy from s_hostent */
return sys_thread_hostent(&s_hostent);
#else
return &s_hostent;
#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
}
/**
* Thread-safe variant of lwip_gethostbyname: instead of using a static
* buffer, this function takes buffer and errno pointers as arguments
* and uses these for the result.
*
* @param name the hostname to resolve
* @param ret pre-allocated struct where to store the result
* @param buf pre-allocated buffer where to store additional data
* @param buflen the size of buf
* @param result pointer to a hostent pointer that is set to ret on success
* and set to zero on error
* @param h_errnop pointer to an int where to store errors (instead of modifying
* the global h_errno)
* @return 0 on success, non-zero on error, additional error information
* is stored in *h_errnop instead of h_errno to be thread-safe
*/
int
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
size_t buflen, struct hostent **result, int *h_errnop)
{
err_t err;
struct gethostbyname_r_helper *h;
char *hostname;
size_t namelen;
int lh_errno;
if (h_errnop == NULL) {
/* ensure h_errnop is never NULL */
h_errnop = &lh_errno;
}
if (result == NULL) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
/* first thing to do: set *result to nothing */
*result = NULL;
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
namelen = strlen(name);
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
/* buf can't hold the data needed + a copy of name */
*h_errnop = ERANGE;
return -1;
}
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
/* query host IP address */
err = netconn_gethostbyname(name, &(h->addr));
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
*h_errnop = ENSRNOTFOUND;
return -1;
}
/* copy the hostname into buf */
MEMCPY(hostname, name, namelen);
hostname[namelen] = 0;
/* fill hostent */
h->addrs = &(h->addr);
h->aliases = NULL;
ret->h_name = (char*)hostname;
ret->h_aliases = &(h->aliases);
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(struct ip_addr);
ret->h_addr_list = (char**)&(h->addrs);
/* set result != NULL */
*result = ret;
/* return success */
return 0;
}
/**
* Frees one or more addrinfo structures returned by getaddrinfo(), along with
* any additional storage associated with those structures. If the ai_next field
* of the structure is not null, the entire list of structures is freed.
*
* @param ai struct addrinfo to free
*/
void
lwip_freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next;
while (ai != NULL) {
if (ai->ai_addr != NULL) {
mem_free(ai->ai_addr);
}
if (ai->ai_canonname != NULL) {
mem_free(ai->ai_canonname);
}
next = ai->ai_next;
mem_free(ai);
ai = next;
}
}
/**
* Translates the name of a service location (for example, a host name) and/or
* a service name and returns a set of socket addresses and associated
* information to be used in creating a socket with which to address the
* specified service.
* Memory for the result is allocated internally and must be freed by calling
* lwip_freeaddrinfo()!
*
* Due to a limitation in dns_gethostbyname, only the first address of a
* host is returned.
* Also, service names are not supported (only port numbers)!
*
* @param nodename descriptive name or address string of the host
* (may be NULL -> local address)
* @param servname port number as string of NULL
* @param hints structure containing input values that set socktype and protocol
* @param res pointer to a pointer where to store the result (set to NULL on failure)
* @return 0 on success, non-zero on failure
*/
int
lwip_getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
err_t err;
struct ip_addr addr;
struct addrinfo *ai;
struct sockaddr_in *sa = NULL;
int port_nr = 0;
if (res == NULL) {
return EAI_FAIL;
}
*res = NULL;
if ((nodename == NULL) && (servname == NULL)) {
return EAI_NONAME;
}
if (servname != NULL) {
/* service name specified: convert to port number
* @todo?: currently, only ASCII integers (port numbers) are supported! */
port_nr = atoi(servname);
if ((port_nr <= 0) || (port_nr > 0xffff)) {
return EAI_SERVICE;
}
}
if (nodename != NULL) {
/* service location specified, try to resolve */
err = netconn_gethostbyname(nodename, &addr);
if (err != ERR_OK) {
return EAI_FAIL;
}
} else {
/* service location specified, use loopback address */
addr.addr = INADDR_LOOPBACK;
}
ai = mem_malloc(sizeof(struct addrinfo));
if (ai == NULL) {
goto memerr;
}
memset(ai, 0, sizeof(struct addrinfo));
sa = mem_malloc(sizeof(struct sockaddr_in));
if (sa == NULL) {
goto memerr;
}
memset(sa, 0, sizeof(struct sockaddr_in));
/* set up sockaddr */
sa->sin_addr.s_addr = addr.addr;
sa->sin_family = AF_INET;
sa->sin_len = sizeof(struct sockaddr_in);
sa->sin_port = htons(port_nr);
/* set up addrinfo */
ai->ai_family = AF_INET;
if (hints != NULL) {
/* copy socktype & protocol from hints if specified */
ai->ai_socktype = hints->ai_socktype;
ai->ai_protocol = hints->ai_protocol;
}
if (nodename != NULL) {
/* copy nodename to canonname if specified */
size_t namelen = strlen(nodename);
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
ai->ai_canonname = mem_malloc((mem_size_t)(namelen + 1));
if (ai->ai_canonname == NULL) {
goto memerr;
}
MEMCPY(ai->ai_canonname, nodename, namelen);
ai->ai_canonname[namelen] = 0;
}
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = (struct sockaddr*)sa;
*res = ai;
return 0;
memerr:
if (ai != NULL) {
mem_free(ai);
}
if (sa != NULL) {
mem_free(sa);
}
return EAI_MEMORY;
}
#endif /* LWIP_DNS && LWIP_SOCKET */

View File

@@ -0,0 +1,126 @@
/**
* @file
* Network Interface Sequential API module
*
*/
/*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
#include "lwip/netifapi.h"
#include "lwip/tcpip.h"
/**
* Call netif_add() inside the tcpip_thread context.
*/
void
do_netifapi_netif_add( struct netifapi_msg_msg *msg)
{
if (!netif_add( msg->netif,
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw,
msg->msg.add.state,
msg->msg.add.init,
msg->msg.add.input)) {
msg->err = ERR_IF;
} else {
msg->err = ERR_OK;
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
void
do_netifapi_netif_common( struct netifapi_msg_msg *msg)
{
if (msg->msg.common.errtfunc!=NULL) {
msg->err =
msg->msg.common.errtfunc(msg->netif);
} else {
msg->err = ERR_OK;
msg->msg.common.voidfunc(msg->netif);
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call netif_add() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @note for params @see netif_add()
*/
err_t
netifapi_netif_add(struct netif *netif,
struct ip_addr *ipaddr,
struct ip_addr *netmask,
struct ip_addr *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif))
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_add;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
msg.msg.msg.add.state = state;
msg.msg.msg.add.init = init;
msg.msg.msg.add.input = input;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
/**
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
* way by running that function inside the tcpip_thread context.
*
* @note use only for functions where there is only "netif" parameter.
*/
err_t
netifapi_netif_common( struct netif *netif,
void (* voidfunc)(struct netif *netif),
err_t (* errtfunc)(struct netif *netif) )
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_common;
msg.msg.netif = netif;
msg.msg.msg.common.voidfunc = voidfunc;
msg.msg.msg.common.errtfunc = errtfunc;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
#endif /* LWIP_NETIF_API */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,596 @@
/**
* @file
* Sequential API Main thread module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/ip_frag.h"
#include "lwip/tcp.h"
#include "lwip/autoip.h"
#include "lwip/dhcp.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
/* global variables */
static void (* tcpip_init_done)(void *arg);
static void *tcpip_init_done_arg;
static sys_mbox_t mbox = SYS_MBOX_NULL;
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
sys_sem_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_TCP
/* global variable that shows if the tcp timer is currently scheduled or not */
static int tcpip_tcp_timer_active;
/**
* Timer callback function that calls tcp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
tcpip_tcp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
#if !NO_SYS
/**
* Called from TCP_REG when registering a new PCB:
* the reason is to have the TCP timer only running when
* there are active (or time-wait) PCBs.
*/
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* !NO_SYS */
#endif /* LWIP_TCP */
#if IP_REASSEMBLY
/**
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
ip_reass_tmr();
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
}
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
/**
* Timer callback function that calls etharp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
arp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
#endif /* LWIP_ARP */
#if LWIP_DHCP
/**
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_coarse(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
dhcp_coarse_tmr();
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
}
/**
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_fine(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
dhcp_fine_tmr();
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/**
* Timer callback function that calls autoip_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
autoip_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
autoip_tmr();
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
}
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
/**
* Timer callback function that calls igmp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
igmp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
igmp_tmr();
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Timer callback function that calls dns_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dns_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));
dns_tmr();
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
}
#endif /* LWIP_DNS */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
* (unless access to them is not locked). Other threads communicate with this
* thread using message boxes.
*
* It also starts all the timers to make sure they are running in the right
* thread context.
*
* @param arg unused argument
*/
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
#if IP_REASSEMBLY
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
LOCK_TCPIP_CORE();
while (1) { /* MAIN Loop */
sys_mbox_fetch(mbox, (void *)&msg);
switch (msg->type) {
#if LWIP_NETCONN
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
#endif /* LWIP_NETCONN */
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ARP
if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ARP */
{ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
break;
#endif /* LWIP_NETIF_API */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.f(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_UNTIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
default:
break;
}
}
}
/**
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet, p->payload pointing to the Ethernet header or
* to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
* @param inp the network interface on which the packet was received
*/
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
}
return ERR_VAL;
}
/**
* Call a specific function in the thread context of
* tcpip_thread for easy access synchronization.
* A function called in that way may access lwIP core code
* without fearing concurrent access.
*
* @param f the function to call
* @param ctx parameter passed to f
* @param block 1 to block until the request is posted, 0 to non-blocking mode
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_CALLBACK;
msg->msg.cb.f = f;
msg->msg.cb.ctx = ctx;
if (block) {
sys_mbox_post(mbox, msg);
} else {
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, msg);
return ERR_MEM;
}
}
return ERR_OK;
}
return ERR_VAL;
}
/**
* call sys_timeout in tcpip_thread
*
* @param msec time in miliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
*/
err_t
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_TIMEOUT;
msg->msg.tmo.msecs = msecs;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
/**
* call sys_untimeout in tcpip_thread
*
* @param msec time in miliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
*/
err_t
tcpip_untimeout(sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_UNTIMEOUT;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
#if LWIP_NETCONN
/**
* Call the lower part of a netconn_* function
* This function is then running in the thread context
* of tcpip_thread and has exclusive access to lwIP core code.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_apimsg(struct api_msg *apimsg)
{
struct tcpip_msg msg;
if (mbox != SYS_MBOX_NULL) {
msg.type = TCPIP_MSG_API;
msg.msg.apimsg = apimsg;
sys_mbox_post(mbox, &msg);
sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);
return ERR_OK;
}
return ERR_VAL;
}
#if LWIP_TCPIP_CORE_LOCKING
/**
* Call the lower part of a netconn_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
*/
err_t
tcpip_apimsg_lock(struct api_msg *apimsg)
{
LOCK_TCPIP_CORE();
apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE();
return ERR_OK;
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
#if LWIP_NETIF_API
#if !LWIP_TCPIP_CORE_LOCKING
/**
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
* function.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return error code given back by the function that was called
*/
err_t
tcpip_netifapi(struct netifapi_msg* netifapimsg)
{
struct tcpip_msg msg;
if (mbox != SYS_MBOX_NULL) {
netifapimsg->msg.sem = sys_sem_new(0);
if (netifapimsg->msg.sem == SYS_SEM_NULL) {
netifapimsg->msg.err = ERR_MEM;
return netifapimsg->msg.err;
}
msg.type = TCPIP_MSG_NETIFAPI;
msg.msg.netifapimsg = netifapimsg;
sys_mbox_post(mbox, &msg);
sys_sem_wait(netifapimsg->msg.sem);
sys_sem_free(netifapimsg->msg.sem);
return netifapimsg->msg.err;
}
return ERR_VAL;
}
#else /* !LWIP_TCPIP_CORE_LOCKING */
/**
* Call the lower part of a netifapi_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
*/
err_t
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
{
LOCK_TCPIP_CORE();
netifapimsg->function(&(netifapimsg->msg));
UNLOCK_TCPIP_CORE();
return netifapimsg->msg.err;
}
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
/**
* Initialize this module:
* - initialize all sub modules
* - start the tcpip_thread
*
* @param initfunc a function to call when tcpip_thread is running and finished initializing
* @param arg argument to pass to initfunc
*/
void
tcpip_init(void (* initfunc)(void *), void *arg)
{
lwip_init();
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
mbox = sys_mbox_new(TCPIP_MBOX_SIZE);
#if LWIP_TCPIP_CORE_LOCKING
lock_tcpip_core = sys_sem_new(1);
#endif /* LWIP_TCPIP_CORE_LOCKING */
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}
/**
* Simple callback function used with tcpip_callback to free a pbuf
* (pbuf_free has a wrong signature for tcpip_callback)
*
* @param p The pbuf (chain) to be dereferenced.
*/
static void
pbuf_free_int(void *p)
{
struct pbuf *q = p;
pbuf_free(q);
}
/**
* A simple wrapper function that allows you to free a pbuf from interrupt context.
*
* @param p The pbuf (chain) to be dereferenced.
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
pbuf_free_callback(struct pbuf *p)
{
return tcpip_callback_with_block(pbuf_free_int, p, 0);
}
/**
* A simple wrapper function that allows you to free heap memory from
* interrupt context.
*
* @param m the heap memory to free
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
mem_free_callback(void *m)
{
return tcpip_callback_with_block(mem_free, m, 0);
}
#endif /* !NO_SYS */

Some files were not shown because too many files have changed in this diff Show More