aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/octoclock/bootloader/CMakeLists.txt2
-rw-r--r--firmware/octoclock/bootloader/main.c40
-rw-r--r--firmware/octoclock/include/debug.h23
-rw-r--r--firmware/octoclock/include/net/eth_mac_addr.h2
-rw-r--r--firmware/octoclock/include/network.h20
-rw-r--r--firmware/octoclock/include/octoclock.h21
-rw-r--r--firmware/octoclock/include/state.h8
-rw-r--r--firmware/octoclock/lib/CMakeLists.txt2
-rw-r--r--firmware/octoclock/lib/enc28j60.c19
-rw-r--r--firmware/octoclock/lib/network.c87
-rw-r--r--firmware/octoclock/lib/state.c32
-rw-r--r--firmware/octoclock/lib/udp_handlers.c28
-rw-r--r--firmware/octoclock/octoclock_r4/CMakeLists.txt3
-rw-r--r--firmware/octoclock/octoclock_r4/octoclock_r4_main.c71
-rw-r--r--host/lib/usrp_clock/octoclock/octoclock_impl.cpp9
-rw-r--r--host/utils/octoclock_firmware_burner.cpp57
16 files changed, 236 insertions, 188 deletions
diff --git a/firmware/octoclock/bootloader/CMakeLists.txt b/firmware/octoclock/bootloader/CMakeLists.txt
index eecb87002..04bcfc492 100644
--- a/firmware/octoclock/bootloader/CMakeLists.txt
+++ b/firmware/octoclock/bootloader/CMakeLists.txt
@@ -31,7 +31,7 @@ add_executable(octoclock_bootloader.elf ${bootloader_sources})
# Details: http://savannah.nongnu.org/bugs/?36410
#
set_target_properties(octoclock_bootloader.elf PROPERTIES
- COMPILE_FLAGS "${CMAKE_C_FLAGS} -Os -D__AVR_LIBC_DEPRECATED_ENABLE__ -Wall"
+ COMPILE_FLAGS "${CMAKE_C_FLAGS} -Os -D__AVR_LIBC_DEPRECATED_ENABLE__ -D__BOOTLOADER__ -Wall"
LINK_FLAGS "-Os -Wl,--relax,--section-start=.text=0x1E000,-Map=octoclock_bootloader.map,--cref"
)
diff --git a/firmware/octoclock/bootloader/main.c b/firmware/octoclock/bootloader/main.c
index b2f6730ac..5e2e6f17e 100644
--- a/firmware/octoclock/bootloader/main.c
+++ b/firmware/octoclock/bootloader/main.c
@@ -28,12 +28,17 @@
#include <debug.h>
#include <network.h>
+#include <util/delay.h>
+
#include <net/enc28j60.h>
#include "octoclock/common.h"
-#define wait() for(uint16_t u=4000; u; u--) asm("nop");
-#define TIME_PASSED (TCNT1 > FIVE_SECONDS || (TIFR & _BV(TOV1)))
+/*
+ * The number for 5 seconds is close enough to 65535 that the
+ * timer may have overflowed before the main loop queries it.
+ */
+#define TIME_PASSED (TCNT1 > (TIMER1_ONE_SECOND*5) || (TIFR & _BV(TOV1)))
//States
static bool received_cmd = false;
@@ -83,8 +88,7 @@ void handle_udp_query_packet(
const octoclock_packet_t *pkt_in = (octoclock_packet_t*)payload;
//Respond to query packets
- if(pkt_in->proto_ver == OCTOCLOCK_FW_COMPAT_NUM &&
- pkt_in->code == OCTOCLOCK_QUERY_CMD){
+ 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;
@@ -134,7 +138,6 @@ void handle_udp_fw_packet(
case FILE_TRANSFER_CMD:
boot_program_page(pkt_in->data, pkt_in->addr);
- wait(); //Necessary for some reason
pkt_out.code = FILE_TRANSFER_ACK;
break;
@@ -144,7 +147,7 @@ void handle_udp_fw_packet(
break;
case FINALIZE_BURNING_CMD:
- //With stuff verified, burn values into EEPROM
+ //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);
@@ -196,17 +199,12 @@ int main(void){
register_udp_listener(OCTOCLOCK_UDP_FW_PORT, handle_udp_fw_packet);
register_udp_listener(OCTOCLOCK_UDP_EEPROM_PORT, handle_udp_eeprom_packet);
- /*
- * Initialize AVR timer. This will be used to detect how much time has gone
- * by with no contact from the octoclock_burn_firmware utility. If 5 seconds go by
- * with no PREPARE_FW_BURN_CMD packet, the bootloader will jump into the
- * existing application.
- *
- * This timer is polled by the main loop with each iteration instead of using
- * an interrupt.
- */
- TCCR1B = (1 << CS12) | (1 << CS10);
- TCNT1 = 0;
+ //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;
while(true){
@@ -219,10 +217,14 @@ int main(void){
if(valid_app()) break;
}
- size_t recv_len = enc28j60PacketReceive(512, buf_in);
- if(recv_len > 0) handle_eth_packet(recv_len);
+ network_check();
}
+ //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
diff --git a/firmware/octoclock/include/debug.h b/firmware/octoclock/include/debug.h
index 3b89140f6..ee0618bc6 100644
--- a/firmware/octoclock/include/debug.h
+++ b/firmware/octoclock/include/debug.h
@@ -18,7 +18,8 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
-#if DEBUG
+//Only expose these macros to the firmware, and only if specified
+#if defined(DEBUG) && !defined(__BOOTLOADER__)
#include <avr/pgmspace.h>
#include <stdbool.h>
@@ -41,17 +42,17 @@
#define DEBUG_LOG_CHAR_ARR(arr,len) DEBUG_LOG_CHAR_ARR_NNL(arr,len); \
DEBUG_LOG(" ")
-#define DEBUG_LOG_MAC(mac_addr) DEBUG_LOG_HEX_NNL(mac_addr.addr[0]); \
+#define DEBUG_LOG_MAC(mac_addr) DEBUG_LOG_HEX_NNL(mac_addr[0]); \
DEBUG_LOG_NNL(":"); \
- DEBUG_LOG_HEX_NNL(mac_addr.addr[1]); \
+ DEBUG_LOG_HEX_NNL(mac_addr[1]); \
DEBUG_LOG_NNL(":"); \
- DEBUG_LOG_HEX_NNL(mac_addr.addr[2]); \
+ DEBUG_LOG_HEX_NNL(mac_addr[2]); \
DEBUG_LOG_NNL(":"); \
- DEBUG_LOG_HEX_NNL(mac_addr.addr[3]); \
+ DEBUG_LOG_HEX_NNL(mac_addr[3]); \
DEBUG_LOG_NNL(":"); \
- DEBUG_LOG_HEX_NNL(mac_addr.addr[4]); \
+ DEBUG_LOG_HEX_NNL(mac_addr[4]); \
DEBUG_LOG_NNL(":"); \
- DEBUG_LOG_HEX(mac_addr.addr[5]);
+ DEBUG_LOG_HEX(mac_addr[5]);
#define DEBUG_LOG_IP(ip_addr) DEBUG_LOG_BYTE_NNL(ip4_addr1(&ip_addr)); \
DEBUG_LOG_NNL("."); \
@@ -62,7 +63,12 @@
DEBUG_LOG_BYTE(ip4_addr4(&ip_addr));
#define DEBUG_LOG_SHORT(num) DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[1]); \
- DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[0]);
+ 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(((uint8_t*)&num)[0]);
#else
@@ -81,6 +87,7 @@
#define DEBUG_LOG_MAC(mac_addr)
#define DEBUG_LOG_IP(ip_addr)
#define DEBUG_LOG_SHORT(num)
+#define DEBUG_LOG_INT(num)
#endif
diff --git a/firmware/octoclock/include/net/eth_mac_addr.h b/firmware/octoclock/include/net/eth_mac_addr.h
index cb6fb234b..0c790aa4f 100644
--- a/firmware/octoclock/include/net/eth_mac_addr.h
+++ b/firmware/octoclock/include/net/eth_mac_addr.h
@@ -22,8 +22,10 @@
// Ethernet MAC address
+#pragma pack(push,1)
typedef struct {
uint8_t addr[6];
} eth_mac_addr_t;
+#pragma pack(pop)
#endif /* INCLUDED_ETH_MAC_ADDR_H */
diff --git a/firmware/octoclock/include/network.h b/firmware/octoclock/include/network.h
index 69c1dcf42..83e398bc5 100644
--- a/firmware/octoclock/include/network.h
+++ b/firmware/octoclock/include/network.h
@@ -41,6 +41,15 @@
#define ntohl(n) htonl(n)
+#define _MAC_ADDR(mac_addr,a,b,c,d,e,f) mac_addr[0] = a; \
+ mac_addr[1] = b; \
+ mac_addr[2] = c; \
+ mac_addr[3] = d; \
+ mac_addr[4] = e; \
+ mac_addr[5] = f;
+
+#define _MAC_SET_EQUAL(mac_addr1,mac_addr2) for(uint8_t i = 0; i < 6; i++) mac_addr1[i] = mac_addr2[i];
+
#define _IP(a,b,c,d) (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | ((uint32_t)d << 0))
#define _IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
#define _IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
@@ -60,11 +69,7 @@
#define _IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (_IPH_TTL(hdr) << 8)))
#define _IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
-// Global network values
-eth_mac_addr_t octoclock_mac_addr;
-struct ip_addr octoclock_ip_addr;
-struct ip_addr octoclock_dr_addr;
-struct ip_addr octoclock_netmask;
+bool using_network_defaults;
// Ethernet I/O buffers
uint8_t buf_in[512];
@@ -76,9 +81,6 @@ 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);
-static const uint8_t blank_eeprom_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-static const uint8_t default_mac[6] = {0x00, 0x80, 0x2F, 0x11, 0x22, 0x33};
-
typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len);
@@ -93,6 +95,8 @@ void send_udp_pkt(int src_port, struct socket_address dst,
void handle_eth_packet(size_t recv_len);
+void network_check(void);
+
void network_init(void);
#endif /* INCLUDED_NETWORK_H */
diff --git a/firmware/octoclock/include/octoclock.h b/firmware/octoclock/include/octoclock.h
index 3c6254eba..849ab7f96 100644
--- a/firmware/octoclock/include/octoclock.h
+++ b/firmware/octoclock/include/octoclock.h
@@ -27,14 +27,25 @@
#define F_CPU 12500000UL
/*
- * Working with the AVR timer
+ * Timer 0 (8-bit)
+ * * Set prescaler to 8
+ * * Enable overflow interrupt
+ * * Set timer to 0
*/
-// Prescaler: 1024, Timer: 0
-#define TIMER_INIT() TCCR1B = (1 << CS12) | (1 << CS10); \
+#define TIMER0_INIT() TCCR0 = (1 << CS01); \
+ TIMSK |= (1 << TOIE0); \
+ TCNT0 = 0;
+/*
+ * Timer 1 (16-bit)
+ * * Set prescaler to 1024
+ * * Enable overflow interrupt
+ * * Set timer to 0
+ */
+#define TIMER1_INIT() TCCR1B = (1 << CS12) | (1 << CS10); \
+ TIMSK |= (1<<TOIE1); \
TCNT1 = 0;
-#define TENTH_SECOND 13
-#define FIVE_SECONDS 61035
+#define TIMER1_ONE_SECOND ((uint32_t)(12207))
// Locations of OctoClock information in EEPROM
#define OCTOCLOCK_EEPROM_MAC_ADDR 0
diff --git a/firmware/octoclock/include/state.h b/firmware/octoclock/include/state.h
index b11cae397..9734948cf 100644
--- a/firmware/octoclock/include/state.h
+++ b/firmware/octoclock/include/state.h
@@ -27,8 +27,6 @@ static ref_t global_which_ref = NO_REF;
static bool global_gps_present = false;
static bool global_ext_ref_is_present = false;
-volatile uint8_t ext_ref_buf[1024];
-
void led(LEDs which, int turn_it_on);
void LEDs_off(void);
@@ -39,14 +37,8 @@ void prefer_internal(void);
void prefer_external(void);
-bool is_ext_ref_present(void);
-
-bool is_gps_present(void);
-
ref_t which_ref(void);
-void check_what_is_present(void);
-
switch_pos_t get_switch_pos(void);
#endif /* _STATE_H_ */
diff --git a/firmware/octoclock/lib/CMakeLists.txt b/firmware/octoclock/lib/CMakeLists.txt
index 006af287a..3c992399e 100644
--- a/firmware/octoclock/lib/CMakeLists.txt
+++ b/firmware/octoclock/lib/CMakeLists.txt
@@ -33,5 +33,5 @@ ENDIF(OCTOCLOCK_DEBUG)
ADD_LIBRARY(octoclock ${lib_files})
SET_TARGET_PROPERTIES(octoclock
- PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -O2"
+ PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -O2 -g"
)
diff --git a/firmware/octoclock/lib/enc28j60.c b/firmware/octoclock/lib/enc28j60.c
index 0e8c1fa3c..f0bbee0e7 100644
--- a/firmware/octoclock/lib/enc28j60.c
+++ b/firmware/octoclock/lib/enc28j60.c
@@ -198,8 +198,23 @@ void enc28j60Init(u08* macaddr)
// perform system reset
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
- // check CLKRDY bit to see if reset is complete
- _delay_us(51);
+
+ /*
+ * "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
diff --git a/firmware/octoclock/lib/network.c b/firmware/octoclock/lib/network.c
index b7de18f3d..bb49de4f6 100644
--- a/firmware/octoclock/lib/network.c
+++ b/firmware/octoclock/lib/network.c
@@ -19,11 +19,13 @@
#include <string.h>
#include <avr/eeprom.h>
+#include <avr/interrupt.h>
#include <lwip/ip.h>
#include <lwip/udp.h>
#include <lwip/icmp.h>
+#include <debug.h>
#include <octoclock.h>
#include <network.h>
@@ -61,10 +63,6 @@ static uint32_t chksum_buffer(
**********************************************************************/
static eth_mac_addr_t _local_mac_addr;
static struct ip_addr _local_ip_addr;
-void register_addrs(const eth_mac_addr_t *mac_addr, const struct ip_addr *ip_addr){
- _local_mac_addr = *mac_addr;
- _local_ip_addr = *ip_addr;
-}
struct listener_entry {
unsigned short port;
@@ -378,28 +376,75 @@ handle_eth_packet(size_t recv_len)
return; // Not ARP or IPV4, ignore
}
-void network_init(void){
+/***********************************************************************
+ * Timer+GARP stuff
+ **********************************************************************/
+
+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.
+ISR(TIMER1_OVF_vect){
+ num_overflows++;
+ if(!(num_overflows % 6)) send_garp = true;
+}
+
+static void
+send_gratuitous_arp(){
+ send_garp = false;
+
+ //Need to htonl IP address
+ struct ip_addr htonl_ip_addr;
+ htonl_ip_addr.addr = htonl(_local_ip_addr.addr);
+
+ struct arp_eth_ipv4 req _AL4;
+ req.ar_hrd = htons(ARPHRD_ETHER);
+ req.ar_pro = htons(ETHERTYPE_IPV4);
+ req.ar_hln = sizeof(eth_mac_addr_t);
+ req.ar_pln = sizeof(struct ip_addr);
+ req.ar_op = htons(ARPOP_REQUEST);
+ memcpy(req.ar_sha, &_local_mac_addr, sizeof(eth_mac_addr_t));
+ memcpy(req.ar_sip, &htonl_ip_addr, sizeof(struct ip_addr));
+ memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t));
+ memcpy(req.ar_tip, &htonl_ip_addr, sizeof(struct ip_addr));
+
+ //Send the request with the broadcast MAC address
+ send_pkt(BCAST_MAC_ADDR, htons(ETHERTYPE_ARP), &req, sizeof(req), 0, 0, 0, 0);
+}
+
+// Executed every loop
+void network_check(void){
+ size_t recv_len = enc28j60PacketReceive(512, buf_in);
+ if(recv_len > 0) handle_eth_packet(recv_len);
/*
- * Read MAC address from EEPROM and initialize Ethernet driver. If EEPROM is blank,
- * use default MAC address instead.
+ * Send a gratuitous ARP packet two seconds after Ethernet
+ * initialization.
*/
- eeprom_read_block((void*)octoclock_mac_addr.addr, (void*)OCTOCLOCK_EEPROM_MAC_ADDR, 6);
- if(!memcmp(&octoclock_mac_addr, blank_eeprom_mac, 6)) memcpy(octoclock_mac_addr.addr, default_mac, 6);
-
- enc28j60Init((uint8_t*)&octoclock_mac_addr);
+ if(!sent_initial_garp && (num_overflows == 0 && TCNT1 > (TIMER1_ONE_SECOND*2))){
+ sent_initial_garp = true;
+ send_garp = true;
+ }
- eeprom_read_block((void*)&octoclock_ip_addr, (void*)OCTOCLOCK_EEPROM_IP_ADDR, 4);
- eeprom_read_block((void*)&octoclock_dr_addr, (void*)OCTOCLOCK_EEPROM_DR_ADDR, 4);
- eeprom_read_block((void*)&octoclock_netmask, (void*)OCTOCLOCK_EEPROM_NETMASK, 4);
+ if(send_garp) send_gratuitous_arp();
+}
- //In case of blank EEPROM, load default values
- if(octoclock_ip_addr.addr == blank_eeprom_ip || octoclock_dr_addr.addr == blank_eeprom_ip ||
- octoclock_netmask.addr == blank_eeprom_ip){
- octoclock_ip_addr.addr = default_ip;
- octoclock_dr_addr.addr = default_dr;
- octoclock_netmask.addr = default_netmask;
+void network_init(void){
+ /*
+ * Read MAC address from EEPROM and initialize Ethernet driver. If EEPROM is blank,
+ * use default MAC address instead.
+ */
+ if(eeprom_read_byte(0) == 0xFF){
+ _MAC_ADDR(_local_mac_addr.addr, 0x00,0x80,0x2F,0x11,0x22,0x33);
+ _local_ip_addr.addr = default_ip;
+ using_network_defaults = true;
+ }
+ else{
+ eeprom_read_block((void*)&_local_mac_addr, (void*)OCTOCLOCK_EEPROM_MAC_ADDR, 6);
+ eeprom_read_block((void*)&_local_ip_addr, (void*)OCTOCLOCK_EEPROM_IP_ADDR, 4);
+ using_network_defaults = false;
}
- register_addrs(&octoclock_mac_addr, &octoclock_ip_addr);
+ enc28j60Init((uint8_t*)&_local_mac_addr);
}
diff --git a/firmware/octoclock/lib/state.c b/firmware/octoclock/lib/state.c
index 2adab6fc4..0dbcc6ece 100644
--- a/firmware/octoclock/lib/state.c
+++ b/firmware/octoclock/lib/state.c
@@ -83,20 +83,27 @@ void prefer_external(void){
LEDs_Off();
}
-bool is_ext_ref_present(void){
- volatile uint8_t prev = (PINE & (1<<DDE7));
- volatile uint8_t now;
+static uint8_t prev_PE7 = 0;
+static uint32_t timer0_num_overflows = 0;
- for(uint16_t i = 1; i < 512; i++){
- now = (PINE & (1<<DDE7));
- if(prev != now) return true;
+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;
}
- return false;
-}
+ if(!global_ext_ref_is_present){
+ global_ext_ref_is_present = (prev_PE7 != (PINE & (1<<DDE7)));
+ }
-bool is_gps_present(void){
- return (PIND & (1<<DDD4));
+ timer0_num_overflows++;
}
ref_t which_ref(void){
@@ -108,11 +115,6 @@ ref_t which_ref(void){
return global_which_ref;
}
-void check_what_is_present(void){
- global_ext_ref_is_present = is_ext_ref_present();
- global_gps_present = is_gps_present();
-}
-
switch_pos_t get_switch_pos(void){
uint8_t portC = PINC;
diff --git a/firmware/octoclock/lib/udp_handlers.c b/firmware/octoclock/lib/udp_handlers.c
index daf2a7612..1f20112c9 100644
--- a/firmware/octoclock/lib/udp_handlers.c
+++ b/firmware/octoclock/lib/udp_handlers.c
@@ -36,13 +36,14 @@ void handle_udp_ctrl_packet(
pkt_out.proto_ver = OCTOCLOCK_FW_COMPAT_NUM;
pkt_out.sequence = pkt_in->sequence;
- if(pkt_in->proto_ver == OCTOCLOCK_FW_COMPAT_NUM){
+ //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;
+ send_udp_pkt(OCTOCLOCK_UDP_CTRL_PORT, src, (void*)&pkt_out, sizeof(octoclock_packet_t));
+ }
+ else if(pkt_in->proto_ver == OCTOCLOCK_FW_COMPAT_NUM){
switch(pkt_in->code){
- case OCTOCLOCK_QUERY_CMD:
- pkt_out.code = OCTOCLOCK_QUERY_ACK;
- pkt_out.len = 0;
- break;
-
case SEND_EEPROM_CMD:
pkt_out.code = SEND_EEPROM_ACK;
pkt_out.len = sizeof(octoclock_fw_eeprom_t);
@@ -50,14 +51,11 @@ void handle_udp_ctrl_packet(
octoclock_fw_eeprom_t *eeprom_info = (octoclock_fw_eeprom_t*)pkt_out.data;
//Read values from EEPROM into packet
- eeprom_read_block(eeprom_info, (void*)0, sizeof(octoclock_fw_eeprom_t));
+ eeprom_read_block(eeprom_info, 0, sizeof(octoclock_fw_eeprom_t));
//If EEPROM network fields are not fully populated, copy defaults
- if(eeprom_read_byte((uint8_t*)OCTOCLOCK_EEPROM_IP_ADDR) == 0xFF ||
- eeprom_read_byte((uint8_t*)OCTOCLOCK_EEPROM_DR_ADDR) == 0xFF ||
- eeprom_read_byte((uint8_t*)OCTOCLOCK_EEPROM_MAC_ADDR) == 0xFF){
-
- memcpy(eeprom_info->mac_addr, default_mac, 6);
+ 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;
@@ -86,11 +84,11 @@ void handle_udp_ctrl_packet(
pkt_out.len = 0;
//Write EEPROM data from packet
- eeprom_write_block(eeprom_pkt, (void*)0, sizeof(octoclock_fw_eeprom_t));
+ eeprom_write_block(eeprom_pkt, 0, sizeof(octoclock_fw_eeprom_t));
//Read back and compare to packet to confirm successful write
uint8_t eeprom_contents[sizeof(octoclock_fw_eeprom_t)];
- eeprom_read_block(eeprom_contents, (void*)0, sizeof(octoclock_fw_eeprom_t));
+ 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
: BURN_EEPROM_SUCCESS_ACK;
@@ -103,7 +101,7 @@ void handle_udp_ctrl_packet(
//Populate octoclock_state_t fields
octoclock_state_t *state = (octoclock_state_t*)pkt_out.data;
- state->external_detected = (is_ext_ref_present()) ? 1 : 0;
+ 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();
diff --git a/firmware/octoclock/octoclock_r4/CMakeLists.txt b/firmware/octoclock/octoclock_r4/CMakeLists.txt
index a030d3249..c3559d8d4 100644
--- a/firmware/octoclock/octoclock_r4/CMakeLists.txt
+++ b/firmware/octoclock/octoclock_r4/CMakeLists.txt
@@ -17,6 +17,9 @@
add_executable(octoclock_r4_fw.elf octoclock_r4_main.c)
target_link_libraries(octoclock_r4_fw.elf octoclock)
+set_target_properties(octoclock_r4_fw.elf PROPERTIES
+ LINK_FLAGS "-Wl,--relax,-Map=octoclock_r4_fw.map,--cref"
+)
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/octoclock_r4_fw.bin
diff --git a/firmware/octoclock/octoclock_r4/octoclock_r4_main.c b/firmware/octoclock/octoclock_r4/octoclock_r4_main.c
index f80c7d188..5e8e6d09b 100644
--- a/firmware/octoclock/octoclock_r4/octoclock_r4_main.c
+++ b/firmware/octoclock/octoclock_r4/octoclock_r4_main.c
@@ -72,23 +72,21 @@
int main(void){
- #ifdef DEBUG
asm("cli");
- #else
- asm("sei");
- #endif
-
- bool old_global_ext_ref_is_present = false;
- switch_pos_t old_switch_pos, current_switch_pos;
setup_atmel_io_ports();
-
network_init();
+
+ #ifndef DEBUG
+ asm("sei");
+ #endif
+
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
usart_init();
//Set initial ClkDist and front panel settings
@@ -98,61 +96,10 @@ int main(void){
led(Top,true);
PORTA |= (1<<PA6); // PPS from Internal source
- /*
- * DO THIS FOREVER:
- *
- * get_switch_state
- *
- * if SWITCH_CHANGED:
- *
- * if PREFER_INTERNAL:
- * if INTERNAL_PRESENT do_internal
- * else if EXTERNAL_PRESENT do_external
- * else LEDs OFF
- *
- * if PREFER_EXTERNAL:
- * if EXTERNAL_PRESENT do_external
- * else if INTERNAL_PRESENT do_internal
- * else LEDs OFF
- *
- * check Ethernet port for incoming packets
- *
- * if packets seen:
- * pass to appropriate handler
- *
- * check if told to monitor GPSDO output
- *
- * if send flag is set:
- * check if interrupt routine has filled buffer with full sentence
- * if so, send to host (last machine to use this port)
- */
-
- check_what_is_present();
- old_global_ext_ref_is_present = !global_ext_ref_is_present;
- old_switch_pos = (get_switch_pos() == UP) ? DOWN : UP;
+ TIMER0_INIT();
+ TIMER1_INIT();
- // Because down below, we use this to get state swap So we arbitrarily set
- // the PREVIOUS state to be the "other" state so that, below, we trigger
- // what happens when the switch changes This first "change" is therefore
- // artificial to keep the logic, below, cleaner
while(true) {
- // Set "global_ext_ref_is_present" and "global_gps_present"
- check_what_is_present();
-
- current_switch_pos = get_switch_pos();
-
- if( (current_switch_pos != old_switch_pos) ||
- (global_ext_ref_is_present != old_global_ext_ref_is_present) ) {
-
- old_switch_pos = current_switch_pos;
- old_global_ext_ref_is_present = global_ext_ref_is_present;
-
- if(current_switch_pos == UP) prefer_internal();
- else prefer_external();
- }
-
- //With OctoClock state verified, pass raw packet to handlers for processing
- size_t recv_len = enc28j60PacketReceive(512, buf_in);
- if(recv_len > 0) handle_eth_packet(recv_len);
+ network_check();
}
}
diff --git a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp
index add5d7931..8c207dd9f 100644
--- a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp
+++ b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp
@@ -75,7 +75,7 @@ device_addrs_t octoclock_find(const device_addr_t &hint){
device_addr_t _hint = hints[0];
device_addrs_t octoclock_addrs;
- //return an empty list of addresses when type is set to non-usrp2
+ //return an empty list of addresses when type is set to non-OctoClock
if (hint.has_key("type") and hint["type"].find("octoclock") == std::string::npos) return octoclock_addrs;
//Return an empty list of addresses when a resource is specified,
@@ -127,11 +127,9 @@ device_addrs_t octoclock_find(const device_addr_t &hint){
const octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t*>(octoclock_data);
while(true){
- size_t len = udp_transport->recv(asio::buffer(octoclock_data), 2);
+ size_t len = udp_transport->recv(asio::buffer(octoclock_data));
if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len)){
device_addr_t new_addr;
- new_addr["type"] = (pkt_in->proto_ver == OCTOCLOCK_FW_COMPAT_NUM) ? "octoclock"
- : "octoclock-bootloader";
new_addr["addr"] = udp_transport->get_recv_addr();
//Attempt direct communication with OctoClock
@@ -143,9 +141,12 @@ device_addrs_t octoclock_find(const device_addr_t &hint){
if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len)){
//If the OctoClock is in its bootloader, don't ask for details
if(pkt_in->proto_ver == OCTOCLOCK_BOOTLOADER_PROTO_VER){
+ new_addr["type"] = "octoclock-bootloader";
octoclock_addrs.push_back(new_addr);
}
else{
+ new_addr["type"] = "octoclock";
+
octoclock_eeprom_t oc_eeprom(ctrl_xport);
new_addr["name"] = oc_eeprom["name"];
new_addr["serial"] = oc_eeprom["serial"];
diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp
index bc91f22f9..9551ddd20 100644
--- a/host/utils/octoclock_firmware_burner.cpp
+++ b/host/utils/octoclock_firmware_burner.cpp
@@ -93,7 +93,7 @@ void list_octoclocks(){
* Manually find bootloader. This sends multiple packets in order to increase chances of getting
* bootloader before it switches to the application.
*/
-device_addrs_t bootloader_find(std::string ip_addr){
+device_addrs_t bootloader_find(const std::string &ip_addr){
udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT));
octoclock_packet_t pkt_out;
@@ -156,7 +156,9 @@ void burn_firmware(udp_simple::sptr udp_transport){
pkt_out.code = FILE_TRANSFER_CMD;
//Actual burning below
+ size_t num_tries = 0;
for(size_t i = 0; i < num_blocks; i++){
+ num_tries = 0;
pkt_out.sequence++;
pkt_out.addr = i*BLOCK_SIZE;
std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100)
@@ -164,8 +166,20 @@ void burn_firmware(udp_simple::sptr udp_transport){
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));
- UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FILE_TRANSFER_CMD, pkt_out, len, octoclock_data);
- if(not (UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len))){
+
+ bool success = false;
+ while(num_tries <= 5){
+ UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FILE_TRANSFER_CMD, pkt_out, len, octoclock_data);
+ if(UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len)){
+ success = true;
+ break;
+ }
+ else{
+ num_tries++;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+ }
+ if(not success){
std::cout << std::endl;
throw uhd::runtime_error("Failed to burn firmware to OctoClock!");
}
@@ -182,7 +196,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;
- std::cout << "Verifying firmware." << std::endl;
for(size_t i = 0; i < num_blocks; i++){
pkt_out.sequence++;
@@ -207,7 +220,7 @@ void verify_firmware(udp_simple::sptr udp_transport){
std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl;
}
-void reset_octoclock(const std::string &ip_addr){
+bool reset_octoclock(const std::string &ip_addr){
udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT));
octoclock_packet_t pkt_out;
@@ -215,8 +228,13 @@ void reset_octoclock(const std::string &ip_addr){
size_t len;
UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, RESET_CMD, pkt_out, len, octoclock_data);
- if(UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)) std::cout << "done." << std::endl;
- else throw uhd::runtime_error("Failed to place device in state to receive firmware.");
+ if(not UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){
+ std::cout << std::endl;
+ throw uhd::runtime_error("Failed to place device in state to receive firmware.");
+ }
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
+ return (bootloader_find(ip_addr).size() == 1);
}
void finalize(udp_simple::sptr udp_transport){
@@ -225,10 +243,11 @@ void finalize(udp_simple::sptr udp_transport){
pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand());
size_t len = 0;
- std::cout << std::endl << "Telling OctoClock to load application..." << std::flush;
UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data);
- if(UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)) std::cout << "done." << std::endl;
- else std::cout << "no ACK. Device may not have loaded application." << std::endl;
+ if(not UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){
+ std::cout << std::endl;
+ std::cout << "no ACK. Bootloader may not have loaded application." << std::endl;
+ }
}
int UHD_SAFE_MAIN(int argc, char *argv[]){
@@ -303,21 +322,18 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << std::endl << boost::format("Searching for OctoClock with IP address %s...") % ip_addr << std::flush;
device_addrs_t octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK);
if(octoclocks.size() == 1){
- //If in application, quietly reset into bootloader and try to find again
if(octoclocks[0]["type"] == "octoclock"){
- reset_octoclock(ip_addr);
- boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
- octoclocks = bootloader_find(ip_addr);
- if(octoclocks.size() == 1) std::cout << "found." << std::endl;
+ std::cout << "found. Resetting..." << std::flush;
+ if(reset_octoclock(ip_addr)) std::cout << "successful." << std::endl;
else{
- std::cout << std::endl;
- throw uhd::runtime_error("Could not find OctoClock with given IP address!");
+ std::cout << "failed." << std::endl;
+ throw uhd::runtime_error("Failed to reset OctoClock device into its bootloader.");
}
}
else std::cout << "found." << std::endl;
}
else{
- std::cout << std::endl;
+ std::cout << "failed." << std::endl;
throw uhd::runtime_error("Could not find OctoClock with given IP address!");
}
@@ -326,11 +342,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::signal(SIGINT, &sig_int_handler);
burn_firmware(udp_transport);
+ std::cout << "Verifying firmware." << std::endl;
verify_firmware(udp_transport);
+ std::cout << std::endl << "Telling OctoClock bootloader to load application..." << std::flush;
finalize(udp_transport);
+ std::cout << "done." << std::endl;
std::cout << "Waiting for OctoClock to reinitialize..." << std::flush;
- boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
+ boost::this_thread::sleep(boost::posix_time::milliseconds(5000));
octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK);
if(octoclocks.size() == 1){
if(octoclocks[0]["type"] == "octoclock-bootloader"){