diff options
| -rw-r--r-- | firmware/octoclock/bootloader/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | firmware/octoclock/bootloader/main.c | 40 | ||||
| -rw-r--r-- | firmware/octoclock/include/debug.h | 23 | ||||
| -rw-r--r-- | firmware/octoclock/include/net/eth_mac_addr.h | 2 | ||||
| -rw-r--r-- | firmware/octoclock/include/network.h | 20 | ||||
| -rw-r--r-- | firmware/octoclock/include/octoclock.h | 21 | ||||
| -rw-r--r-- | firmware/octoclock/include/state.h | 8 | ||||
| -rw-r--r-- | firmware/octoclock/lib/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | firmware/octoclock/lib/enc28j60.c | 19 | ||||
| -rw-r--r-- | firmware/octoclock/lib/network.c | 87 | ||||
| -rw-r--r-- | firmware/octoclock/lib/state.c | 32 | ||||
| -rw-r--r-- | firmware/octoclock/lib/udp_handlers.c | 28 | ||||
| -rw-r--r-- | firmware/octoclock/octoclock_r4/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | firmware/octoclock/octoclock_r4/octoclock_r4_main.c | 71 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_impl.cpp | 9 | ||||
| -rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 57 | 
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"){ | 
