mirror of
https://github.com/fairwaves/UHD-Fairwaves.git
synced 2025-11-02 13:03:13 +00:00
umtrx: moved new umtrx directory up one
This commit is contained in:
1
zpu/.gitignore
vendored
Normal file
1
zpu/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
4
zpu/AUTHORS
Normal file
4
zpu/AUTHORS
Normal 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
126
zpu/CMakeLists.txt
Normal 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
16
zpu/README
Normal 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
409
zpu/apps/txrx_uhd.c
Normal 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, ð_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
29
zpu/bin/bin_to_mif.py
Executable 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])
|
||||
39
zpu/bin/bin_to_ram_macro_init.py
Executable file
39
zpu/bin/bin_to_ram_macro_init.py
Executable 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
34
zpu/bin/divisors.py
Executable 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
142
zpu/bin/elf_to_sbf
Executable 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
134
zpu/bin/sbf.py
Executable 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
363
zpu/bin/serial_loader
Executable 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
138
zpu/bin/uart_ihex_flash_loader.py
Executable 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
70
zpu/bin/uart_ihex_ram_loader.py
Executable 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
50
zpu/lib/CMakeLists.txt
Normal 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
27
zpu/lib/_exit.c
Normal 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
32
zpu/lib/abort.c
Normal 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
42
zpu/lib/ad9510.c
Normal 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
30
zpu/lib/ad9510.h
Normal 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
90
zpu/lib/arp_cache.c
Normal 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
33
zpu/lib/arp_cache.h
Normal 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
31
zpu/lib/banal.c
Normal 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
71
zpu/lib/banal.h
Normal 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
118
zpu/lib/clocks.c
Normal 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
30
zpu/lib/clocks.h
Normal 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
26
zpu/lib/compiler.h
Normal 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
88
zpu/lib/eeprom.c
Normal 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
150
zpu/lib/eth_addrs.c
Normal 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
121
zpu/lib/eth_mac.c
Normal 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
32
zpu/lib/eth_mac.h
Normal 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
99
zpu/lib/ethernet.h
Normal 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
27
zpu/lib/ethertype.h
Normal 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
28
zpu/lib/exit.c
Normal 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
198
zpu/lib/gpsdo.c
Normal 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
30
zpu/lib/gpsdo.h
Normal 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
274
zpu/lib/hal_io.c
Normal 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
96
zpu/lib/hal_io.h
Normal 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
137
zpu/lib/hal_uart.c
Normal 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
92
zpu/lib/hal_uart.h
Normal 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
129
zpu/lib/i2c.c
Normal 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
39
zpu/lib/i2c.h
Normal 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
206
zpu/lib/i2c_async.c
Normal 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
50
zpu/lib/i2c_async.h
Normal 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
153
zpu/lib/if_arp.h
Normal 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
57
zpu/lib/ihex.c
Normal 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
18
zpu/lib/ihex.h
Normal 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
31
zpu/lib/mdelay.c
Normal 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
29
zpu/lib/mdelay.h
Normal 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
42
zpu/lib/memcpy_wa.c
Normal 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
32
zpu/lib/memcpy_wa.h
Normal 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
521
zpu/lib/memory_map.h
Normal 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
45
zpu/lib/memset_wa.c
Normal 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
27
zpu/lib/memset_wa.h
Normal 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 */
|
||||
29
zpu/lib/net/eth_mac_addr.h
Normal file
29
zpu/lib/net/eth_mac_addr.h
Normal 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 */
|
||||
37
zpu/lib/net/padded_eth_hdr.h
Normal file
37
zpu/lib/net/padded_eth_hdr.h
Normal 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 */
|
||||
41
zpu/lib/net/socket_address.h
Normal file
41
zpu/lib/net/socket_address.h
Normal 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
479
zpu/lib/net_common.c
Normal 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(ð_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
58
zpu/lib/net_common.h
Normal 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
123
zpu/lib/nonstdio.c
Normal 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
47
zpu/lib/nonstdio.h
Normal 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
89
zpu/lib/pic.c
Normal 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
36
zpu/lib/pic.h
Normal 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
100
zpu/lib/pkt_ctrl.c
Normal 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
63
zpu/lib/pkt_ctrl.h
Normal 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
33
zpu/lib/print_addrs.c
Normal 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
36
zpu/lib/print_buffer.c
Normal 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
44
zpu/lib/print_rmon_regs.c
Normal 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
24
zpu/lib/print_rmon_regs.h
Normal 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
134
zpu/lib/printf.c
Normal 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
134
zpu/lib/printf.c.smaller
Normal 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
110
zpu/lib/spi.c
Normal 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
77
zpu/lib/spi.h
Normal 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
34
zpu/lib/stdint.h
Normal 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
38
zpu/lib/stdio.h
Normal 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
88
zpu/lib/u2_init.c
Normal 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
28
zpu/lib/u2_init.h
Normal 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
75
zpu/lib/udp_fw_update.h
Normal 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
116
zpu/lib/udp_uart.c
Normal 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
36
zpu/lib/udp_uart.h
Normal 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
70
zpu/lib/umtrx_init.c
Normal 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
28
zpu/lib/umtrx_init.h
Normal 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 */
|
||||
2248
zpu/lwip/lwip-1.3.1/CHANGELOG
Normal file
2248
zpu/lwip/lwip-1.3.1/CHANGELOG
Normal file
File diff suppressed because it is too large
Load Diff
33
zpu/lwip/lwip-1.3.1/COPYING
Normal file
33
zpu/lwip/lwip-1.3.1/COPYING
Normal 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>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
4
zpu/lwip/lwip-1.3.1/FILES
Normal file
4
zpu/lwip/lwip-1.3.1/FILES
Normal 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.
|
||||
89
zpu/lwip/lwip-1.3.1/README
Normal file
89
zpu/lwip/lwip-1.3.1/README
Normal 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>
|
||||
|
||||
6
zpu/lwip/lwip-1.3.1/doc/FILES
Normal file
6
zpu/lwip/lwip-1.3.1/doc/FILES
Normal 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.
|
||||
63
zpu/lwip/lwip-1.3.1/doc/contrib.txt
Normal file
63
zpu/lwip/lwip-1.3.1/doc/contrib.txt
Normal 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.
|
||||
|
||||
478
zpu/lwip/lwip-1.3.1/doc/rawapi.txt
Normal file
478
zpu/lwip/lwip-1.3.1/doc/rawapi.txt
Normal 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.
|
||||
135
zpu/lwip/lwip-1.3.1/doc/savannah.txt
Normal file
135
zpu/lwip/lwip-1.3.1/doc/savannah.txt
Normal 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.
|
||||
181
zpu/lwip/lwip-1.3.1/doc/snmp_agent.txt
Normal file
181
zpu/lwip/lwip-1.3.1/doc/snmp_agent.txt
Normal 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 */
|
||||
228
zpu/lwip/lwip-1.3.1/doc/sys_arch.txt
Normal file
228
zpu/lwip/lwip-1.3.1/doc/sys_arch.txt
Normal 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
|
||||
26
zpu/lwip/lwip-1.3.1/src/.hgignore
Normal file
26
zpu/lwip/lwip-1.3.1/src/.hgignore
Normal 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
|
||||
13
zpu/lwip/lwip-1.3.1/src/FILES
Normal file
13
zpu/lwip/lwip-1.3.1/src/FILES
Normal 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.
|
||||
557
zpu/lwip/lwip-1.3.1/src/api/api_lib.c
Normal file
557
zpu/lwip/lwip-1.3.1/src/api/api_lib.c
Normal 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 */
|
||||
1232
zpu/lwip/lwip-1.3.1/src/api/api_msg.c
Normal file
1232
zpu/lwip/lwip-1.3.1/src/api/api_msg.c
Normal file
File diff suppressed because it is too large
Load Diff
74
zpu/lwip/lwip-1.3.1/src/api/err.c
Normal file
74
zpu/lwip/lwip-1.3.1/src/api/err.c
Normal 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 */
|
||||
235
zpu/lwip/lwip-1.3.1/src/api/netbuf.c
Normal file
235
zpu/lwip/lwip-1.3.1/src/api/netbuf.c
Normal 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 */
|
||||
356
zpu/lwip/lwip-1.3.1/src/api/netdb.c
Normal file
356
zpu/lwip/lwip-1.3.1/src/api/netdb.c
Normal 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 */
|
||||
126
zpu/lwip/lwip-1.3.1/src/api/netifapi.c
Normal file
126
zpu/lwip/lwip-1.3.1/src/api/netifapi.c
Normal 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 */
|
||||
1970
zpu/lwip/lwip-1.3.1/src/api/sockets.c
Normal file
1970
zpu/lwip/lwip-1.3.1/src/api/sockets.c
Normal file
File diff suppressed because it is too large
Load Diff
596
zpu/lwip/lwip-1.3.1/src/api/tcpip.c
Normal file
596
zpu/lwip/lwip-1.3.1/src/api/tcpip.c
Normal 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
Reference in New Issue
Block a user