mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
OctoClock bugfixes
* Bumped compatibility version to 3 * firmware: Ethernet, clkdist bugfixes * lib: fixed invalid rev detection
This commit is contained in:
parent
1449687bb4
commit
d9656de88f
@ -31,7 +31,7 @@ if(NOT DEFINED PROGRAMMER)
|
||||
endif(NOT DEFINED PROGRAMMER)
|
||||
|
||||
if(OCTOCLOCK_DEBUG)
|
||||
message(STATUS "Debug enabled. Interrupts will be disabled.")
|
||||
message(STATUS "Debug enabled.")
|
||||
add_definitions(-DDEBUG)
|
||||
endif(OCTOCLOCK_DEBUG)
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ add_custom_target(
|
||||
|
||||
add_custom_target(
|
||||
upload_bootloader
|
||||
${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xFF:m -U flash:w:octoclock_bootloader.hex:i
|
||||
${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xEF:m -U flash:w:octoclock_bootloader.hex:i
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS octoclock_bootloader_hex
|
||||
COMMENT "Uploading OctoClock bootloader to device with ${PROGRAMMER}"
|
||||
|
||||
@ -23,13 +23,13 @@
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#include <avrlibdefs.h>
|
||||
#include <octoclock.h>
|
||||
#include <debug.h>
|
||||
#include <network.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <net/enc28j60.h>
|
||||
|
||||
#include "octoclock/common.h"
|
||||
@ -40,10 +40,19 @@
|
||||
*/
|
||||
#define TIME_PASSED (TCNT1 > (TIMER1_ONE_SECOND*5) || (TIFR & _BV(TOV1)))
|
||||
|
||||
//States
|
||||
static bool received_cmd = false;
|
||||
static bool done_burning = false;
|
||||
/*
|
||||
* States
|
||||
*/
|
||||
static bool received_cmd = false; // Received "PREPARE_FW_BURN_CMD" signal
|
||||
static bool done_burning = false; // Received "FINALIZE_BURNING_CMD" signal
|
||||
static bool app_checked = false; // Ran validation check on firmware
|
||||
|
||||
/*
|
||||
* After new firmware is burned onto the device, the bootloader calculates its
|
||||
* CRC and burns it into the EEPROM. When the device boots, this CRC is used
|
||||
* to validate the firmware before loading it. This struct represents how the
|
||||
* information is stored in the EEPROM.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t fw_len;
|
||||
uint16_t fw_crc;
|
||||
@ -51,15 +60,22 @@ typedef struct {
|
||||
|
||||
static crc_info_t crc_info;
|
||||
|
||||
/*
|
||||
* What actually burns the firmware onto the device.
|
||||
*
|
||||
* Source: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__boot.html
|
||||
*/
|
||||
static void boot_program_page(uint8_t *buf, uint16_t page){
|
||||
uint16_t i;
|
||||
// Disable interrupts
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
|
||||
eeprom_busy_wait();
|
||||
|
||||
boot_page_erase(page);
|
||||
boot_spm_busy_wait(); // Wait until the memory is erased.
|
||||
|
||||
for(i = 0; i < SPM_PAGESIZE; i += 2){
|
||||
for(uint16_t i = 0; i < SPM_PAGESIZE; i += 2){
|
||||
// Set up little-endian word.
|
||||
uint16_t w = *buf++;
|
||||
w += ((*buf++) << 8);
|
||||
@ -68,36 +84,31 @@ static void boot_program_page(uint8_t *buf, uint16_t page){
|
||||
}
|
||||
|
||||
boot_page_write(page); // Store buffer in flash page.
|
||||
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||
|
||||
// Reenable RWW-section again. We need this if we want to jump back
|
||||
// to the application after bootloading.
|
||||
boot_rww_enable();
|
||||
|
||||
// Restore interrupt state
|
||||
SREG = sreg;
|
||||
sei();
|
||||
}
|
||||
|
||||
/*
|
||||
* Load firmware at given address into packet to send to host.
|
||||
*/
|
||||
static void read_firmware(uint16_t addr, octoclock_packet_t *pkt_out){
|
||||
for(size_t i = 0; i < SPM_PAGESIZE; i++){
|
||||
pkt_out->data[i] = pgm_read_byte(addr+i);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_udp_query_packet(
|
||||
struct socket_address src, struct socket_address dst,
|
||||
unsigned char *payload, int payload_len
|
||||
){
|
||||
const octoclock_packet_t *pkt_in = (octoclock_packet_t*)payload;
|
||||
|
||||
//Respond to query packets
|
||||
if(pkt_in->code == OCTOCLOCK_QUERY_CMD){
|
||||
octoclock_packet_t pkt_out;
|
||||
pkt_out.proto_ver = OCTOCLOCK_BOOTLOADER_PROTO_VER;
|
||||
pkt_out.sequence = pkt_in->sequence;
|
||||
pkt_out.code = OCTOCLOCK_QUERY_ACK;
|
||||
pkt_out.len = 0;
|
||||
send_udp_pkt(OCTOCLOCK_UDP_CTRL_PORT, src, (void*)&pkt_out, sizeof(octoclock_packet_t));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the CRC of the current firmware.
|
||||
*
|
||||
* Adapted from _crc16_update in <util/crc16.h>.
|
||||
*/
|
||||
static void calculate_crc(uint16_t *crc, uint16_t len){
|
||||
*crc = 0xFFFF;
|
||||
|
||||
@ -110,6 +121,11 @@ static void calculate_crc(uint16_t *crc, uint16_t len){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the CRC of the current firmware. If it matches the
|
||||
* CRC burned into the EEPROM, the firmware is considered valid,
|
||||
* and the bootloader can load it.
|
||||
*/
|
||||
static bool valid_app(){
|
||||
crc_info_t crc_eeprom_info;
|
||||
eeprom_read_block(&crc_eeprom_info, (void*)OCTOCLOCK_EEPROM_APP_LEN, 4);
|
||||
@ -118,6 +134,26 @@ static bool valid_app(){
|
||||
return (crc_info.fw_crc == crc_eeprom_info.fw_crc);
|
||||
}
|
||||
|
||||
/*
|
||||
* UDP handlers
|
||||
*/
|
||||
void handle_udp_query_packet(
|
||||
struct socket_address src, struct socket_address dst,
|
||||
unsigned char *payload, int payload_len
|
||||
){
|
||||
const octoclock_packet_t *pkt_in = (octoclock_packet_t*)payload;
|
||||
|
||||
// Respond to uhd::device::find(), identify as bootloader
|
||||
if(pkt_in->code == OCTOCLOCK_QUERY_CMD){
|
||||
octoclock_packet_t pkt_out;
|
||||
pkt_out.proto_ver = OCTOCLOCK_BOOTLOADER_PROTO_VER;
|
||||
pkt_out.sequence = pkt_in->sequence;
|
||||
pkt_out.code = OCTOCLOCK_QUERY_ACK;
|
||||
pkt_out.len = 0;
|
||||
send_udp_pkt(OCTOCLOCK_UDP_CTRL_PORT, src, (void*)&pkt_out, sizeof(octoclock_packet_t));
|
||||
}
|
||||
}
|
||||
|
||||
void handle_udp_fw_packet(
|
||||
struct socket_address src, struct socket_address dst,
|
||||
unsigned char *payload, int payload_len
|
||||
@ -132,24 +168,27 @@ void handle_udp_fw_packet(
|
||||
case PREPARE_FW_BURN_CMD:
|
||||
received_cmd = true;
|
||||
done_burning = false;
|
||||
crc_info.fw_crc = pkt_in->crc;
|
||||
crc_info.fw_len = pkt_in->len;
|
||||
pkt_out.code = FW_BURN_READY_ACK;
|
||||
break;
|
||||
|
||||
// Burn firmware sent from the host
|
||||
case FILE_TRANSFER_CMD:
|
||||
boot_program_page(pkt_in->data, pkt_in->addr);
|
||||
pkt_out.code = FILE_TRANSFER_ACK;
|
||||
pkt_out.addr = pkt_in->addr;
|
||||
break;
|
||||
|
||||
// Send firmware back to the host for verification
|
||||
case READ_FW_CMD:
|
||||
pkt_out.code = READ_FW_ACK;
|
||||
read_firmware(pkt_in->addr, &pkt_out);
|
||||
break;
|
||||
|
||||
// Calculate the CRC of the new firmware and finish
|
||||
case FINALIZE_BURNING_CMD:
|
||||
//With stuff verified, burn CRC info into EEPROM
|
||||
done_burning = true;
|
||||
calculate_crc(&(crc_info.fw_crc), crc_info.fw_len);
|
||||
eeprom_write_block(&crc_info, (void*)OCTOCLOCK_EEPROM_APP_LEN, 4);
|
||||
pkt_out.code = FINALIZE_BURNING_ACK;
|
||||
break;
|
||||
@ -170,11 +209,12 @@ void handle_udp_eeprom_packet(
|
||||
pkt_out.sequence = pkt_in->sequence;
|
||||
pkt_out.len = 0;
|
||||
|
||||
// Restore OctoClock's EEPROM to factory state
|
||||
if(pkt_in->proto_ver == OCTOCLOCK_FW_COMPAT_NUM){
|
||||
switch(pkt_in->code){
|
||||
case CLEAR_EEPROM_CMD:
|
||||
received_cmd = true;
|
||||
uint8_t blank_eeprom[103];
|
||||
uint8_t blank_eeprom[103]; // 103 is offset of CRC info
|
||||
memset(blank_eeprom, 0xFF, 103);
|
||||
eeprom_write_block(blank_eeprom, 0, 103);
|
||||
pkt_out.code = CLEAR_EEPROM_ACK;
|
||||
@ -189,28 +229,45 @@ void handle_udp_eeprom_packet(
|
||||
|
||||
int main(void){
|
||||
|
||||
asm("cli");
|
||||
// Disable watchdog timer
|
||||
wdt_disable();
|
||||
|
||||
//Initialization
|
||||
// Give interrupts to bootloader
|
||||
MCUCR = (1<<IVCE);
|
||||
MCUCR = (1<<IVSEL);
|
||||
cli();
|
||||
|
||||
// Atmega128
|
||||
setup_atmel_io_ports();
|
||||
|
||||
// Start timer
|
||||
TIMER1_INIT();
|
||||
|
||||
// Ethernet stack
|
||||
network_init();
|
||||
init_udp_listeners();
|
||||
register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_query_packet);
|
||||
register_udp_listener(OCTOCLOCK_UDP_FW_PORT, handle_udp_fw_packet);
|
||||
register_udp_listener(OCTOCLOCK_UDP_EEPROM_PORT, handle_udp_eeprom_packet);
|
||||
|
||||
//Turn LED's on to show we're in the bootloader
|
||||
// Turn LED's on to show we're in the bootloader
|
||||
PORTC |= 0x20;
|
||||
PORTC |= (0x20<<1);
|
||||
PORTC |= (0x20<<2);
|
||||
|
||||
TIMER1_INIT();
|
||||
bool app_checked = false;
|
||||
|
||||
/*
|
||||
* This loop determines whether the OctoClock will remain in its bootloader
|
||||
* state or if it will load the main firmware. After five seconds, it will
|
||||
* check to see if valid firmware is installed. If so, it will immediately
|
||||
* load it. Otherwise, it will remain here until firmware is installed.
|
||||
*
|
||||
* This process can be stopped by an instruction from the firmware burner
|
||||
* utility, at which point the OctoClock will remain in bootloader state until
|
||||
* instructed by the utility to exit the loop and load the new firmware.
|
||||
*/
|
||||
while(true){
|
||||
if(done_burning){
|
||||
if(valid_app()) break;
|
||||
else done_burning = false; //Burning somehow failed and wasn't caught
|
||||
else done_burning = false; // Burning somehow failed and wasn't caught
|
||||
}
|
||||
if(!app_checked && !received_cmd && TIME_PASSED){
|
||||
app_checked = true;
|
||||
@ -220,16 +277,18 @@ int main(void){
|
||||
network_check();
|
||||
}
|
||||
|
||||
//Turn LED's off before moving to application
|
||||
// Turn LED's off before moving to application
|
||||
PORTC &= ~0x20;
|
||||
PORTC &= ~(0x20<<1);
|
||||
PORTC &= ~(0x20<<2);
|
||||
|
||||
/*
|
||||
* Whether the bootloader reaches here through five seconds of inactivity
|
||||
* or after a firmware burn just finished, it can be assumed that the application
|
||||
* is valid.
|
||||
* At this point, the bootloader has determined that there is valid
|
||||
* firmware installed on the device and that it is OK to load it.
|
||||
*/
|
||||
TIMER1_DISABLE();
|
||||
MCUCR = (1<<IVCE);
|
||||
MCUCR = 0;
|
||||
cli();
|
||||
asm("jmp 0000");
|
||||
return 0; //Will never get here, but AVR-GCC needs it
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include <octoclock.h>
|
||||
|
||||
typedef enum {
|
||||
Reg0, Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7,
|
||||
Reg0=0, Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7,
|
||||
Reg8_Status_Control,
|
||||
Read_Command=0xE,
|
||||
RAM_EEPROM_Unlock=0x1F,
|
||||
@ -46,6 +46,8 @@ void reset_TI_CDCE18005(void);
|
||||
|
||||
uint32_t get_TI_CDCE18005(CDCE18005 which_register);
|
||||
|
||||
void set_TI_CDCE18005(CDCE18005 which_register, uint32_t bits);
|
||||
|
||||
bool check_TI_CDCE18005(TI_Input_10_MHz which_input, CDCE18005 which_register);
|
||||
|
||||
#endif /* _CLKDIST_H_ */
|
||||
|
||||
@ -66,8 +66,8 @@
|
||||
DEBUG_LOG_HEX(((uint8_t*)&num)[0]);
|
||||
|
||||
#define DEBUG_LOG_INT(num) DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[3]); \
|
||||
DEBUG_LOG_HEX(((uint8_t*)&num)[2]); \
|
||||
DEBUG_LOG_HEX(((uint8_t*)&num)[1]); \
|
||||
DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[2]); \
|
||||
DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[1]); \
|
||||
DEBUG_LOG_HEX(((uint8_t*)&num)[0]);
|
||||
|
||||
#else
|
||||
|
||||
@ -27,6 +27,4 @@ gpsdo_cache_state_t gpsdo_state;
|
||||
|
||||
void send_gpsdo_cmd(char* buf, uint8_t size);
|
||||
|
||||
void process_gpsdo_output(void);
|
||||
|
||||
#endif /* _GPSDO_H_ */
|
||||
|
||||
@ -1,299 +1,276 @@
|
||||
/*! \file enc28j60.h \brief Microchip ENC28J60 Ethernet Interface Driver. */
|
||||
//*****************************************************************************
|
||||
//
|
||||
// File Name : 'enc28j60.h'
|
||||
// Title : Microchip ENC28J60 Ethernet Interface Driver
|
||||
// Author : Pascal Stang (c)2005
|
||||
// Created : 9/22/2005
|
||||
// Revised : 9/22/2005
|
||||
// Version : 0.1
|
||||
// Target MCU : Atmel AVR series
|
||||
// Editor Tabs : 4
|
||||
//
|
||||
/// \ingroup network
|
||||
/// \defgroup enc28j60 Microchip ENC28J60 Ethernet Interface Driver (enc28j60.c)
|
||||
/// \code #include "net/enc28j60.h" \endcode
|
||||
/// \par Overview
|
||||
/// This driver provides initialization and transmit/receive
|
||||
/// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
|
||||
/// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
|
||||
/// chip, using an SPI interface to the host processor.
|
||||
///
|
||||
//
|
||||
//*****************************************************************************
|
||||
//@{
|
||||
/*
|
||||
* Copyright 2015 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 ENC28J60_H
|
||||
#define ENC28J60_H
|
||||
#ifndef _NET_ENC28J60_H_
|
||||
#define _NET_ENC28J60_H_
|
||||
|
||||
#include <avrlibdefs.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#include "enc28j60conf.h"
|
||||
#define SPI_DDR DDRB
|
||||
#define SPI_PORT PORTB
|
||||
#define SPI_CS 0
|
||||
#define SPI_MOSI 2
|
||||
#define SPI_MISO 3
|
||||
#define SPI_SCK 1
|
||||
|
||||
// ENC28J60 Control Registers
|
||||
// Control register definitions are a combination of address,
|
||||
// bank number, and Ethernet/MAC/PHY indicator bits.
|
||||
// - Register address (bits 0-4)
|
||||
// - Bank number (bits 5-6)
|
||||
// - MAC/PHY indicator (bit 7)
|
||||
#define ADDR_MASK 0x1F
|
||||
#define BANK_MASK 0x60
|
||||
#define SPRD_MASK 0x80
|
||||
// All-bank registers
|
||||
#define EIE 0x1B
|
||||
#define EIR 0x1C
|
||||
#define ESTAT 0x1D
|
||||
#define ECON2 0x1E
|
||||
#define ECON1 0x1F
|
||||
// Bank 0 registers
|
||||
#define ERDPTL (0x00|0x00)
|
||||
#define ERDPTH (0x01|0x00)
|
||||
#define EWRPTL (0x02|0x00)
|
||||
#define EWRPTH (0x03|0x00)
|
||||
#define ETXSTL (0x04|0x00)
|
||||
#define ETXSTH (0x05|0x00)
|
||||
#define ETXNDL (0x06|0x00)
|
||||
#define ETXNDH (0x07|0x00)
|
||||
#define ERXSTL (0x08|0x00)
|
||||
#define ERXSTH (0x09|0x00)
|
||||
#define ERXNDL (0x0A|0x00)
|
||||
#define ERXNDH (0x0B|0x00)
|
||||
#define ERXRDPTL (0x0C|0x00)
|
||||
#define ERXRDPTH (0x0D|0x00)
|
||||
#define ERXWRPTL (0x0E|0x00)
|
||||
#define ERXWRPTH (0x0F|0x00)
|
||||
#define EDMASTL (0x10|0x00)
|
||||
#define EDMASTH (0x11|0x00)
|
||||
#define EDMANDL (0x12|0x00)
|
||||
#define EDMANDH (0x13|0x00)
|
||||
#define EDMADSTL (0x14|0x00)
|
||||
#define EDMADSTH (0x15|0x00)
|
||||
#define EDMACSL (0x16|0x00)
|
||||
#define EDMACSH (0x17|0x00)
|
||||
// Bank 1 registers
|
||||
#define EHT0 (0x00|0x20)
|
||||
#define EHT1 (0x01|0x20)
|
||||
#define EHT2 (0x02|0x20)
|
||||
#define EHT3 (0x03|0x20)
|
||||
#define EHT4 (0x04|0x20)
|
||||
#define EHT5 (0x05|0x20)
|
||||
#define EHT6 (0x06|0x20)
|
||||
#define EHT7 (0x07|0x20)
|
||||
#define EPMM0 (0x08|0x20)
|
||||
#define EPMM1 (0x09|0x20)
|
||||
#define EPMM2 (0x0A|0x20)
|
||||
#define EPMM3 (0x0B|0x20)
|
||||
#define EPMM4 (0x0C|0x20)
|
||||
#define EPMM5 (0x0D|0x20)
|
||||
#define EPMM6 (0x0E|0x20)
|
||||
#define EPMM7 (0x0F|0x20)
|
||||
#define EPMCSL (0x10|0x20)
|
||||
#define EPMCSH (0x11|0x20)
|
||||
#define EPMOL (0x14|0x20)
|
||||
#define EPMOH (0x15|0x20)
|
||||
#define EWOLIE (0x16|0x20)
|
||||
#define EWOLIR (0x17|0x20)
|
||||
#define ERXFCON (0x18|0x20)
|
||||
#define EPKTCNT (0x19|0x20)
|
||||
// Bank 2 registers
|
||||
#define MACON1 (0x00|0x40|0x80)
|
||||
#define MACON2 (0x01|0x40|0x80)
|
||||
#define MACON3 (0x02|0x40|0x80)
|
||||
#define MACON4 (0x03|0x40|0x80)
|
||||
#define MABBIPG (0x04|0x40|0x80)
|
||||
#define MAIPGL (0x06|0x40|0x80)
|
||||
#define MAIPGH (0x07|0x40|0x80)
|
||||
#define MACLCON1 (0x08|0x40|0x80)
|
||||
#define MACLCON2 (0x09|0x40|0x80)
|
||||
#define MAMXFLL (0x0A|0x40|0x80)
|
||||
#define MAMXFLH (0x0B|0x40|0x80)
|
||||
#define MAPHSUP (0x0D|0x40|0x80)
|
||||
#define MICON (0x11|0x40|0x80)
|
||||
#define MICMD (0x12|0x40|0x80)
|
||||
#define MIREGADR (0x14|0x40|0x80)
|
||||
#define MIWRL (0x16|0x40|0x80)
|
||||
#define MIWRH (0x17|0x40|0x80)
|
||||
#define MIRDL (0x18|0x40|0x80)
|
||||
#define MIRDH (0x19|0x40|0x80)
|
||||
// Bank 3 registers
|
||||
#define MAADR1 (0x00|0x60|0x80)
|
||||
#define MAADR0 (0x01|0x60|0x80)
|
||||
#define MAADR3 (0x02|0x60|0x80)
|
||||
#define MAADR2 (0x03|0x60|0x80)
|
||||
#define MAADR5 (0x04|0x60|0x80)
|
||||
#define MAADR4 (0x05|0x60|0x80)
|
||||
#define EBSTSD (0x06|0x60)
|
||||
#define EBSTCON (0x07|0x60)
|
||||
#define EBSTCSL (0x08|0x60)
|
||||
#define EBSTCSH (0x09|0x60)
|
||||
#define MISTAT (0x0A|0x60|0x80)
|
||||
#define EREVID (0x12|0x60)
|
||||
#define ECOCON (0x15|0x60)
|
||||
#define EFLOCON (0x17|0x60)
|
||||
#define EPAUSL (0x18|0x60)
|
||||
#define EPAUSH (0x19|0x60)
|
||||
// PHY registers
|
||||
#define PHCON1 0x00
|
||||
#define PHSTAT1 0x01
|
||||
#define PHHID1 0x02
|
||||
#define PHHID2 0x03
|
||||
#define PHCON2 0x10
|
||||
#define PHSTAT2 0x11
|
||||
#define PHIE 0x12
|
||||
#define PHIR 0x13
|
||||
#define PHLCON 0x14
|
||||
// Register Masks
|
||||
#define ADDR_MASK 0x1F
|
||||
#define BANK_MASK 0x60
|
||||
#define SPRD_MASK 0x80
|
||||
|
||||
// ENC28J60 EIE Register Bit Definitions
|
||||
#define EIE_INTIE 0x80
|
||||
#define EIE_PKTIE 0x40
|
||||
#define EIE_DMAIE 0x20
|
||||
#define EIE_LINKIE 0x10
|
||||
#define EIE_TXIE 0x08
|
||||
#define EIE_WOLIE 0x04
|
||||
#define EIE_TXERIE 0x02
|
||||
#define EIE_RXERIE 0x01
|
||||
// ENC28J60 EIR Register Bit Definitions
|
||||
#define EIR_PKTIF 0x40
|
||||
#define EIR_DMAIF 0x20
|
||||
#define EIR_LINKIF 0x10
|
||||
#define EIR_TXIF 0x08
|
||||
#define EIR_WOLIF 0x04
|
||||
#define EIR_TXERIF 0x02
|
||||
#define EIR_RXERIF 0x01
|
||||
// ENC28J60 ESTAT Register Bit Definitions
|
||||
#define ESTAT_INT 0x80
|
||||
#define ESTAT_LATECOL 0x10
|
||||
#define ESTAT_RXBUSY 0x04
|
||||
#define ESTAT_TXABRT 0x02
|
||||
#define ESTAT_CLKRDY 0x01
|
||||
// ENC28J60 ECON2 Register Bit Definitions
|
||||
#define ECON2_AUTOINC 0x80
|
||||
#define ECON2_PKTDEC 0x40
|
||||
#define ECON2_PWRSV 0x20
|
||||
#define ECON2_VRPS 0x08
|
||||
// ENC28J60 ECON1 Register Bit Definitions
|
||||
#define ECON1_TXRST 0x80
|
||||
#define ECON1_RXRST 0x40
|
||||
#define ECON1_DMAST 0x20
|
||||
#define ECON1_CSUMEN 0x10
|
||||
#define ECON1_TXRTS 0x08
|
||||
#define ECON1_RXEN 0x04
|
||||
#define ECON1_BSEL1 0x02
|
||||
#define ECON1_BSEL0 0x01
|
||||
// ENC28J60 MACON1 Register Bit Definitions
|
||||
#define MACON1_LOOPBK 0x10
|
||||
#define MACON1_TXPAUS 0x08
|
||||
#define MACON1_RXPAUS 0x04
|
||||
#define MACON1_PASSALL 0x02
|
||||
#define MACON1_MARXEN 0x01
|
||||
// ENC28J60 MACON2 Register Bit Definitions
|
||||
#define MACON2_MARST 0x80
|
||||
#define MACON2_RNDRST 0x40
|
||||
#define MACON2_MARXRST 0x08
|
||||
#define MACON2_RFUNRST 0x04
|
||||
#define MACON2_MATXRST 0x02
|
||||
#define MACON2_TFUNRST 0x01
|
||||
// ENC28J60 MACON3 Register Bit Definitions
|
||||
#define MACON3_PADCFG2 0x80
|
||||
#define MACON3_PADCFG1 0x40
|
||||
#define MACON3_PADCFG0 0x20
|
||||
#define MACON3_TXCRCEN 0x10
|
||||
#define MACON3_PHDRLEN 0x08
|
||||
#define MACON3_HFRMLEN 0x04
|
||||
#define MACON3_FRMLNEN 0x02
|
||||
#define MACON3_FULDPX 0x01
|
||||
// ENC28J60 MICMD Register Bit Definitions
|
||||
#define MICMD_MIISCAN 0x02
|
||||
#define MICMD_MIIRD 0x01
|
||||
// ENC28J60 MISTAT Register Bit Definitions
|
||||
#define MISTAT_NVALID 0x04
|
||||
#define MISTAT_SCAN 0x02
|
||||
#define MISTAT_BUSY 0x01
|
||||
// ENC28J60 PHY PHCON1 Register Bit Definitions
|
||||
#define PHCON1_PRST 0x8000
|
||||
#define PHCON1_PLOOPBK 0x4000
|
||||
#define PHCON1_PPWRSV 0x0800
|
||||
#define PHCON1_PDPXMD 0x0100
|
||||
// ENC28J60 PHY PHSTAT1 Register Bit Definitions
|
||||
#define PHSTAT1_PFDPX 0x1000
|
||||
#define PHSTAT1_PHDPX 0x0800
|
||||
#define PHSTAT1_LLSTAT 0x0004
|
||||
#define PHSTAT1_JBSTAT 0x0002
|
||||
// ENC28J60 PHY PHCON2 Register Bit Definitions
|
||||
#define PHCON2_FRCLINK 0x4000
|
||||
#define PHCON2_TXDIS 0x2000
|
||||
#define PHCON2_JABBER 0x0400
|
||||
#define PHCON2_HDLDIS 0x0100
|
||||
// All Banks Registers
|
||||
#define EIE 0x1B
|
||||
#define EIR 0x1C
|
||||
#define ESTAT 0x1D
|
||||
#define ECON2 0x1E
|
||||
#define ECON1 0x1F
|
||||
|
||||
// ENC28J60 Packet Control Byte Bit Definitions
|
||||
#define PKTCTRL_PHUGEEN 0x08
|
||||
#define PKTCTRL_PPADEN 0x04
|
||||
#define PKTCTRL_PCRCEN 0x02
|
||||
#define PKTCTRL_POVERRIDE 0x01
|
||||
// Bank 0 Registers
|
||||
#define ERDPTL 0x00
|
||||
#define ERDPTH 0x01
|
||||
#define EWRPTL 0x02
|
||||
#define EWRPTH 0x03
|
||||
#define ETXSTL 0x04
|
||||
#define ETXSTH 0x05
|
||||
#define ETXNDL 0x06
|
||||
#define ETXNDH 0x07
|
||||
#define ERXSTL 0x08
|
||||
#define ERXSTH 0x09
|
||||
#define ERXNDL 0x0A
|
||||
#define ERXNDH 0x0B
|
||||
#define ERXRDPTL 0x0C
|
||||
#define ERXRDPTH 0x0D
|
||||
#define ERXWRPTL 0x0E
|
||||
#define ERXWRPTH 0x0F
|
||||
#define EDMASTL 0x10
|
||||
#define EDMASTH 0x11
|
||||
#define EDMANDL 0x12
|
||||
#define EDMANDH 0x13
|
||||
#define EDMADSTL 0x14
|
||||
#define EDMADSTH 0x15
|
||||
#define EDMACSL 0x16
|
||||
#define EDMACSH 0x17
|
||||
|
||||
// SPI operation codes
|
||||
#define ENC28J60_READ_CTRL_REG 0x00
|
||||
#define ENC28J60_READ_BUF_MEM 0x3A
|
||||
#define ENC28J60_WRITE_CTRL_REG 0x40
|
||||
#define ENC28J60_WRITE_BUF_MEM 0x7A
|
||||
#define ENC28J60_BIT_FIELD_SET 0x80
|
||||
#define ENC28J60_BIT_FIELD_CLR 0xA0
|
||||
#define ENC28J60_SOFT_RESET 0xFF
|
||||
// Bank 1 Registers
|
||||
#define EHT0 0x20
|
||||
#define EHT1 0x21
|
||||
#define EHT2 0x22
|
||||
#define EHT3 0x23
|
||||
#define EHT4 0x24
|
||||
#define EHT5 0x25
|
||||
#define EHT6 0x26
|
||||
#define EHT7 0x27
|
||||
#define EPMM0 0x28
|
||||
#define EPMM1 0x29
|
||||
#define EPMM2 0x2A
|
||||
#define EPMM3 0x2B
|
||||
#define EPMM4 0x2C
|
||||
#define EPMM5 0x2D
|
||||
#define EPMM6 0x2E
|
||||
#define EPMM7 0x2F
|
||||
#define EPMCSL 0x30
|
||||
#define EPMCSH 0x31
|
||||
#define EPMOL 0x34
|
||||
#define EPMOH 0x35
|
||||
#define EWOLIE 0x36
|
||||
#define EWOLIR 0x37
|
||||
#define ERXFCON 0x38
|
||||
#define EPKTCNT 0x39
|
||||
|
||||
// Bank 2 Register
|
||||
#define MACON1 0xC0
|
||||
#define MACON2 0xC1
|
||||
#define MACON3 0xC2
|
||||
#define MACON4 0xC3
|
||||
#define MABBIPG 0xC4
|
||||
#define MAIPGL 0xC6
|
||||
#define MAIPGH 0xC7
|
||||
#define MACLCON1 0xC8
|
||||
#define MACLCON2 0xC9
|
||||
#define MAMXFLL 0xCA
|
||||
#define MAMXFLH 0xCB
|
||||
#define MAPHSUP 0xCD
|
||||
#define MICON 0xD1
|
||||
#define MICMD 0xD2
|
||||
#define MIREGADR 0xD4
|
||||
#define MIWRL 0xD6
|
||||
#define MIWRH 0xD7
|
||||
#define MIRDL 0xD8
|
||||
#define MIRDH 0xD9
|
||||
|
||||
// buffer boundaries applied to internal 8K ram
|
||||
// entire available packet buffer space is allocated
|
||||
#define TXSTART_INIT 0x0000 // start TX buffer at 0
|
||||
#define RXSTART_INIT 0x0600 // give TX buffer space for one full ethernet frame (~1500 bytes)
|
||||
#define RXSTOP_INIT 0x1FFF // receive buffer gets the rest
|
||||
// Bank 3 Registers
|
||||
#define MAADR1 0xE0
|
||||
#define MAADR0 0xE1
|
||||
#define MAADR3 0xE2
|
||||
#define MAADR2 0xE3
|
||||
#define MAADR5 0xE4
|
||||
#define MAADR4 0xE5
|
||||
#define EBSTSD 0x66
|
||||
#define EBSTCON 0x67
|
||||
#define EBSTCSL 0x68
|
||||
#define EBSTCSH 0x69
|
||||
#define MISTAT 0xEA
|
||||
#define EREVID 0x72
|
||||
#define ECOCON 0x75
|
||||
#define EFLOCON 0x77
|
||||
#define EPAUSL 0x78
|
||||
#define EPAUSH 0x79
|
||||
|
||||
#define MAX_FRAMELEN 1518 // maximum ethernet frame length
|
||||
// PHY Registers
|
||||
#define PHCON1 0x00
|
||||
#define PHSTAT1 0x01
|
||||
#define PHHID1 0x02
|
||||
#define PHHID2 0x03
|
||||
#define PHCON2 0x10
|
||||
#define PHSTAT2 0x11
|
||||
#define PHIE 0x12
|
||||
#define PHIR 0x13
|
||||
#define PHLCON 0x14
|
||||
|
||||
// Ethernet constants
|
||||
#define ETHERNET_MIN_PACKET_LENGTH 0x3C
|
||||
//#define ETHERNET_HEADER_LENGTH 0x0E
|
||||
// ERXFCON bit definitions
|
||||
#define UCEN 0x80
|
||||
#define ANDOR 0x40
|
||||
#define CRCEN 0x20
|
||||
#define PMEN 0x10
|
||||
#define MPEN 0x08
|
||||
#define HTEN 0x04
|
||||
#define MCEN 0x02
|
||||
#define BCEN 0x01
|
||||
|
||||
// setup ports for I/O
|
||||
//void ax88796SetupPorts(void);
|
||||
// EIE bit definitions
|
||||
#define INTIE 0x80
|
||||
#define PKTIE 0x40
|
||||
#define DMAIE 0x20
|
||||
#define LINKIE 0x10
|
||||
#define TXIE 0x08
|
||||
#define WOLIE 0x04
|
||||
#define TXERIE 0x02
|
||||
#define RXERIE 0x01
|
||||
|
||||
//! do a ENC28J60 read operation
|
||||
u08 enc28j60ReadOp(u08 op, u08 address);
|
||||
//! do a ENC28J60 write operation
|
||||
void enc28j60WriteOp(u08 op, u08 address, u08 data);
|
||||
//! read the packet buffer memory
|
||||
void enc28j60ReadBuffer(u16 len, u08* data);
|
||||
//! write the packet buffer memory
|
||||
void enc28j60WriteBuffer(u16 len, u08* data);
|
||||
//! set the register bank for register at address
|
||||
void enc28j60SetBank(u08 address);
|
||||
//! read ax88796 register
|
||||
u08 enc28j60Read(u08 address);
|
||||
//! write ax88796 register
|
||||
void enc28j60Write(u08 address, u08 data);
|
||||
//! read a PHY register
|
||||
u16 enc28j60PhyRead(u08 address);
|
||||
//! write a PHY register
|
||||
void enc28j60PhyWrite(u08 address, u16 data);
|
||||
// EIR bit definitions
|
||||
#define PKTIF 0x40
|
||||
#define DMAIF 0x20
|
||||
#define LINKIF 0x10
|
||||
#define TXIF 0x08
|
||||
#define WOLIF 0x04
|
||||
#define TXERIF 0x02
|
||||
#define RXERIF 0x01
|
||||
|
||||
//! initialize the ethernet interface for transmit/receive
|
||||
void enc28j60Init(u08* macaddr);
|
||||
// ESTAT bit definitions
|
||||
#define INT 0x80
|
||||
#define LATECOL 0x10
|
||||
#define RXBUSY 0x04
|
||||
#define TXABRT 0x02
|
||||
#define CLKRDY 0x01
|
||||
|
||||
//! Packet transmit function.
|
||||
/// Sends a packet on the network. It is assumed that the packet is headed by a valid ethernet header.
|
||||
/// \param len Length of packet in bytes.
|
||||
/// \param packet Pointer to packet data.
|
||||
/// \param len2 Length of the secound packet in bytes, can be 0.
|
||||
/// \param packet2 Pointer to the secound packet data, can be NULL.
|
||||
void enc28j60PacketSend(unsigned int len1, unsigned char* packet1, unsigned int len2, unsigned char* packet2);
|
||||
// ECON2 bit definitions
|
||||
#define AUTOINC 0x80
|
||||
#define PKTDEC 0x40
|
||||
#define PWRSV 0x20
|
||||
#define VRPS 0x08
|
||||
|
||||
//! Packet receive function.
|
||||
/// Gets a packet from the network receive buffer, if one is available.
|
||||
/// The packet will by headed by an ethernet header.
|
||||
/// \param maxlen The maximum acceptable length of a retrieved packet.
|
||||
/// \param buf Pointer to buffer.
|
||||
/// \return Packet length in bytes if a packet was retrieved, zero otherwise.
|
||||
unsigned int enc28j60PacketReceive(unsigned int maxlen, u08* buf);
|
||||
// ECON1 bit definitions
|
||||
#define TXRST 0x80
|
||||
#define RXRST 0x40
|
||||
#define DMAST 0x20
|
||||
#define CSUMEN 0x10
|
||||
#define TXRTS 0x08
|
||||
#define ENCRXEN 0x04
|
||||
#define BSEL1 0x02
|
||||
#define BSEL0 0x01
|
||||
|
||||
#endif
|
||||
//@}
|
||||
// MACON1 bit definitions
|
||||
#define LOOPBK 0x10
|
||||
#define TXPAUS 0x08
|
||||
#define RXPAUS 0x04
|
||||
#define PASSALL 0x02
|
||||
#define MARXEN 0x01
|
||||
|
||||
// MACON2 bit definitions
|
||||
#define MARST 0x80
|
||||
#define RNDRST 0x40
|
||||
#define MARXRST 0x08
|
||||
#define RFUNRST 0x04
|
||||
#define MATXRST 0x02
|
||||
#define TFUNRST 0x01
|
||||
|
||||
// MACON3 bit definitions
|
||||
#define PADCFG2 0x80
|
||||
#define PADCFG1 0x40
|
||||
#define PADCFG0 0x20
|
||||
#define TXCRCEN 0x10
|
||||
#define PHDRLEN 0x08
|
||||
#define HFRMLEN 0x04
|
||||
#define FRMLNEN 0x02
|
||||
#define FULDPX 0x01
|
||||
|
||||
// MICMD bit definitions
|
||||
#define MIISCAN 0x02
|
||||
#define MIIRD 0x01
|
||||
|
||||
// MISTAT bit definitions
|
||||
#define NVALID 0x04
|
||||
#define SCAN 0x02
|
||||
#define BUSY 0x01
|
||||
|
||||
// PHCON1 bit definitions
|
||||
#define PRST 0x8000
|
||||
#define PLOOPBK 0x4000
|
||||
#define PPWRSV 0x0800
|
||||
#define PDPXMD 0x0100
|
||||
|
||||
// PHSTAT1 bit definitions
|
||||
#define PFDPX 0x1000
|
||||
#define PHDPX 0x0800
|
||||
#define LLSTAT 0x0004
|
||||
#define JBSTAT 0x0002
|
||||
|
||||
// PHCON2 bit definitions
|
||||
#define FRCLINK 0x4000
|
||||
#define TXDIS 0x2000
|
||||
#define JABBER 0x0400
|
||||
#define HDLDIS 0x0100
|
||||
|
||||
// Packet Control bit Definitions
|
||||
#define PHUGEEN 0x08
|
||||
#define PPADEN 0x04
|
||||
#define PCRCEN 0x02
|
||||
#define POVERRIDE 0x01
|
||||
|
||||
// SPI Instruction Set
|
||||
#define RCR 0x00 // Read Control Register
|
||||
#define RBM 0x3A // Read Buffer Memory
|
||||
#define WCR 0x40 // Write Control Register
|
||||
#define WBM 0x7A // Write Buffer Memory
|
||||
#define BFS 0x80 // Bit Field Set
|
||||
#define BFC 0xA0 // Bit Field Clear
|
||||
#define SC 0xFF // Soft Reset
|
||||
|
||||
// Buffer
|
||||
#define RXSTART_INIT 0x0000
|
||||
#define RXSTOP_INIT (0x1FFF-0x0600-1)
|
||||
#define TXSTART_INIT (0x1FFF-0x0600)
|
||||
#define TXSTOP_INIT 0x1FFF
|
||||
#define MAX_FRAMELEN 1500
|
||||
|
||||
void enc28j60_init(uint8_t* mac_addr);
|
||||
|
||||
uint16_t enc28j60_recv(uint8_t* buffer, uint16_t max_len);
|
||||
|
||||
void enc28j60_send(uint8_t* buffer, uint16_t len);
|
||||
|
||||
#endif /* _NET_ENC28J60_H_ */
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
/*! \file enc28j60conf.h \brief Microchip ENC28J60 Ethernet Interface Driver Configuration. */
|
||||
//*****************************************************************************
|
||||
//
|
||||
// File Name : 'enc28j60conf.h'
|
||||
// Title : Microchip ENC28J60 Ethernet Interface Driver Configuration
|
||||
// Author : Pascal Stang
|
||||
// Created : 10/5/2004
|
||||
// Revised : 8/22/2005
|
||||
// Version : 0.1
|
||||
// Target MCU : Atmel AVR series
|
||||
// Editor Tabs : 4
|
||||
//
|
||||
// Description : This driver provides initialization and transmit/receive
|
||||
// functions for the ENC28J60 10Mb Ethernet Controller and PHY.
|
||||
//
|
||||
// This code is distributed under the GNU Public License
|
||||
// which can be found at http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef ENC28J60CONF_H
|
||||
#define ENC28J60CONF_H
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint8_t u08;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
|
||||
// ENC28J60 SPI port
|
||||
#define ENC28J60_SPI_PORT PORTB
|
||||
#define ENC28J60_SPI_DDR DDRB
|
||||
#define ENC28J60_SPI_SCK PORTB1
|
||||
#define ENC28J60_SPI_MOSI PORTB2
|
||||
#define ENC28J60_SPI_MISO PORTB3
|
||||
#define ENC28J60_SPI_SS PORTB0
|
||||
// ENC28J60 control port
|
||||
#define ENC28J60_CONTROL_PORT PORTB
|
||||
#define ENC28J60_CONTROL_DDR DDRB
|
||||
#define ENC28J60_CONTROL_CS PORTB0
|
||||
|
||||
// MAC address for this interface
|
||||
#define ENC28J60_MAC0 '0'
|
||||
#define ENC28J60_MAC1 'F'
|
||||
#define ENC28J60_MAC2 'F'
|
||||
#define ENC28J60_MAC3 'I'
|
||||
#define ENC28J60_MAC4 'C'
|
||||
#define ENC28J60_MAC5 'E'
|
||||
|
||||
#endif /* ENC28J60CONF_H */
|
||||
@ -21,11 +21,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Ethernet MAC address
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t addr[6];
|
||||
} eth_mac_addr_t;
|
||||
#pragma pack(pop)
|
||||
} eth_mac_addr_t __attribute__((aligned(1)));
|
||||
|
||||
#endif /* INCLUDED_ETH_MAC_ADDR_H */
|
||||
|
||||
@ -69,17 +69,11 @@
|
||||
#define _IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (_IPH_TTL(hdr) << 8)))
|
||||
#define _IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
|
||||
|
||||
bool using_network_defaults;
|
||||
volatile bool using_network_defaults;
|
||||
|
||||
// Ethernet I/O buffers
|
||||
uint8_t buf_in[512];
|
||||
uint8_t buf_out[512];
|
||||
|
||||
// Default values loaded if EEPROM is incomplete
|
||||
static const uint32_t blank_eeprom_ip = _IP(255,255,255,255);
|
||||
static const uint32_t default_ip = _IP(192,168,10,3);
|
||||
static const uint32_t default_dr = _IP(192,168,10,1);
|
||||
static const uint32_t default_netmask = _IP(255,255,255,0);
|
||||
#define ETH_BUF_SIZE 512
|
||||
uint8_t eth_buf[ETH_BUF_SIZE];
|
||||
|
||||
typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst,
|
||||
unsigned char *payload, int payload_len);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 Ettus Research LLC
|
||||
* Copyright 2014-2015 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
|
||||
@ -24,17 +24,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Define frequency
|
||||
#define F_CPU 12500000UL
|
||||
#define F_CPU 7372800UL
|
||||
|
||||
/*
|
||||
* Timer 0 (8-bit)
|
||||
* * Set prescaler to 8
|
||||
* * Enable overflow interrupt
|
||||
* * Set timer to 0
|
||||
*/
|
||||
#define TIMER0_INIT() TCCR0 = (1 << CS01); \
|
||||
TIMSK |= (1 << TOIE0); \
|
||||
TCNT0 = 0;
|
||||
/*
|
||||
* Timer 1 (16-bit)
|
||||
* * Set prescaler to 1024
|
||||
@ -42,8 +33,12 @@
|
||||
* * Set timer to 0
|
||||
*/
|
||||
#define TIMER1_INIT() TCCR1B = (1 << CS12) | (1 << CS10); \
|
||||
TIMSK |= (1<<TOIE1); \
|
||||
TCNT1 = 0;
|
||||
TIMSK |= (1<<TOIE1); \
|
||||
TCNT1 = 0;
|
||||
|
||||
#define TIMER1_DISABLE() TCCR1B = 0; \
|
||||
TIMSK = 0; \
|
||||
TCNT1 = 0;
|
||||
|
||||
#define TIMER1_ONE_SECOND ((uint32_t)(12207))
|
||||
|
||||
@ -94,12 +89,6 @@
|
||||
* Bits_32(10000000,11111111,10101010,01010101) = 2164238933
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
Top,
|
||||
Middle,
|
||||
Bottom
|
||||
} LEDs;
|
||||
|
||||
void setup_atmel_io_ports(void);
|
||||
|
||||
#endif /* _OCTOCLOCK_H_ */
|
||||
|
||||
@ -22,23 +22,24 @@
|
||||
|
||||
#include <octoclock.h>
|
||||
|
||||
// NOT PRESENT unless proven so...
|
||||
static ref_t global_which_ref = NO_REF;
|
||||
static bool global_gps_present = false;
|
||||
static bool global_ext_ref_is_present = false;
|
||||
// Global state variables
|
||||
extern volatile bool g_ext_ref_present;
|
||||
extern volatile bool g_gps_present;
|
||||
extern volatile switch_pos_t g_switch_pos;
|
||||
extern volatile ref_t g_ref;
|
||||
|
||||
void led(LEDs which, int turn_it_on);
|
||||
typedef enum {
|
||||
LED_TOP, // Internal
|
||||
LED_MIDDLE, // External
|
||||
LED_BOTTOM // Status
|
||||
} led_t;
|
||||
|
||||
void LEDs_off(void);
|
||||
void led(led_t which, bool on);
|
||||
|
||||
void force_internal(void);
|
||||
void leds_off(void);
|
||||
|
||||
void prefer_internal(void);
|
||||
|
||||
void prefer_external(void);
|
||||
|
||||
ref_t which_ref(void);
|
||||
|
||||
switch_pos_t get_switch_pos(void);
|
||||
|
||||
#endif /* _STATE_H_ */
|
||||
|
||||
@ -25,10 +25,6 @@ void usart_init(void);
|
||||
|
||||
char usart_getc(void);
|
||||
|
||||
char usart_getc_noblock(void);
|
||||
|
||||
void usart_putc(char ch);
|
||||
|
||||
void usart_putc_nowait(char ch);
|
||||
|
||||
#endif /* _USART_H_ */
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
#include <clkdist.h>
|
||||
#include <state.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
#define wait() for(uint16_t u=14000; u; u--) asm("nop");
|
||||
|
||||
#define CLK (PA0) // Shift by 0 bits
|
||||
@ -33,7 +35,7 @@
|
||||
// Table of 32-bit constants to be written to the TI chip's registers. These are
|
||||
// from the "Special Settings" on Page 35 of the datasheet.
|
||||
// For the GPS's 10 MHz output
|
||||
static uint32_t table_Pri_Ref[] = {
|
||||
static const uint32_t table_Pri_Ref[] = {
|
||||
Bits_32(1,01010100,0,0), // Reg 0
|
||||
Bits_32(1,01010100,0,0), // Outputs LVCMOS Positive&Negative Active - Non-inverted
|
||||
Bits_32(1,01010100,0,0),
|
||||
@ -47,7 +49,7 @@ static uint32_t table_Pri_Ref[] = {
|
||||
|
||||
// For the External 10 MHz input LVDS with external termination,
|
||||
// Effectively DC coupled
|
||||
static uint32_t table_Sec_Ref[] = {
|
||||
static const uint32_t table_Sec_Ref[] = {
|
||||
Bits_32(0001,01010100,0,100000), // Reg 0 -- use Secondary Reference for all channels
|
||||
Bits_32(0001,01010100,0,100000), // Outputs LVCMOS Positive&Negative Active - Non-inverted
|
||||
Bits_32(0001,01010100,0,100000),
|
||||
@ -81,7 +83,6 @@ static bool get_bit(uint8_t bit_number) {
|
||||
// Send 32 bits to TI chip, LSB first.
|
||||
// Don't worry about reading any bits back at this time
|
||||
static void send_SPI(uint32_t bits) {
|
||||
|
||||
// Basically, when the clock is low, one can set MOSI to anything, as it's
|
||||
// ignored.
|
||||
set_bit(CE_, Lo); // Start SPI transaction with TI chip
|
||||
@ -130,7 +131,8 @@ void setup_TI_CDCE18005(TI_Input_10_MHz which_input) {
|
||||
for(uint8_t i=0; i<table_size; i++){
|
||||
temp = table_Pri_Ref[i]<<4;
|
||||
temp |= i;
|
||||
send_SPI(temp); // Make sure the register's address is in the LSBs
|
||||
// Make sure the register's address is in the LSBs
|
||||
send_SPI(temp);
|
||||
}
|
||||
} else {
|
||||
// is Secondary_Ext -- External 10 MHz input from SMA connector
|
||||
@ -169,6 +171,10 @@ uint32_t get_TI_CDCE18005(CDCE18005 which_register){
|
||||
return receive_SPI();
|
||||
}
|
||||
|
||||
void set_TI_CDCE18005(CDCE18005 which_register, uint32_t bits){
|
||||
send_SPI((bits << 4) | which_register);
|
||||
}
|
||||
|
||||
bool check_TI_CDCE18005(TI_Input_10_MHz which_input,
|
||||
CDCE18005 which_register) {
|
||||
|
||||
|
||||
@ -1,337 +1,211 @@
|
||||
/*! \file enc28j60.c \brief Microchip ENC28J60 Ethernet Interface Driver. */
|
||||
//*****************************************************************************
|
||||
//
|
||||
// File Name : 'enc28j60.c'
|
||||
// Title : Microchip ENC28J60 Ethernet Interface Driver
|
||||
// Author : Pascal Stang (c)2005
|
||||
// Created : 9/22/2005
|
||||
// Revised : 5/19/2014
|
||||
// Version : 0.1
|
||||
// Target MCU : Atmel AVR series
|
||||
// Editor Tabs : 4
|
||||
//
|
||||
// Description : This driver provides initialization and transmit/receive
|
||||
// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
|
||||
// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
|
||||
// chip, using an SPI interface to the host processor.
|
||||
//
|
||||
//*****************************************************************************
|
||||
/*
|
||||
* Copyright 2015 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 <octoclock.h>
|
||||
|
||||
#include <net/enc28j60.h>
|
||||
#include <net/enc28j60conf.h>
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
u08 Enc28j60Bank;
|
||||
u16 NextPacketPtr;
|
||||
static uint8_t current_bank;
|
||||
static uint16_t next_pkt_ptr;
|
||||
|
||||
u08 enc28j60ReadOp(u08 op, u08 address)
|
||||
{
|
||||
u08 data;
|
||||
|
||||
// assert CS
|
||||
ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
|
||||
|
||||
// issue read command
|
||||
SPDR = op | (address & ADDR_MASK);
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
// read data
|
||||
SPDR = 0x00;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
// do dummy read if needed
|
||||
if(address & 0x80)
|
||||
{
|
||||
SPDR = 0x00;
|
||||
while(!(inb(SPSR) & (1<<SPIF)));
|
||||
}
|
||||
data = SPDR;
|
||||
|
||||
// release CS
|
||||
ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
|
||||
#define SET_CS_ACTIVE() SPI_PORT &= ~(1<<SPI_CS);
|
||||
#define SET_CS_PASSIVE() SPI_PORT |= (1<<SPI_CS);
|
||||
#define SPI_WAIT() while(!(SPSR & (1<<SPIF)));
|
||||
|
||||
return data;
|
||||
static uint8_t enc28j60_read_op(uint8_t op, uint8_t addr){
|
||||
SET_CS_ACTIVE();
|
||||
SPDR = (op | (addr & ADDR_MASK));
|
||||
SPI_WAIT();
|
||||
SPDR = 0x00;
|
||||
SPI_WAIT();
|
||||
|
||||
if(addr & 0x80){
|
||||
SPDR = 0x00;
|
||||
SPI_WAIT();
|
||||
}
|
||||
|
||||
SET_CS_PASSIVE();
|
||||
return SPDR;
|
||||
}
|
||||
|
||||
void enc28j60WriteOp(u08 op, u08 address, u08 data)
|
||||
{
|
||||
// assert CS
|
||||
ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
|
||||
static void enc28j60_write_op(uint8_t op, uint8_t addr, uint8_t value){
|
||||
SET_CS_ACTIVE();
|
||||
|
||||
// issue write command
|
||||
SPDR = op | (address & ADDR_MASK);
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
// write data
|
||||
SPDR = data;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
SPDR = (op | (addr & ADDR_MASK));
|
||||
SPI_WAIT();
|
||||
SPDR = value;
|
||||
SPI_WAIT();
|
||||
|
||||
// release CS
|
||||
ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
|
||||
SET_CS_PASSIVE();
|
||||
}
|
||||
|
||||
void enc28j60ReadBuffer(u16 len, u08* data)
|
||||
{
|
||||
// assert CS
|
||||
ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
|
||||
|
||||
// issue read command
|
||||
SPDR = ENC28J60_READ_BUF_MEM;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
while(len--)
|
||||
{
|
||||
// read data
|
||||
SPDR = 0x00;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
*data++ = SPDR;
|
||||
}
|
||||
// release CS
|
||||
ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
|
||||
static void enc28j60_read_buffer(uint8_t* buf, uint16_t len){
|
||||
SET_CS_ACTIVE();
|
||||
|
||||
SPDR = RBM;
|
||||
SPI_WAIT();
|
||||
while(len){
|
||||
len--;
|
||||
SPDR = 0x00;
|
||||
SPI_WAIT();
|
||||
*buf = SPDR;
|
||||
buf++;
|
||||
}
|
||||
*buf = '\0';
|
||||
|
||||
SET_CS_PASSIVE();
|
||||
}
|
||||
|
||||
void enc28j60WriteBuffer(u16 len, u08* data)
|
||||
{
|
||||
// assert CS
|
||||
ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
|
||||
|
||||
// issue write command
|
||||
SPDR = ENC28J60_WRITE_BUF_MEM;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
while(len--)
|
||||
{
|
||||
// write data
|
||||
SPDR = *data++;
|
||||
while(!(SPSR & (1<<SPIF)));
|
||||
}
|
||||
// release CS
|
||||
ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
|
||||
static void enc28j60_write_buffer(uint8_t* buf, uint16_t len){
|
||||
SET_CS_ACTIVE();
|
||||
|
||||
SPDR = WBM;
|
||||
SPI_WAIT();
|
||||
while(len){
|
||||
len--;
|
||||
SPDR = *buf;
|
||||
buf++;
|
||||
SPI_WAIT();
|
||||
}
|
||||
|
||||
SET_CS_PASSIVE();
|
||||
}
|
||||
|
||||
void enc28j60SetBank(u08 address)
|
||||
{
|
||||
// set the bank (if needed)
|
||||
if((address & BANK_MASK) != Enc28j60Bank)
|
||||
{
|
||||
// set the bank
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
|
||||
Enc28j60Bank = (address & BANK_MASK);
|
||||
}
|
||||
static void enc28j60_set_bank(uint8_t addr){
|
||||
if((addr & BANK_MASK) != current_bank){
|
||||
enc28j60_write_op(BFC, ECON1, (BSEL1|BSEL0));
|
||||
enc28j60_write_op(BFS, ECON1, ((addr & BANK_MASK) >> 5));
|
||||
current_bank = (addr & BANK_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
u08 enc28j60Read(u08 address)
|
||||
{
|
||||
// set the bank
|
||||
enc28j60SetBank(address);
|
||||
// do the read
|
||||
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
|
||||
static uint8_t enc28j60_read(uint8_t addr){
|
||||
enc28j60_set_bank(addr);
|
||||
return enc28j60_read_op(RCR, addr);
|
||||
}
|
||||
|
||||
void enc28j60Write(u08 address, u08 data)
|
||||
{
|
||||
// set the bank
|
||||
enc28j60SetBank(address);
|
||||
// do the write
|
||||
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
|
||||
static void enc28j60_write(uint8_t addr, uint16_t value){
|
||||
enc28j60_set_bank(addr);
|
||||
enc28j60_write_op(WCR, addr, value);
|
||||
}
|
||||
|
||||
u16 enc28j60PhyRead(u08 address)
|
||||
{
|
||||
u16 data;
|
||||
void enc28j60_init(uint8_t* mac_addr){
|
||||
SPI_DDR |= (1 << SPI_CS);
|
||||
SET_CS_PASSIVE();
|
||||
|
||||
// Set the right address and start the register read operation
|
||||
enc28j60Write(MIREGADR, address);
|
||||
enc28j60Write(MICMD, MICMD_MIIRD);
|
||||
SPI_DDR |= ((1 << SPI_MOSI) | (1 << SPI_SCK));
|
||||
SPI_DDR &= ~(1 << SPI_MISO);
|
||||
SPI_PORT &= ~(1 << SPI_MOSI);
|
||||
SPI_PORT &= ~(1 << SPI_SCK);
|
||||
SPCR = ((1 << SPE) | (1 << MSTR));
|
||||
SPSR |= (1 << SPI2X);
|
||||
enc28j60_write_op(SC, 0, SC);
|
||||
next_pkt_ptr = RXSTART_INIT;
|
||||
|
||||
// wait until the PHY read completes
|
||||
while(enc28j60Read(MISTAT) & MISTAT_BUSY);
|
||||
// Designate RX addresses
|
||||
enc28j60_write(ERXSTL, (RXSTART_INIT & 0xFF));
|
||||
enc28j60_write(ERXSTH, (RXSTART_INIT >> 8));
|
||||
enc28j60_write(ERXNDL, (RXSTOP_INIT & 0xFF));
|
||||
enc28j60_write(ERXNDH, (RXSTOP_INIT >> 8));
|
||||
|
||||
// quit reading
|
||||
enc28j60Write(MICMD, 0x00);
|
||||
|
||||
// get data value
|
||||
data = enc28j60Read(MIRDL);
|
||||
data |= enc28j60Read(MIRDH);
|
||||
// return the data
|
||||
return data;
|
||||
// Designate TX addresses
|
||||
enc28j60_write(ETXSTL, (TXSTART_INIT & 0xFF));
|
||||
enc28j60_write(ETXSTH, (TXSTART_INIT >> 8));
|
||||
enc28j60_write(ETXNDL, (TXSTOP_INIT & 0xFF));
|
||||
enc28j60_write(ETXNDH, (TXSTOP_INIT >> 8));
|
||||
|
||||
// Configure filters
|
||||
enc28j60_write(ERXFCON, (UCEN|CRCEN|PMEN|BCEN));
|
||||
enc28j60_write(EPMM0, 0x3F);
|
||||
enc28j60_write(EPMM1, 0x30);
|
||||
enc28j60_write(EPMCSL, 0xF9);
|
||||
enc28j60_write(EPMCSH, 0xF7);
|
||||
|
||||
// MAC initialization
|
||||
enc28j60_write(MACON1, (MARXEN|TXPAUS|RXPAUS));
|
||||
enc28j60_write(MACON2, 0x00);
|
||||
enc28j60_write_op(BFS, MACON3, (PADCFG0|TXCRCEN|FRMLNEN));
|
||||
enc28j60_write(MAIPGL, 0x12);
|
||||
enc28j60_write(MAIPGH, 0x0C);
|
||||
enc28j60_write(MABBIPG, 0x12);
|
||||
enc28j60_write(MAMXFLL, (MAX_FRAMELEN & 0xFF));
|
||||
enc28j60_write(MAMXFLH, (MAX_FRAMELEN >> 8));
|
||||
enc28j60_write(MAADR5, mac_addr[0]);
|
||||
enc28j60_write(MAADR4, mac_addr[1]);
|
||||
enc28j60_write(MAADR3, mac_addr[2]);
|
||||
enc28j60_write(MAADR2, mac_addr[3]);
|
||||
enc28j60_write(MAADR1, mac_addr[4]);
|
||||
enc28j60_write(MAADR0, mac_addr[5]);
|
||||
|
||||
enc28j60_set_bank(ECON1);
|
||||
enc28j60_write_op(BFS, ECON1, ENCRXEN);
|
||||
}
|
||||
|
||||
void enc28j60PhyWrite(u08 address, u16 data)
|
||||
{
|
||||
// set the PHY register address
|
||||
enc28j60Write(MIREGADR, address);
|
||||
|
||||
// write the PHY data
|
||||
enc28j60Write(MIWRL, data);
|
||||
enc28j60Write(MIWRH, data>>8);
|
||||
uint16_t enc28j60_recv(uint8_t* buf, uint16_t max_len){
|
||||
uint16_t rxstat, len;
|
||||
|
||||
// wait until the PHY write completes
|
||||
while(enc28j60Read(MISTAT) & MISTAT_BUSY);
|
||||
// Return if no data is available
|
||||
if(enc28j60_read(EPKTCNT) == 0) return 0;
|
||||
|
||||
enc28j60_write(ERDPTL, (next_pkt_ptr & 0xFF));
|
||||
enc28j60_write(ERDPTH, (next_pkt_ptr >> 8));
|
||||
next_pkt_ptr = enc28j60_read_op(RBM, 0) | ((uint16_t)enc28j60_read_op(RBM, 0) << 8);
|
||||
len = enc28j60_read_op(RBM, 0) | ((uint16_t)enc28j60_read_op(RBM, 0) << 8);
|
||||
len -= 4;
|
||||
rxstat = enc28j60_read_op(RBM, 0) | ((uint16_t)enc28j60_read_op(RBM, 0) << 8);
|
||||
|
||||
// Length sanity check and actual enc28j60_read call
|
||||
if(len > (max_len - 1)) len = max_len - 1;
|
||||
if((rxstat & 0x80) == 0) len = 0;
|
||||
else enc28j60_read_buffer(buf, len);
|
||||
|
||||
// Update next packet pointer
|
||||
enc28j60_write(ERXRDPTL, (next_pkt_ptr & 0xFF));
|
||||
enc28j60_write(ERXRDPTH, (next_pkt_ptr >> 8));
|
||||
if(((next_pkt_ptr - 1) < RXSTART_INIT) || ((next_pkt_ptr - 1) > RXSTOP_INIT)){
|
||||
enc28j60_write(ERXRDPTL, (RXSTOP_INIT & 0xFF));
|
||||
enc28j60_write(ERXRDPTH, (RXSTOP_INIT >> 8));
|
||||
}
|
||||
else{
|
||||
enc28j60_write(ERXRDPTL, ((next_pkt_ptr - 1) & 0xFF));
|
||||
enc28j60_write(ERXRDPTH, ((next_pkt_ptr - 1) >> 8));
|
||||
}
|
||||
enc28j60_write_op(BFS, ECON2, PKTDEC);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void enc28j60Init(u08* macaddr)
|
||||
{
|
||||
// initialize I/O
|
||||
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_CS);
|
||||
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
||||
void enc28j60_send(uint8_t* buf, uint16_t len){
|
||||
|
||||
// setup SPI I/O pins
|
||||
sbi(ENC28J60_SPI_PORT, ENC28J60_SPI_SCK); // set SCK hi
|
||||
sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_SCK); // set SCK as output
|
||||
cbi(ENC28J60_SPI_DDR, ENC28J60_SPI_MISO); // set MISO as input
|
||||
sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_MOSI); // set MOSI as output
|
||||
sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_SS); // SS must be output for Master mode to work
|
||||
// initialize SPI interface
|
||||
// master mode
|
||||
sbi(SPCR, MSTR);
|
||||
// select clock phase positive-going in middle of data
|
||||
cbi(SPCR, CPOL);
|
||||
// Data order MSB first
|
||||
cbi(SPCR,DORD);
|
||||
// switch to f/4 2X = f/2 bitrate
|
||||
cbi(SPCR, SPR0);
|
||||
cbi(SPCR, SPR1);
|
||||
sbi(SPSR, SPI2X);
|
||||
// enable SPI
|
||||
sbi(SPCR, SPE);
|
||||
// Wait for any current transmission to finish
|
||||
while(enc28j60_read_op(RCR, ECON1) & TXRTS){
|
||||
if(enc28j60_read(EIR) & TXERIF){
|
||||
enc28j60_write_op(BFS, ECON1, TXRST);
|
||||
enc28j60_write_op(BFC, ECON1, TXRST);
|
||||
}
|
||||
}
|
||||
|
||||
// perform system reset
|
||||
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
|
||||
/*
|
||||
* "After sending an SPI Reset command, the PHY
|
||||
* clock is stopped but the ESTAT.CLKRDY bit is not
|
||||
* cleared. Therefore, polling the CLKRDY bit will not
|
||||
* work to detect if the PHY is ready.
|
||||
*
|
||||
* Additionally, the hardware start-up time of 300 us
|
||||
* may expire before the device is ready to operate.
|
||||
*
|
||||
* Work around
|
||||
* After issuing the Reset command, wait at least
|
||||
* 1 ms in firmware for the device to be ready."
|
||||
*
|
||||
* Source: http://ww1.microchip.com/downloads/en/DeviceDoc/80349c.pdf
|
||||
*/
|
||||
_delay_ms(1);
|
||||
|
||||
// do bank 0 stuff
|
||||
// initialize receive buffer
|
||||
// 16-bit transfers, must write low byte first
|
||||
// set receive buffer start address
|
||||
NextPacketPtr = RXSTART_INIT;
|
||||
enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
|
||||
enc28j60Write(ERXSTH, RXSTART_INIT>>8);
|
||||
// set receive pointer address
|
||||
enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
|
||||
enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
|
||||
// set receive buffer end
|
||||
// ERXND defaults to 0x1FFF (end of ram)
|
||||
enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
|
||||
enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
|
||||
// set transmit buffer start
|
||||
// ETXST defaults to 0x0000 (beginnging of ram)
|
||||
enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
|
||||
enc28j60Write(ETXSTH, TXSTART_INIT>>8);
|
||||
|
||||
// do bank 2 stuff
|
||||
// enable MAC receive
|
||||
enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
|
||||
// bring MAC out of reset
|
||||
enc28j60Write(MACON2, 0x00);
|
||||
// enable automatic padding and CRC operations
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
|
||||
// set inter-frame gap (non-back-to-back)
|
||||
enc28j60Write(MAIPGL, 0x12);
|
||||
enc28j60Write(MAIPGH, 0x0C);
|
||||
// set inter-frame gap (back-to-back)
|
||||
enc28j60Write(MABBIPG, 0x12);
|
||||
// Set the maximum packet size which the controller will accept
|
||||
enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF);
|
||||
enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
|
||||
|
||||
// do bank 3 stuff
|
||||
// write MAC address
|
||||
// NOTE: MAC address in ENC28J60 is byte-backward
|
||||
enc28j60Write(MAADR5, macaddr[0]);
|
||||
enc28j60Write(MAADR4, macaddr[1]);
|
||||
enc28j60Write(MAADR3, macaddr[2]);
|
||||
enc28j60Write(MAADR2, macaddr[3]);
|
||||
enc28j60Write(MAADR1, macaddr[4]);
|
||||
enc28j60Write(MAADR0, macaddr[5]);
|
||||
|
||||
// no loopback of transmitted frames
|
||||
enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
|
||||
|
||||
// switch to bank 0
|
||||
enc28j60SetBank(ECON1);
|
||||
// enable interrutps
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
|
||||
// enable packet reception
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
}
|
||||
|
||||
void enc28j60PacketSend(unsigned int len1, unsigned char* packet1, unsigned int len2, unsigned char* packet2)
|
||||
{
|
||||
//Errata: Transmit Logic reset
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
|
||||
|
||||
// Set the write pointer to start of transmit buffer area
|
||||
enc28j60Write(EWRPTL, TXSTART_INIT&0xff);
|
||||
enc28j60Write(EWRPTH, TXSTART_INIT>>8);
|
||||
// Set the TXND pointer to correspond to the packet size given
|
||||
enc28j60Write(ETXNDL, (TXSTART_INIT+len1+len2));
|
||||
enc28j60Write(ETXNDH, (TXSTART_INIT+len1+len2)>>8);
|
||||
|
||||
// write per-packet control byte
|
||||
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
|
||||
|
||||
// copy the packet into the transmit buffer
|
||||
enc28j60WriteBuffer(len1, packet1);
|
||||
if(len2>0) enc28j60WriteBuffer(len2, packet2);
|
||||
|
||||
// send the contents of the transmit buffer onto the network
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
|
||||
}
|
||||
|
||||
unsigned int enc28j60PacketReceive(unsigned int maxlen, u08* buf)
|
||||
{
|
||||
u16 rxstat;
|
||||
u16 len;
|
||||
|
||||
// check if a packet has been received and buffered
|
||||
if( !enc28j60Read(EPKTCNT) )
|
||||
return 0;
|
||||
|
||||
// Set the read pointer to the start of the received packet
|
||||
enc28j60Write(ERDPTL, (NextPacketPtr));
|
||||
enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
|
||||
// read the next packet pointer
|
||||
NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
|
||||
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
|
||||
// read the packet length
|
||||
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
|
||||
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
|
||||
// read the receive status
|
||||
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
|
||||
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
|
||||
|
||||
// limit retrieve length
|
||||
// (we reduce the MAC-reported length by 4 to remove the CRC)
|
||||
len = MIN(len, maxlen);
|
||||
|
||||
// copy the packet from the receive buffer
|
||||
enc28j60ReadBuffer(len, buf);
|
||||
|
||||
// Move the RX read pointer to the start of the next received packet
|
||||
// This frees the memory we just read out
|
||||
enc28j60Write(ERXRDPTL, (NextPacketPtr));
|
||||
enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
|
||||
|
||||
// decrement the packet counter indicate we are done with this packet
|
||||
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
|
||||
|
||||
return len;
|
||||
enc28j60_write(EWRPTL, (TXSTART_INIT & 0xFF));
|
||||
enc28j60_write(EWRPTH, (TXSTART_INIT >> 8));
|
||||
enc28j60_write(ETXNDL, ((TXSTART_INIT + len) & 0xFF));
|
||||
enc28j60_write(ETXNDH, ((TXSTART_INIT + len) >> 8));
|
||||
enc28j60_write_op(WBM, 0, 0x00);
|
||||
enc28j60_write_buffer(buf, len);
|
||||
enc28j60_write_op(BFS, ECON1, TXRTS);
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ void setup_atmel_io_ports(){
|
||||
|
||||
// /pd_cdcd, /sync_code, /ce need to be 1 (disabled) to start
|
||||
// all bits are outputs, except PA7 (gps_lock) and PA3 (MISO_CDCE) are inputs
|
||||
PORTA = Bits_8(00110010);
|
||||
PORTA = Bits_8(00100010);
|
||||
DDRA = 1<<DDA6 | 1<<DDA5 | 1<<DDA4 | 1<<DDA2 | 1<<DDA1 | 1<<DDA0;
|
||||
|
||||
/*
|
||||
@ -90,8 +90,8 @@ DDRA = 1<<DDA6 | 1<<DDA5 | 1<<DDA4 | 1<<DDA2 | 1<<DDA1 | 1<<DDA0;
|
||||
*
|
||||
*/
|
||||
|
||||
PORTB = Bits_8(01100001); // Initial Value is all zeros
|
||||
DDRB = 1<<DDB2 | 1<<DDB4 | 1<<DDB7; // MOSI is an output; the Not Connected pins are also outputs
|
||||
PORTB = Bits_8(01100001); // Initial Value is all zeros
|
||||
DDRB = Bits_8(11110111); // MOSI is an output; the Not Connected pins are also outputs
|
||||
|
||||
/*
|
||||
* Port C
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include <debug.h>
|
||||
#include <octoclock.h>
|
||||
#include <state.h>
|
||||
#include <network.h>
|
||||
|
||||
#include <net/enc28j60.h>
|
||||
@ -34,12 +35,14 @@
|
||||
#include <net/if_arp.h>
|
||||
#include <net/ethertype.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
#include "arp_cache.h"
|
||||
|
||||
/***********************************************************************
|
||||
* Constants + Globals
|
||||
**********************************************************************/
|
||||
static const size_t out_buff_size = 512;
|
||||
static const size_t out_buff_size = ETH_BUF_SIZE;
|
||||
static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||
#define MAX_UDP_LISTENERS 10
|
||||
|
||||
@ -139,7 +142,7 @@ send_pkt(
|
||||
//grab an out buffer and pointer
|
||||
//select the output buffer based on type of packet
|
||||
uint8_t *p;
|
||||
p = buf_out;
|
||||
p = eth_buf;
|
||||
size_t total_len = 0;
|
||||
|
||||
//create a list of all buffers to copy
|
||||
@ -149,7 +152,7 @@ send_pkt(
|
||||
//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 - (uint8_t*)buf_out);
|
||||
size_t bytes_remaining = out_buff_size - (size_t)(p - (uint8_t*)eth_buf);
|
||||
if (lens[i] > bytes_remaining) lens[i] = bytes_remaining;
|
||||
memcpy(p, buffs[i], lens[i]);
|
||||
p += lens[i];
|
||||
@ -161,7 +164,7 @@ send_pkt(
|
||||
//For some reason, the ENC28J60 won't send the CRC
|
||||
//if you don't tell it to send another byte after
|
||||
//the given packet
|
||||
enc28j60PacketSend(total_len+1, buf_out, 0, 0);
|
||||
enc28j60_send(eth_buf, total_len);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -333,15 +336,15 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size)
|
||||
void
|
||||
handle_eth_packet(size_t recv_len)
|
||||
{
|
||||
eth_hdr_t *eth_hdr = (eth_hdr_t *)buf_in;
|
||||
eth_hdr_t *eth_hdr = (eth_hdr_t *)eth_buf;
|
||||
uint16_t ethertype = htons(eth_hdr->ethertype);
|
||||
|
||||
if (ethertype == ETHERTYPE_ARP){
|
||||
struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(buf_in + sizeof(eth_hdr_t));
|
||||
struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(eth_buf + sizeof(eth_hdr_t));
|
||||
handle_arp_packet(arp, recv_len-ETH_HLEN);
|
||||
}
|
||||
else if (ethertype == ETHERTYPE_IPV4){
|
||||
struct ip_hdr *ip = (struct ip_hdr *)(buf_in + sizeof(eth_hdr_t));
|
||||
struct ip_hdr *ip = (struct ip_hdr *)(eth_buf + sizeof(eth_hdr_t));
|
||||
|
||||
if (_IPH_V(ip) != 4 || _IPH_HL(ip) != 5) // ignore pkts w/ bad version or options
|
||||
return;
|
||||
@ -357,7 +360,7 @@ handle_eth_packet(size_t recv_len)
|
||||
bool is_my_ip = memcmp(&ip->dest, &htonl_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 *)buf_in)+6));
|
||||
arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)eth_buf)+6));
|
||||
|
||||
switch (_IPH_PROTO(ip)){
|
||||
case IP_PROTO_UDP:
|
||||
@ -381,7 +384,6 @@ handle_eth_packet(size_t recv_len)
|
||||
**********************************************************************/
|
||||
|
||||
static bool send_garp = false;
|
||||
static bool sent_initial_garp = false;
|
||||
static uint32_t num_overflows = 0;
|
||||
|
||||
// Six overflows is the closest overflow count to one minute.
|
||||
@ -390,6 +392,7 @@ ISR(TIMER1_OVF_vect){
|
||||
if(!(num_overflows % 6)) send_garp = true;
|
||||
}
|
||||
|
||||
// Send a GARP packet once per minute.
|
||||
static void
|
||||
send_gratuitous_arp(){
|
||||
send_garp = false;
|
||||
@ -415,18 +418,9 @@ send_gratuitous_arp(){
|
||||
|
||||
// Executed every loop
|
||||
void network_check(void){
|
||||
size_t recv_len = enc28j60PacketReceive(512, buf_in);
|
||||
size_t recv_len = enc28j60_recv(eth_buf, ETH_BUF_SIZE);
|
||||
if(recv_len > 0) handle_eth_packet(recv_len);
|
||||
|
||||
/*
|
||||
* Send a gratuitous ARP packet two seconds after Ethernet
|
||||
* initialization.
|
||||
*/
|
||||
if(!sent_initial_garp && (num_overflows == 0 && TCNT1 > (TIMER1_ONE_SECOND*2))){
|
||||
sent_initial_garp = true;
|
||||
send_garp = true;
|
||||
}
|
||||
|
||||
if(send_garp) send_gratuitous_arp();
|
||||
}
|
||||
|
||||
@ -435,9 +429,10 @@ void network_init(void){
|
||||
* Read MAC address from EEPROM and initialize Ethernet driver. If EEPROM is blank,
|
||||
* use default MAC address instead.
|
||||
*/
|
||||
eeprom_busy_wait();
|
||||
if(eeprom_read_byte(0) == 0xFF){
|
||||
_MAC_ADDR(_local_mac_addr.addr, 0x00,0x80,0x2F,0x11,0x22,0x33);
|
||||
_local_ip_addr.addr = default_ip;
|
||||
_local_ip_addr.addr = _IP(192,168,10,3);
|
||||
using_network_defaults = true;
|
||||
}
|
||||
else{
|
||||
@ -446,5 +441,8 @@ void network_init(void){
|
||||
using_network_defaults = false;
|
||||
}
|
||||
|
||||
enc28j60Init((uint8_t*)&_local_mac_addr);
|
||||
enc28j60_init((uint8_t*)&_local_mac_addr);
|
||||
init_udp_listeners();
|
||||
|
||||
send_garp = true;
|
||||
}
|
||||
|
||||
@ -15,110 +15,80 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#include <avrlibdefs.h>
|
||||
#include <debug.h>
|
||||
#include <octoclock.h>
|
||||
#include <clkdist.h>
|
||||
#include <state.h>
|
||||
|
||||
void led(LEDs which, int turn_it_on) {
|
||||
// Global state variables
|
||||
volatile bool g_ext_ref_present = false;
|
||||
volatile bool g_gps_present = false;
|
||||
volatile switch_pos_t g_switch_pos = PREFER_INTERNAL;
|
||||
volatile ref_t g_ref = NO_REF;
|
||||
|
||||
void led(led_t which, bool on){
|
||||
// selects the proper bit
|
||||
uint8_t LED = 0x20 << which;
|
||||
|
||||
if(turn_it_on)
|
||||
if(on)
|
||||
PORTC |= LED;
|
||||
else
|
||||
PORTC &= ~LED;
|
||||
}
|
||||
|
||||
void LEDs_Off(void){
|
||||
led(Top,false);
|
||||
led(Middle,false);
|
||||
led(Bottom,false);
|
||||
void leds_off(void){
|
||||
led(LED_TOP, false);
|
||||
led(LED_MIDDLE, false);
|
||||
led(LED_BOTTOM, false);
|
||||
}
|
||||
|
||||
void force_internal(void){
|
||||
led(Top,true);
|
||||
led(Middle,false);
|
||||
led(Bottom,true);
|
||||
static void force_internal(void){
|
||||
led(LED_TOP, true);
|
||||
led(LED_MIDDLE, false);
|
||||
led(LED_BOTTOM, true);
|
||||
|
||||
// Tell ClkDist chip to use internal signals
|
||||
cli();
|
||||
setup_TI_CDCE18005(Primary_GPS);
|
||||
sei();
|
||||
|
||||
// Set PPS to Primary (1) n.b.: "1" in general means "Internal" for all
|
||||
// such signals
|
||||
// Set PPS to internal
|
||||
PORTA |= (1<<PA6);
|
||||
}
|
||||
|
||||
void force_external(void){
|
||||
led(Top, false);
|
||||
led(Middle, true);
|
||||
led(Bottom, true);
|
||||
static void force_external(void){
|
||||
led(LED_TOP, false);
|
||||
led(LED_MIDDLE, true);
|
||||
led(LED_BOTTOM, true);
|
||||
|
||||
// Tell Clkdist chip to use external signals
|
||||
cli();
|
||||
setup_TI_CDCE18005(Secondary_Ext);
|
||||
sei();
|
||||
|
||||
// Set PPS to External
|
||||
// Set PPS to external
|
||||
PORTA &= ~(1<<PA6);
|
||||
}
|
||||
|
||||
void prefer_internal(void){
|
||||
// if internal is NOT OK, then force external
|
||||
if(global_gps_present)
|
||||
// If internal is NOT OK, then force external
|
||||
if(g_gps_present)
|
||||
force_internal();
|
||||
else if(global_ext_ref_is_present)
|
||||
else if(g_ext_ref_present)
|
||||
force_external();
|
||||
else
|
||||
LEDs_Off();
|
||||
leds_off();
|
||||
}
|
||||
|
||||
void prefer_external(void){
|
||||
// if external is NOT OK, then force internal
|
||||
if(global_ext_ref_is_present)
|
||||
// If external is NOT OK, then force internal
|
||||
if(g_ext_ref_present)
|
||||
force_external();
|
||||
else if(global_gps_present)
|
||||
else if(g_gps_present)
|
||||
force_internal();
|
||||
else
|
||||
LEDs_Off();
|
||||
}
|
||||
|
||||
static uint8_t prev_PE7 = 0;
|
||||
static uint32_t timer0_num_overflows = 0;
|
||||
|
||||
ISR(TIMER0_OVF_vect){
|
||||
global_gps_present = (PIND & (1<<DDD4));
|
||||
|
||||
// Every ~1/10 second
|
||||
if(!(timer0_num_overflows % 610)){
|
||||
prev_PE7 = (PINE & (1<<DDE7));
|
||||
|
||||
if(get_switch_pos() == UP) prefer_internal();
|
||||
else prefer_external();
|
||||
|
||||
global_ext_ref_is_present = false;
|
||||
}
|
||||
|
||||
if(!global_ext_ref_is_present){
|
||||
global_ext_ref_is_present = (prev_PE7 != (PINE & (1<<DDE7)));
|
||||
}
|
||||
|
||||
timer0_num_overflows++;
|
||||
}
|
||||
|
||||
ref_t which_ref(void){
|
||||
if(!global_gps_present && !global_ext_ref_is_present) global_which_ref = NO_REF;
|
||||
else if(global_gps_present && !global_ext_ref_is_present) global_which_ref = INTERNAL;
|
||||
else if(!global_gps_present && global_ext_ref_is_present) global_which_ref = EXTERNAL;
|
||||
else global_which_ref = (get_switch_pos() == UP) ? INTERNAL : EXTERNAL;
|
||||
|
||||
return global_which_ref;
|
||||
}
|
||||
|
||||
switch_pos_t get_switch_pos(void){
|
||||
uint8_t portC = PINC;
|
||||
|
||||
// UP is prefer internal,
|
||||
// DOWN is prefer external
|
||||
return (portC & (1<<DDC1)) ? DOWN : UP;
|
||||
leds_off();
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ void handle_udp_ctrl_packet(
|
||||
pkt_out.proto_ver = OCTOCLOCK_FW_COMPAT_NUM;
|
||||
pkt_out.sequence = pkt_in->sequence;
|
||||
|
||||
//If the firmware is incompatible, only respond to queries
|
||||
// If the firmware is incompatible, only respond to queries
|
||||
if(pkt_in->code == OCTOCLOCK_QUERY_CMD){
|
||||
pkt_out.code = OCTOCLOCK_QUERY_ACK;
|
||||
pkt_out.len = 0;
|
||||
@ -50,44 +50,43 @@ void handle_udp_ctrl_packet(
|
||||
|
||||
octoclock_fw_eeprom_t *eeprom_info = (octoclock_fw_eeprom_t*)pkt_out.data;
|
||||
|
||||
//Read values from EEPROM into packet
|
||||
// Read values from EEPROM into packet
|
||||
eeprom_busy_wait();
|
||||
eeprom_read_block(eeprom_info, 0, sizeof(octoclock_fw_eeprom_t));
|
||||
|
||||
//If EEPROM network fields are not fully populated, copy defaults
|
||||
// If EEPROM network fields are not fully populated, copy defaults
|
||||
if(using_network_defaults){
|
||||
_MAC_ADDR(eeprom_info->mac_addr, 0x00,0x80,0x2F,0x11,0x22,0x33);
|
||||
eeprom_info->ip_addr = default_ip;
|
||||
eeprom_info->dr_addr = default_dr;
|
||||
eeprom_info->netmask = default_netmask;
|
||||
eeprom_info->ip_addr = _IP(192,168,10,3);
|
||||
eeprom_info->dr_addr = _IP(192,168,10,1);
|
||||
eeprom_info->netmask = _IP(255,255,255,0);
|
||||
}
|
||||
|
||||
//Check if strings or revision is empty
|
||||
if(eeprom_info->serial[0] == 0xFF) memset(eeprom_info->serial, 0, 10);
|
||||
if(eeprom_info->name[0] == 0xFF) memset(eeprom_info->name, 0, 10);
|
||||
// Check if strings or revision is empty
|
||||
if(eeprom_info->revision == 0xFF) eeprom_info->revision = 0;
|
||||
break;
|
||||
|
||||
case BURN_EEPROM_CMD:{
|
||||
//Confirm length of data
|
||||
// Confirm length of data
|
||||
if(pkt_in->len != sizeof(octoclock_fw_eeprom_t)){
|
||||
pkt_out.code = BURN_EEPROM_FAILURE_ACK;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* In all cases, a full octoclock_fw_eeprom_t is written to lower the overall
|
||||
* number of writes due to this EEPROM's smaller amount of safe writes.
|
||||
* It is up to the host to make sure that the values that should be
|
||||
* preserved are present in the octoclock_fw_eeprom_t struct.
|
||||
*/
|
||||
const octoclock_fw_eeprom_t *eeprom_pkt = (octoclock_fw_eeprom_t*)pkt_in->data;
|
||||
pkt_out.len = 0;
|
||||
|
||||
//Write EEPROM data from packet
|
||||
// Write EEPROM data from packet
|
||||
eeprom_busy_wait();
|
||||
eeprom_write_block(eeprom_pkt, 0, sizeof(octoclock_fw_eeprom_t));
|
||||
|
||||
//Read back and compare to packet to confirm successful write
|
||||
// Read back and compare to packet to confirm successful write
|
||||
uint8_t eeprom_contents[sizeof(octoclock_fw_eeprom_t)];
|
||||
eeprom_busy_wait();
|
||||
eeprom_read_block(eeprom_contents, 0, sizeof(octoclock_fw_eeprom_t));
|
||||
uint8_t n = memcmp(eeprom_contents, eeprom_pkt, sizeof(octoclock_fw_eeprom_t));
|
||||
pkt_out.code = n ? BURN_EEPROM_FAILURE_ACK
|
||||
@ -99,12 +98,12 @@ void handle_udp_ctrl_packet(
|
||||
pkt_out.code = SEND_STATE_ACK;
|
||||
pkt_out.len = sizeof(octoclock_state_t);
|
||||
|
||||
//Populate octoclock_state_t fields
|
||||
// Populate octoclock_state_t fields
|
||||
octoclock_state_t *state = (octoclock_state_t*)pkt_out.data;
|
||||
state->external_detected = global_ext_ref_is_present ? 1 : 0;
|
||||
state->gps_detected = (PIND & _BV(DDD4)) ? 1 : 0;
|
||||
state->which_ref = (uint8_t)which_ref();
|
||||
state->switch_pos = (uint8_t)get_switch_pos();
|
||||
state->external_detected = g_ext_ref_present ? 1 : 0;
|
||||
state->gps_detected = g_gps_present ? 1 : 0;
|
||||
state->which_ref = (uint8_t)g_ref;
|
||||
state->switch_pos = (uint8_t)g_switch_pos;
|
||||
break;
|
||||
|
||||
case RESET_CMD:
|
||||
|
||||
@ -34,16 +34,8 @@ char usart_getc(void){
|
||||
return UDR1;
|
||||
}
|
||||
|
||||
char usart_getc_noblock(void){
|
||||
return ((UCSR1A & (1 << RXC))) ? UDR1 : -1;
|
||||
}
|
||||
|
||||
void usart_putc(char ch){
|
||||
while((UCSR1A & (1 << UDRE1)) == 0);
|
||||
|
||||
UDR1 = ch;
|
||||
}
|
||||
|
||||
void usart_putc_nowait(char ch){
|
||||
if((UCSR1A & (1 << UDRE1)) != 0) UDR1 = ch;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ add_custom_target(
|
||||
)
|
||||
add_custom_target(
|
||||
upload_r4
|
||||
${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x81:m -U lfuse:w:0xFF:m -U flash:w:octoclock_r4_fw.hex:i
|
||||
${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x81:m -U lfuse:w:0xEF:m -U flash:w:octoclock_r4_fw.hex:i
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS octoclock_r4_fw_hex
|
||||
COMMENT "Uploading OctoClock firmware to device with ${PROGRAMMER}"
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
* JTAGEN = [X]
|
||||
* SPIEN = [X]
|
||||
* EESAVE = [X]
|
||||
* BOOTSZ = 4096W_F000
|
||||
* BOOTSZ = 4095W_F000
|
||||
* BOOTRST = [ ]
|
||||
* CKOPT = [X]
|
||||
* BODLEVEL = 2V7
|
||||
@ -49,57 +49,165 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#include <avrlibdefs.h>
|
||||
#include <octoclock.h>
|
||||
#include <clkdist.h>
|
||||
#include <debug.h>
|
||||
#include <clkdist.h>
|
||||
#include <state.h>
|
||||
#include <network.h>
|
||||
#include <usart.h>
|
||||
#include <gpsdo.h>
|
||||
#include <net/enc28j60.h>
|
||||
#include <net/udp_handlers.h>
|
||||
|
||||
/*
|
||||
* Timer 3 (16-bit)
|
||||
* * Set input capture trigger to rising edge
|
||||
* * Set prescaler to 1
|
||||
* * Enable overflow interrupt
|
||||
* * Set timer to 0
|
||||
*/
|
||||
#define TIMER3_INIT() TCCR3B = (1 << ICES3) | (1 << CS30); \
|
||||
ETIMSK |= (1 << TOIE3); \
|
||||
TCNT3 = 0; \
|
||||
ICR3 = 0;
|
||||
|
||||
/*
|
||||
* We use TIMER3 as a watchdog timer for external reference
|
||||
* detection. Once a signal is detected, we allow for five
|
||||
* timer overflows (~26 ms) without another signal before
|
||||
* deciding that there is no external reference connected.
|
||||
*/
|
||||
#define EXT_REF_TIMEOUT 5
|
||||
|
||||
static volatile uint16_t num_overflows = 0;
|
||||
static uint16_t current_num_overflows = 0;
|
||||
static uint16_t prev_num_overflows = 0;
|
||||
static uint16_t current_ICR3 = 0;
|
||||
static uint16_t prev_ICR3 = 0;
|
||||
static ref_t prev_ref = NO_REF;
|
||||
static switch_pos_t prev_switch_pos = PREFER_EXTERNAL;
|
||||
bool top = false;
|
||||
|
||||
ISR(TIMER3_OVF_vect){
|
||||
num_overflows++;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Main Routine
|
||||
*******************************************************************************/
|
||||
|
||||
int main(void){
|
||||
|
||||
asm("cli");
|
||||
/*
|
||||
* Initializations
|
||||
*/
|
||||
cli();
|
||||
|
||||
// Make sure interrupts belong to us
|
||||
MCUCR = (1<<IVCE);
|
||||
MCUCR = 0;
|
||||
|
||||
// Initialize global variables
|
||||
g_ext_ref_present = false;
|
||||
g_gps_present = false;
|
||||
g_switch_pos = PREFER_INTERNAL;
|
||||
g_ref = NO_REF;
|
||||
|
||||
// Atmega128
|
||||
setup_atmel_io_ports();
|
||||
network_init();
|
||||
|
||||
#ifndef DEBUG
|
||||
asm("sei");
|
||||
#endif
|
||||
// Reset ClkDist chip
|
||||
reset_TI_CDCE18005();
|
||||
|
||||
init_udp_listeners();
|
||||
register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet);
|
||||
register_udp_listener(OCTOCLOCK_UDP_GPSDO_PORT, handle_udp_gpsdo_packet);
|
||||
|
||||
DEBUG_INIT(); // Does nothing when not in debug mode
|
||||
DEBUG_LOG(" "); //Force a newline between runs
|
||||
// GPSDO communication
|
||||
usart_init();
|
||||
|
||||
//Set initial ClkDist and front panel settings
|
||||
led(Middle,true);
|
||||
setup_TI_CDCE18005(Primary_GPS); // 10 MHz from Internal Source
|
||||
// Ethernet stack
|
||||
network_init();
|
||||
register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet);
|
||||
register_udp_listener(OCTOCLOCK_UDP_GPSDO_PORT, handle_udp_gpsdo_packet);
|
||||
|
||||
led(Top,true);
|
||||
PORTA |= (1<<PA6); // PPS from Internal source
|
||||
// Timers
|
||||
TIMER1_INIT(); // Network
|
||||
TIMER3_INIT(); // External reference check
|
||||
|
||||
TIMER0_INIT();
|
||||
TIMER1_INIT();
|
||||
// Debug (does nothing when not in debug mode)
|
||||
DEBUG_INIT();
|
||||
DEBUG_LOG(" "); // Force a newline between runs
|
||||
|
||||
while(true) {
|
||||
leds_off();
|
||||
|
||||
sei();
|
||||
|
||||
// Check if GPS present (should only need to happen once)
|
||||
g_gps_present = (PIND & (1<<DDD4));
|
||||
|
||||
// State of previous iteration
|
||||
prev_ref = NO_REF;
|
||||
prev_switch_pos = PREFER_EXTERNAL;
|
||||
cli();
|
||||
prev_ICR3 = ICR3;
|
||||
sei();
|
||||
prev_num_overflows = 0;
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
*/
|
||||
while(true){
|
||||
// Check switch position
|
||||
g_switch_pos = (PINC & (1<<DDC1)) ? PREFER_EXTERNAL : PREFER_INTERNAL;
|
||||
|
||||
/*
|
||||
* Check input capture pin for external reference detection.
|
||||
*
|
||||
* 16-bit reads could be corrupted during an interrupt, so
|
||||
* disable interrupts for safety.
|
||||
*/
|
||||
cli();
|
||||
current_ICR3 = ICR3;
|
||||
current_num_overflows = num_overflows;
|
||||
sei();
|
||||
|
||||
// Signal detected, reset timer
|
||||
if(current_ICR3 != prev_ICR3){
|
||||
cli();
|
||||
TCNT3 = 0;
|
||||
num_overflows = 0;
|
||||
sei();
|
||||
g_ext_ref_present = true;
|
||||
}
|
||||
|
||||
// Timeout, no external reference detected
|
||||
if(current_num_overflows >= EXT_REF_TIMEOUT){
|
||||
g_ext_ref_present = false;
|
||||
}
|
||||
|
||||
// Determine and set reference based on state
|
||||
if(!g_gps_present && !g_ext_ref_present) g_ref = NO_REF;
|
||||
else if(g_gps_present && !g_ext_ref_present) g_ref = INTERNAL;
|
||||
else if(!g_gps_present && g_ext_ref_present) g_ref = EXTERNAL;
|
||||
else g_ref = (g_switch_pos == PREFER_INTERNAL) ? INTERNAL : EXTERNAL;
|
||||
|
||||
if((g_ref != prev_ref) || (g_switch_pos != prev_switch_pos)){
|
||||
if(g_switch_pos == PREFER_INTERNAL) prefer_internal();
|
||||
else prefer_external();
|
||||
}
|
||||
|
||||
// Record this iteration's state
|
||||
prev_ref = g_ref;
|
||||
prev_switch_pos = g_switch_pos;
|
||||
prev_ICR3 = current_ICR3;
|
||||
prev_num_overflows = current_num_overflows;
|
||||
|
||||
// Handle incoming Ethernet packets
|
||||
network_check();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,41 +7,24 @@
|
||||
- Hardware Capabilities:
|
||||
- Fully integrated timing source with 8-Way distribution (10 MHz and 1 PPS)
|
||||
- User selection between internal GPSDO (when present) or external 10 MHz/1 PPS source
|
||||
- Ethernet bootloader for easy firmware upgrade
|
||||
- Source detection with automatic switch over in case of failure or disconnect
|
||||
- Streaming GPS time and NMEA strings over Ethernet (OctoClock-G only)
|
||||
|
||||
\section octoclock_load Loading Firmware onto the Octoclock
|
||||
|
||||
\subsection bootloader OctoClock bootloader
|
||||
|
||||
If you purchased your OctoClock device before Ethernet functionality was introduced, or if your unit's
|
||||
bootloader has somehow become corrupted, you must burn the bootloader onto the device before you can load
|
||||
the primary firmware.
|
||||
|
||||
To load the bootloader onto the OctoClock, two things are needed:
|
||||
|
||||
- AVR programmer
|
||||
- AVRdude software
|
||||
|
||||
Connect the AVR programmer to J108, as specified on the <a href="http://files.ettus.com/schematics/octoclock/octoclock.pdf">
|
||||
schematics</a>. Once you verify that the programmer is properly connected, run the following commands to burn the firmware:
|
||||
First, the OctoClock's bootloader needs to be loaded onto the device. Connect the AVR programmer to J108, as
|
||||
specified on the <a href="http://files.ettus.com/schematics/octoclock/octoclock.pdf">schematics</a>. Once you
|
||||
verify that the programmer is properly connected, run the following commands to load the bootloader:
|
||||
|
||||
cd <install path>/share/uhd/images
|
||||
avrdude -p atmega128 -c <programmer name> -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xFF:m -U flash:w:octoclock_bootloader.hex:i
|
||||
avrdude -p atmega128 -c <programmer name> -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xEF:m -U flash:w:octoclock_r4_fw.hex:i
|
||||
|
||||
When the bootloader is loaded, it will have a default IP address of `192.168.10.3`.
|
||||
|
||||
\b Note:
|
||||
On Linux, `sudo avrdude ...` might be necessary to gain access to the programmer.
|
||||
|
||||
Once the bootloader has been burned, power-cycle your OctoClock device and refer to the below instructions on burning the OctoClock's
|
||||
primary firmware.
|
||||
|
||||
\subsection application Primary Octoclock firmware
|
||||
|
||||
To load firmware onto the OctoClock, you must use the `octoclock_firmware_burner` utility, specifying the IP
|
||||
address of the OctoClock device, as follows:
|
||||
|
||||
octoclock_firmware_burner --addr=192.168.10.3
|
||||
|
||||
\section octoclock_network Setting Up Networking
|
||||
|
||||
\subsection host_interface Setting up the host interface
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 Ettus Research LLC
|
||||
* Copyright 2014-2015 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
|
||||
@ -42,11 +42,11 @@ extern "C" {
|
||||
* only valid C code should go in this section.
|
||||
*/
|
||||
|
||||
//These values are placed in the octoclock_packet_t.proto_ver field
|
||||
// These values are placed in the octoclock_packet_t.proto_ver field
|
||||
#define OCTOCLOCK_BOOTLOADER_PROTO_VER 1234
|
||||
#define OCTOCLOCK_FW_COMPAT_NUM 2
|
||||
#define OCTOCLOCK_FW_COMPAT_NUM 3
|
||||
|
||||
//UDP ports assigned for different tasks
|
||||
// UDP ports assigned for different tasks
|
||||
#define OCTOCLOCK_UDP_CTRL_PORT 50000
|
||||
#define OCTOCLOCK_UDP_GPSDO_PORT 50001
|
||||
#define OCTOCLOCK_UDP_FW_PORT 50002
|
||||
@ -98,11 +98,21 @@ typedef enum {
|
||||
} ref_t;
|
||||
|
||||
typedef enum {
|
||||
UP,
|
||||
DOWN
|
||||
PREFER_INTERNAL,
|
||||
PREFER_EXTERNAL
|
||||
} switch_pos_t;
|
||||
|
||||
/*
|
||||
* Some versions of AVR-GCC ignore #pragma pack, so
|
||||
* if AVR-GCC is being used, use __attribute__
|
||||
* instead.
|
||||
*/
|
||||
#ifdef AVR
|
||||
#define __AVR_ALIGNED__ __attribute__((aligned(1)))
|
||||
#else
|
||||
#define __AVR_ALIGNED__
|
||||
#pragma pack(push,1)
|
||||
#endif
|
||||
|
||||
// Structure of values in EEPROM, starting in location 0
|
||||
typedef struct {
|
||||
@ -113,34 +123,37 @@ typedef struct {
|
||||
uint8_t serial[10];
|
||||
uint8_t name[10];
|
||||
uint8_t revision;
|
||||
} octoclock_fw_eeprom_t;
|
||||
} octoclock_fw_eeprom_t __AVR_ALIGNED__;
|
||||
|
||||
typedef struct {
|
||||
uint8_t external_detected;
|
||||
uint8_t gps_detected;
|
||||
uint8_t which_ref;
|
||||
uint8_t switch_pos;
|
||||
} octoclock_state_t;
|
||||
} octoclock_state_t __AVR_ALIGNED__;
|
||||
|
||||
typedef struct {
|
||||
uint8_t num_wraps;
|
||||
uint8_t pos;
|
||||
} gpsdo_cache_state_t;
|
||||
} gpsdo_cache_state_t __AVR_ALIGNED__;
|
||||
|
||||
typedef struct {
|
||||
uint32_t proto_ver;
|
||||
uint32_t sequence;
|
||||
uint8_t code;
|
||||
union {
|
||||
uint16_t len;
|
||||
uint16_t crc;
|
||||
gpsdo_cache_state_t state;
|
||||
uint16_t poolsize;
|
||||
uint16_t addr;
|
||||
};
|
||||
uint8_t data[256];
|
||||
} octoclock_packet_t;
|
||||
uint16_t len;
|
||||
} octoclock_packet_t __AVR_ALIGNED__;
|
||||
|
||||
#ifndef AVR
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -357,14 +357,14 @@ void octoclock_impl::_get_state(const std::string &oc){
|
||||
}
|
||||
|
||||
uhd::dict<ref_t, std::string> _ref_strings = boost::assign::map_list_of
|
||||
(NO_REF, "none")
|
||||
(NO_REF, "none")
|
||||
(INTERNAL, "internal")
|
||||
(EXTERNAL, "external")
|
||||
;
|
||||
|
||||
uhd::dict<switch_pos_t, std::string> _switch_pos_strings = boost::assign::map_list_of
|
||||
(UP, "Prefer internal")
|
||||
(DOWN, "Prefer external")
|
||||
(PREFER_INTERNAL, "Prefer internal")
|
||||
(PREFER_EXTERNAL, "Prefer external")
|
||||
;
|
||||
|
||||
sensor_value_t octoclock_impl::_ext_ref_detected(const std::string &oc){
|
||||
@ -410,7 +410,7 @@ boost::uint32_t octoclock_impl::_get_time(const std::string &oc){
|
||||
}
|
||||
|
||||
std::string octoclock_impl::_get_images_help_message(const std::string &addr){
|
||||
const std::string image_name = "octoclock_r4_fw.bin";
|
||||
const std::string image_name = "octoclock_r4_fw.hex";
|
||||
|
||||
//Check to see if image is in default location
|
||||
std::string image_location;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2014 Ettus Research LLC
|
||||
// Copyright 2014-2015 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
|
||||
@ -74,8 +74,23 @@ boost::uint8_t firmware_image[MAX_FIRMWARE_SIZE];
|
||||
size_t firmware_size = 0;
|
||||
boost::uint8_t octoclock_data[udp_simple::mtu];
|
||||
octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t *>(octoclock_data);
|
||||
std::string firmware_path;
|
||||
std::string firmware_path, actual_firmware_path;
|
||||
size_t num_blocks = 0;
|
||||
bool hex = true;
|
||||
|
||||
static uint16_t calculate_crc(boost::uint8_t* buffer, boost::uint16_t len){
|
||||
boost::uint16_t crc = 0xFFFF;
|
||||
|
||||
for(size_t i = 0; i < len; i++){
|
||||
crc ^= buffer[i];
|
||||
for(boost::uint8_t j = 0; j < 8; ++j){
|
||||
if(crc & 1) crc = (crc >> 1) ^ 0xA001;
|
||||
else crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions
|
||||
@ -121,26 +136,25 @@ device_addrs_t bootloader_find(const std::string &ip_addr){
|
||||
}
|
||||
|
||||
void read_firmware(){
|
||||
std::ifstream firmware_file(firmware_path.c_str(), std::ios::binary);
|
||||
firmware_file.seekg(0, std::ios::end);
|
||||
firmware_size = size_t(firmware_file.tellg());
|
||||
std::ifstream firmware_file(actual_firmware_path.c_str(), std::ios::binary);
|
||||
firmware_size = size_t(fs::file_size(actual_firmware_path));
|
||||
if(firmware_size > MAX_FIRMWARE_SIZE){
|
||||
firmware_file.close();
|
||||
throw uhd::runtime_error(str(boost::format("Firmware file too large: %d > %d")
|
||||
% firmware_size % (MAX_FIRMWARE_SIZE)));
|
||||
}
|
||||
firmware_file.seekg(0, std::ios::beg);
|
||||
firmware_file.read((char*)firmware_image, firmware_size);
|
||||
firmware_file.close();
|
||||
|
||||
num_blocks = (firmware_size % BLOCK_SIZE) ? (firmware_size / BLOCK_SIZE)
|
||||
: ((firmware_size / BLOCK_SIZE) + 1);
|
||||
num_blocks = (firmware_size % BLOCK_SIZE) ? ((firmware_size / BLOCK_SIZE) + 1)
|
||||
: (firmware_size / BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void burn_firmware(udp_simple::sptr udp_transport){
|
||||
octoclock_packet_t pkt_out;
|
||||
pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand());
|
||||
pkt_out.len = uhd::htonx<boost::uint16_t>((boost::uint16_t)firmware_size);
|
||||
pkt_out.len = (boost::uint16_t)firmware_size;
|
||||
pkt_out.crc = calculate_crc(firmware_image, firmware_size);
|
||||
size_t len = 0, current_pos = 0;
|
||||
|
||||
//Tell OctoClock not to jump to application, wait for us instead
|
||||
@ -149,6 +163,7 @@ void burn_firmware(udp_simple::sptr udp_transport){
|
||||
if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)) std::cout << "ready." << std::endl;
|
||||
else{
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Could not get OctoClock in valid state for firmware download.");
|
||||
}
|
||||
|
||||
@ -165,7 +180,7 @@ void burn_firmware(udp_simple::sptr udp_transport){
|
||||
<< "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush;
|
||||
|
||||
memset(pkt_out.data, 0, BLOCK_SIZE);
|
||||
memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], std::min(int(firmware_size-current_pos), BLOCK_SIZE));
|
||||
memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], BLOCK_SIZE);
|
||||
|
||||
bool success = false;
|
||||
while(num_tries <= 5){
|
||||
@ -181,6 +196,7 @@ void burn_firmware(udp_simple::sptr udp_transport){
|
||||
}
|
||||
if(not success){
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Failed to burn firmware to OctoClock!");
|
||||
}
|
||||
|
||||
@ -196,7 +212,6 @@ void verify_firmware(udp_simple::sptr udp_transport){
|
||||
pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand());
|
||||
size_t len = 0, current_pos = 0;
|
||||
|
||||
|
||||
for(size_t i = 0; i < num_blocks; i++){
|
||||
pkt_out.sequence++;
|
||||
pkt_out.addr = i*BLOCK_SIZE;
|
||||
@ -208,11 +223,13 @@ void verify_firmware(udp_simple::sptr udp_transport){
|
||||
if(memcmp((void*)(pkt_in->data), &firmware_image[i*BLOCK_SIZE],
|
||||
std::min(int(firmware_size-current_pos), BLOCK_SIZE))){
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Failed to verify OctoClock firmware!");
|
||||
}
|
||||
}
|
||||
else{
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Failed to verify OctoClock firmware!");
|
||||
}
|
||||
}
|
||||
@ -230,6 +247,7 @@ bool reset_octoclock(const std::string &ip_addr){
|
||||
UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, RESET_CMD, pkt_out, len, octoclock_data);
|
||||
if(not UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Failed to place device in state to receive firmware.");
|
||||
}
|
||||
|
||||
@ -246,11 +264,13 @@ void finalize(udp_simple::sptr udp_transport){
|
||||
UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data);
|
||||
if(not UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
std::cout << "no ACK. Bootloader may not have loaded application." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){
|
||||
|
||||
std::string ip_addr;
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
@ -300,7 +320,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
throw uhd::runtime_error(str(boost::format("This filepath does not exist: %s") % firmware_path));
|
||||
}
|
||||
}
|
||||
else firmware_path = find_image_path("octoclock_r4_fw.bin");
|
||||
else firmware_path = find_image_path("octoclock_r4_fw.hex");
|
||||
|
||||
//If Intel hex file detected, convert to binary
|
||||
std::string ext = fs::extension(firmware_path);
|
||||
@ -312,9 +332,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
% time_spec_t::get_system_time().get_full_secs()));
|
||||
Hex2Bin(firmware_path.c_str(), temp_bin.string().c_str(), false);
|
||||
|
||||
firmware_path = temp_bin.string();
|
||||
actual_firmware_path = temp_bin.string();
|
||||
}
|
||||
else if(ext == ".bin"){
|
||||
hex = false;
|
||||
actual_firmware_path = firmware_path;
|
||||
std::cout << "Found firmware at path: " << firmware_path << std::endl;
|
||||
}
|
||||
else throw uhd::runtime_error("The firmware file has in improper extension (must be .hex or .bin).");
|
||||
@ -327,6 +349,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
if(reset_octoclock(ip_addr)) std::cout << "successful." << std::endl;
|
||||
else{
|
||||
std::cout << "failed." << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Failed to reset OctoClock device into its bootloader.");
|
||||
}
|
||||
}
|
||||
@ -334,6 +357,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
}
|
||||
else{
|
||||
std::cout << "failed." << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Could not find OctoClock with given IP address!");
|
||||
}
|
||||
|
||||
@ -354,7 +378,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
if(octoclocks.size() == 1){
|
||||
if(octoclocks[0]["type"] == "octoclock-bootloader"){
|
||||
std::cout << std::endl;
|
||||
throw uhd::runtime_error("OctoClock failed to leave bootloader state.");
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Firmware did not load properly.");
|
||||
}
|
||||
else{
|
||||
std::cout << "found." << std::endl << std::endl
|
||||
@ -363,8 +388,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
|
||||
}
|
||||
else{
|
||||
std::cout << std::endl;
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
throw uhd::runtime_error("Failed to reinitialize OctoClock.");
|
||||
}
|
||||
if(hex) fs::remove(actual_firmware_path);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user