1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
/*
* Copyright 2013-2014 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/>.
*/
/*
* Welcome to the firmware code for the USRP Octoclock accessory product!
*
* Notes regarding this firmware:
* NOT in M103 compatibility mode
* CKOPT full rail-to-rail
* xtal osc
* 16K CK (16K clock cycles)
* additional delay 65ms for Crystal Oscillator
* slowly rising power
* persistent EEPROM
*
* These settings are very conservative. If a lower power oscillator is
* required, change CKOPT to '1' (UNPROGRAMMED).
*
* M103C = [ ]
* WDTON = [ ]
* OCDEN = [ ]
* JTAGEN = [X]
* SPIEN = [X]
* EESAVE = [X]
* BOOTSZ = 4096W_F000
* BOOTRST = [ ]
* CKOPT = [X]
* BODLEVEL = 2V7
* BODEN = [ ]
* SUT_CKSEL = EXTHIFXTALRES_16KCK_64MS
*
* EXTENDED = 0xFF (valid)
* HIGH = 0x81 (valid)
* LOW = 0xFF (valid)
*
*/
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/eeprom.h>
#include <avr/io.h>
#include <octoclock.h>
#include <clkdist.h>
#include <debug.h>
#include <state.h>
#include <network.h>
#include <usart.h>
#include <gpsdo.h>
#include <net/enc28j60.h>
#include <net/udp_handlers.h>
/*******************************************************************************
* Main Routine
*******************************************************************************/
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();
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
usart_init();
//Set initial ClkDist and front panel settings
led(Middle,true);
setup_TI_CDCE18005(Primary_GPS); // 10 MHz from Internal Source
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;
// 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);
}
}
|