1 /*
2  * Copyright 2010-2012 Ettus Research LLC
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 //peripheral headers
19 #include "u2_init.h"
20 #include "spi.h"
21 #include "i2c.h"
22 #include "hal_io.h"
23 #include "pic.h"
24 
25 //printf headers
26 #include "nonstdio.h"
27 
28 //network headers
29 #include "arp_cache.h"
30 #include "ethernet.h"
31 #include "net_common.h"
32 #include "usrp2/fw_common.h"
33 #include "udp_fw_update.h"
34 #include "pkt_ctrl.h"
35 #include "udp_uart.h"
36 
37 //standard headers
38 #include <stddef.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdbool.h>
42 
43 #ifdef BOOTLOADER
44 #include <bootloader_utils.h>
45 #endif
46 
47 //virtual registers in the firmware to store persistent values
48 static uint32_t fw_regs[8];
49 
handle_udp_data_packet(struct socket_address src,struct socket_address dst,unsigned char * payload,int payload_len)50 static void handle_udp_data_packet(
51     struct socket_address src, struct socket_address dst,
52     unsigned char *payload, int payload_len
53 ){
54     //handle ICMP destination unreachable
55     if (payload == NULL) switch(src.port){
56     case USRP2_UDP_RX_DSP0_PORT:
57         //reset dsp to stop streaming
58         sr_rx_ctrl0->clear = 1;
59         fw_regs[U2_FW_REG_LOCK_TIME] = 0; //force an unlock
60         return;
61 
62     case USRP2_UDP_RX_DSP1_PORT:
63         //reset dsp to stop streaming
64         sr_rx_ctrl1->clear = 1;
65         fw_regs[U2_FW_REG_LOCK_TIME] = 0; //force an unlock
66         return;
67 
68     case USRP2_UDP_TX_DSP0_PORT:
69         //end async update packets per second
70         sr_tx_ctrl->cyc_per_up = 0;
71         fw_regs[U2_FW_REG_LOCK_TIME] = 0; //force an unlock
72         return;
73 
74     default: return;
75     }
76 
77     //handle an incoming UDP packet
78     size_t which = 0;
79     if (payload != 0) switch(dst.port){
80     case USRP2_UDP_RX_DSP0_PORT:
81         which = 0;
82         break;
83 
84     case USRP2_UDP_RX_DSP1_PORT:
85         which = 2;
86         break;
87 
88     case USRP2_UDP_TX_DSP0_PORT:
89         which = 1;
90         break;
91 
92     case USRP2_UDP_FIFO_CRTL_PORT:
93         which = 3;
94         break;
95 
96     default: return;
97     }
98 
99     //assume the packet destination is the packet source
100     //the arp cache lookup should never fail for this case
101     const struct socket_address src_addr = dst;
102     struct socket_address dst_addr = src;
103     eth_mac_addr_t eth_mac_dst;
104     arp_cache_lookup_mac(&dst_addr.addr, &eth_mac_dst);
105 
106     //however, if this control packet has an alternative destination...
107     if (payload_len >= sizeof(usrp2_stream_ctrl_t)){
108 
109         //parse the destination ip addr and udp port from the payload
110         const usrp2_stream_ctrl_t *stream_ctrl = (const usrp2_stream_ctrl_t *)payload;
111         dst_addr.addr.addr = stream_ctrl->ip_addr;
112         dst_addr.port = (uint16_t)stream_ctrl->udp_port;
113         struct ip_addr ip_dest = dst_addr.addr;
114 
115         //are we in the subnet? if not use the gateway
116         const uint32_t subnet_mask = get_subnet()->addr;
117         const bool in_subnet = ((get_ip_addr()->addr & subnet_mask) == (ip_dest.addr & subnet_mask));
118         if (!in_subnet) ip_dest = *get_gateway();
119 
120         //lookup the host ip address with ARP (this may fail)
121         const bool ok = arp_cache_lookup_mac(&ip_dest, &eth_mac_dst);
122         if (!ok) net_common_send_arp_request(&ip_dest);
123         const uint32_t result = (ok)? 0 : ~0;
124         send_udp_pkt(dst.port, src, &result, sizeof(result));
125     }
126 
127     setup_framer(eth_mac_dst, *ethernet_mac_addr(), dst_addr, src_addr, which);
128 }
129 
130 #define OTW_GPIO_BANK_TO_NUM(bank) \
131     (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK))
132 
handle_udp_ctrl_packet(struct socket_address src,struct socket_address dst,unsigned char * payload,int payload_len)133 static void handle_udp_ctrl_packet(
134     struct socket_address src, struct socket_address dst,
135     unsigned char *payload, int payload_len
136 ){
137     //printf("Got ctrl packet #words: %d\n", (int)payload_len);
138     const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload;
139     uint32_t ctrl_data_in_id = ctrl_data_in->id;
140 
141     //ensure that the protocol versions match
142     if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){
143         if (ctrl_data_in->proto_ver) printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n",
144             USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver
145         );
146         ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO;
147     }
148 
149     //ensure that this is not a short packet
150     if (payload_len < sizeof(usrp2_ctrl_data_t)){
151         printf("!Error in control packet handler: Expected payload length %d, but got %d\n",
152             (int)sizeof(usrp2_ctrl_data_t), payload_len
153         );
154         ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT;
155     }
156 
157     //setup the output data
158     usrp2_ctrl_data_t ctrl_data_out;
159     ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM;
160     ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT;
161     ctrl_data_out.seq=ctrl_data_in->seq;
162 
163     //handle the data based on the id
164     switch(ctrl_data_in_id){
165 
166     /*******************************************************************
167      * Addressing
168      ******************************************************************/
169     case USRP2_CTRL_ID_WAZZUP_BRO:
170         ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE;
171         memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr));
172         break;
173 
174     /*******************************************************************
175      * SPI
176      ******************************************************************/
177     case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{
178             //transact
179             uint32_t result = spi_transact(
180                 (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX,
181                 ctrl_data_in->data.spi_args.dev,      //which device
182                 ctrl_data_in->data.spi_args.data,     //32 bit data
183                 ctrl_data_in->data.spi_args.num_bits, //length in bits
184                 ((ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPI_PUSH_FALL : SPI_PUSH_RISE) |
185                 ((ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPI_LATCH_RISE : SPI_LATCH_FALL)
186             );
187 
188             //load output
189             ctrl_data_out.data.spi_args.data = result;
190             ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE;
191         }
192         break;
193 
194     /*******************************************************************
195      * I2C
196      ******************************************************************/
197     case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{
198             uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes;
199             i2c_read(
200                 ctrl_data_in->data.i2c_args.addr,
201                 ctrl_data_out.data.i2c_args.data,
202                 num_bytes
203             );
204             ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE;
205             ctrl_data_out.data.i2c_args.bytes = num_bytes;
206         }
207         break;
208 
209     case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{
210             uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes;
211             i2c_write(
212                 ctrl_data_in->data.i2c_args.addr,
213                 ctrl_data_in->data.i2c_args.data,
214                 num_bytes
215             );
216             ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE;
217             ctrl_data_out.data.i2c_args.bytes = num_bytes;
218         }
219         break;
220 
221     /*******************************************************************
222      * Peek and Poke Register
223      ******************************************************************/
224     case USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO:
225         switch(ctrl_data_in->data.reg_args.action){
226             case USRP2_REG_ACTION_FPGA_PEEK32:
227                 ctrl_data_out.data.reg_args.data = *((uint32_t *) ctrl_data_in->data.reg_args.addr);
228                 break;
229 
230             case USRP2_REG_ACTION_FPGA_PEEK16:
231                 ctrl_data_out.data.reg_args.data = *((uint16_t *) ctrl_data_in->data.reg_args.addr);
232                 break;
233 
234             case USRP2_REG_ACTION_FPGA_POKE32:
235                 *((uint32_t *) ctrl_data_in->data.reg_args.addr) = (uint32_t)ctrl_data_in->data.reg_args.data;
236                 break;
237 
238             case USRP2_REG_ACTION_FPGA_POKE16:
239                 *((uint16_t *) ctrl_data_in->data.reg_args.addr) = (uint16_t)ctrl_data_in->data.reg_args.data;
240                 break;
241 
242             case USRP2_REG_ACTION_FW_PEEK32:
243                 ctrl_data_out.data.reg_args.data = fw_regs[(ctrl_data_in->data.reg_args.addr)];
244                 break;
245 
246             case USRP2_REG_ACTION_FW_POKE32:
247                 fw_regs[(ctrl_data_in->data.reg_args.addr)] = ctrl_data_in->data.reg_args.data;
248                 break;
249 
250         }
251         ctrl_data_out.id = USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE;
252         break;
253 
254     /*******************************************************************
255      * Echo test
256      ******************************************************************/
257     case USRP2_CTRL_ID_HOLLER_AT_ME_BRO:
258         ctrl_data_out.data.echo_args.len = payload_len;
259         ctrl_data_out.id = USRP2_CTRL_ID_HOLLER_BACK_DUDE;
260         send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, ctrl_data_in->data.echo_args.len);
261         return;
262 
263     default:
264         ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT;
265     }
266     send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out));
267 }
268 
269 #include <net/padded_eth_hdr.h>
handle_inp_packet(uint32_t * buff,size_t num_lines)270 static void handle_inp_packet(uint32_t *buff, size_t num_lines){
271 
272   //test if its an ip recovery packet
273   typedef struct{
274       padded_eth_hdr_t eth_hdr;
275       char code[4];
276       union {
277         struct ip_addr ip_addr;
278       } data;
279   }recovery_packet_t;
280   recovery_packet_t *recovery_packet = (recovery_packet_t *)buff;
281   if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){
282       printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline();
283       set_ip_addr(&recovery_packet->data.ip_addr);
284       return;
285   }
286 
287   //pass it to the slow-path handler
288   handle_eth_packet(buff, num_lines);
289 }
290 
291 //------------------------------------------------------------------
292 
293 /*
294  * Called when eth phy state changes (w/ interrupts disabled)
295  */
link_changed_callback(int speed)296 void link_changed_callback(int speed){
297     printf("\neth link changed: speed = %d\n", speed);
298     if (speed != 0){
299         hal_set_leds(LED_RJ45, LED_RJ45);
300         pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_MASTER);
301         send_gratuitous_arp();
302     }
303     else{
304         hal_set_leds(0x0, LED_RJ45);
305         pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
306     }
307 }
308 
309 int
main(void)310 main(void)
311 {
312   u2_init();
313   arp_cache_init();
314 #ifdef BOOTLOADER
315   putstr("\nUSRP N210 UDP bootloader\n");
316 #else
317   putstr("\nTxRx-UHD-ZPU\n");
318 #endif
319   printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM);
320   printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM);
321 
322   //init readback for firmware minor version number
323   fw_regs[U2_FW_REG_VER_MINOR] = USRP2_FW_VER_MINOR;
324 
325 #ifdef BOOTLOADER
326   //load the production FPGA image or firmware if appropriate
327   do_the_bootload_thing();
328   //if we get here we've fallen through to safe firmware
329   eth_addrs_set_default();
330 #endif
331 
332   print_mac_addr(ethernet_mac_addr()); newline();
333   print_ip_addr(get_ip_addr()); newline();
334 
335   //1) register the addresses into the network stack
336   register_addrs(ethernet_mac_addr(), get_ip_addr());
337   pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_TX_DSP0_PORT);
338 
339   //2) register callbacks for udp ports we service
340   init_udp_listeners();
341   register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet);
342   register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet);
343   register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet);
344   register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet);
345   register_udp_listener(USRP2_UDP_FIFO_CRTL_PORT, handle_udp_data_packet);
346 
347 #ifdef USRP2P
348   register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet);
349 #endif
350 
351   udp_uart_init(USRP2_UDP_UART_BASE_PORT); //setup uart messaging
352 
353   //3) set the routing mode to slave to set defaults
354   pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
355 
356   //4) setup ethernet hardware to bring the link up
357   ethernet_register_link_changed_callback(link_changed_callback);
358   ethernet_init();
359 
360   while(true){
361 
362     size_t num_lines;
363     void *buff = pkt_ctrl_claim_incoming_buffer(&num_lines);
364     if (buff != NULL){
365         handle_inp_packet((uint32_t *)buff, num_lines);
366         pkt_ctrl_release_incoming_buffer();
367     }
368 
369     udp_uart_poll(); //uart message handling
370 
371     pic_interrupt_handler();
372     /*
373     int pending = pic_regs->pending;		// poll for under or overrun
374 
375     if (pending & PIC_UNDERRUN_INT){
376       pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt
377       putchar('U');
378     }
379 
380     if (pending & PIC_OVERRUN_INT){
381       pic_regs->pending = PIC_OVERRUN_INT;	// clear interrupt
382       putchar('O');
383     }
384     */
385   }
386 }
387