Statistics
| Branch: | Tag: | Revision:

root / firmware / zpu / apps / txrx_uhd.c @ 25494489

History | View | Annotate | Download (11.7 KB)

1
/*
2
 * Copyright 2010-2011 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

    
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
        //the end continuous streaming command
58
        sr_rx_ctrl0->cmd = 1 << 31 | 1 << 28; //no samples now
59
        sr_rx_ctrl0->time_secs = 0;
60
        sr_rx_ctrl0->time_ticks = 0; //latch the command
61
        break;
62

    
63
    case USRP2_UDP_RX_DSP1_PORT:
64
        //the end continuous streaming command
65
        sr_rx_ctrl1->cmd = 1 << 31 | 1 << 28; //no samples now
66
        sr_rx_ctrl1->time_secs = 0;
67
        sr_rx_ctrl1->time_ticks = 0; //latch the command
68
        break;
69

    
70
    case USRP2_UDP_TX_DSP0_PORT:
71
        //end async update packets per second
72
        sr_tx_ctrl->cyc_per_up = 0;
73
        break;
74

    
75
    default: return;
76
    }
77

    
78
    //handle an incoming UDP packet
79
    size_t which = 0;
80
    if (payload != 0) switch(dst.port){
81
    case USRP2_UDP_RX_DSP0_PORT:
82
        which = 0;
83
        break;
84

    
85
    case USRP2_UDP_RX_DSP1_PORT:
86
        which = 2;
87
        break;
88

    
89
    case USRP2_UDP_TX_DSP0_PORT:
90
        which = 1;
91
        break;
92

    
93
    default: return;
94
    }
95

    
96
    eth_mac_addr_t eth_mac_host; arp_cache_lookup_mac(&src.addr, &eth_mac_host);
97
    setup_framer(eth_mac_host, *ethernet_mac_addr(), src, dst, which);
98
}
99

    
100
#define OTW_GPIO_BANK_TO_NUM(bank) \
101
    (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK))
102

    
103
static void handle_udp_ctrl_packet(
104
    struct socket_address src, struct socket_address dst,
105
    unsigned char *payload, int payload_len
106
){
107
    //printf("Got ctrl packet #words: %d\n", (int)payload_len);
108
    const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload;
109
    uint32_t ctrl_data_in_id = ctrl_data_in->id;
110

    
111
    //ensure that the protocol versions match
112
    if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){
113
        if (ctrl_data_in->proto_ver) printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n",
114
            USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver
115
        );
116
        ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO;
117
    }
118

    
119
    //ensure that this is not a short packet
120
    if (payload_len < sizeof(usrp2_ctrl_data_t)){
121
        printf("!Error in control packet handler: Expected payload length %d, but got %d\n",
122
            (int)sizeof(usrp2_ctrl_data_t), payload_len
123
        );
124
        ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT;
125
    }
126

    
127
    //setup the output data
128
    usrp2_ctrl_data_t ctrl_data_out;
129
    ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM;
130
    ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT;
131
    ctrl_data_out.seq=ctrl_data_in->seq;
132

    
133
    //handle the data based on the id
134
    switch(ctrl_data_in_id){
135

    
136
    /*******************************************************************
137
     * Addressing
138
     ******************************************************************/
139
    case USRP2_CTRL_ID_WAZZUP_BRO:
140
        ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE;
141
        memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr));
142
        break;
143

    
144
    /*******************************************************************
145
     * SPI
146
     ******************************************************************/
147
    case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{
148
            //transact
149
            uint32_t result = spi_transact(
150
                (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX,
151
                ctrl_data_in->data.spi_args.dev,      //which device
152
                ctrl_data_in->data.spi_args.data,     //32 bit data
153
                ctrl_data_in->data.spi_args.num_bits, //length in bits
154
                (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE |
155
                (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL
156
            );
157

    
158
            //load output
159
            ctrl_data_out.data.spi_args.data = result;
160
            ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE;
161
        }
162
        break;
163

    
164
    /*******************************************************************
165
     * I2C
166
     ******************************************************************/
167
    case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{
168
            uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes;
169
            i2c_read(
170
                ctrl_data_in->data.i2c_args.addr,
171
                ctrl_data_out.data.i2c_args.data,
172
                num_bytes
173
            );
174
            ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE;
175
            ctrl_data_out.data.i2c_args.bytes = num_bytes;
176
        }
177
        break;
178

    
179
    case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{
180
            uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes;
181
            i2c_write(
182
                ctrl_data_in->data.i2c_args.addr,
183
                ctrl_data_in->data.i2c_args.data,
184
                num_bytes
185
            );
186
            ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE;
187
            ctrl_data_out.data.i2c_args.bytes = num_bytes;
188
        }
189
        break;
190

    
191
    /*******************************************************************
192
     * Peek and Poke Register
193
     ******************************************************************/
194
    case USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO:
195
        switch(ctrl_data_in->data.reg_args.action){
196
            case USRP2_REG_ACTION_FPGA_PEEK32:
197
                ctrl_data_out.data.reg_args.data = *((uint32_t *) ctrl_data_in->data.reg_args.addr);
198
                break;
199

    
200
            case USRP2_REG_ACTION_FPGA_PEEK16:
201
                ctrl_data_out.data.reg_args.data = *((uint16_t *) ctrl_data_in->data.reg_args.addr);
202
                break;
203

    
204
            case USRP2_REG_ACTION_FPGA_POKE32:
205
                *((uint32_t *) ctrl_data_in->data.reg_args.addr) = (uint32_t)ctrl_data_in->data.reg_args.data;
206
                break;
207

    
208
            case USRP2_REG_ACTION_FPGA_POKE16:
209
                *((uint16_t *) ctrl_data_in->data.reg_args.addr) = (uint16_t)ctrl_data_in->data.reg_args.data;
210
                break;
211

    
212
            case USRP2_REG_ACTION_FW_PEEK32:
213
                ctrl_data_out.data.reg_args.data = fw_regs[(ctrl_data_in->data.reg_args.addr)];
214
                break;
215

    
216
            case USRP2_REG_ACTION_FW_POKE32:
217
                fw_regs[(ctrl_data_in->data.reg_args.addr)] = ctrl_data_in->data.reg_args.data;
218
                break;
219

    
220
        }
221
        ctrl_data_out.id = USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE;
222
        break;
223

    
224
    /*******************************************************************
225
     * Echo test
226
     ******************************************************************/
227
    case USRP2_CTRL_ID_HOLLER_AT_ME_BRO:
228
        ctrl_data_out.data.echo_args.len = payload_len;
229
        ctrl_data_out.id = USRP2_CTRL_ID_HOLLER_BACK_DUDE;
230
        send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, ctrl_data_in->data.echo_args.len);
231
        return;
232

    
233
    default:
234
        ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT;
235
    }
236
    send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out));
237
}
238

    
239
#include <net/padded_eth_hdr.h>
240
static void handle_inp_packet(uint32_t *buff, size_t num_lines){
241

    
242
  //test if its an ip recovery packet
243
  typedef struct{
244
      padded_eth_hdr_t eth_hdr;
245
      char code[4];
246
      union {
247
        struct ip_addr ip_addr;
248
      } data;
249
  }recovery_packet_t;
250
  recovery_packet_t *recovery_packet = (recovery_packet_t *)buff;
251
  if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){
252
      printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline();
253
      set_ip_addr(&recovery_packet->data.ip_addr);
254
      return;
255
  }
256

    
257
  //pass it to the slow-path handler
258
  handle_eth_packet(buff, num_lines);
259
}
260

    
261
//------------------------------------------------------------------
262

    
263
/*
264
 * Called when eth phy state changes (w/ interrupts disabled)
265
 */
266
void link_changed_callback(int speed){
267
    printf("\neth link changed: speed = %d\n", speed);
268
    if (speed != 0){
269
        hal_set_leds(LED_RJ45, LED_RJ45);
270
        pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_MASTER);
271
        send_gratuitous_arp();
272
    }
273
    else{
274
        hal_set_leds(0x0, LED_RJ45);
275
        pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
276
    }
277
}
278

    
279
int
280
main(void)
281
{
282
  u2_init();
283
#ifdef BOOTLOADER
284
  putstr("\nUSRP N210 UDP bootloader\n");
285
#else
286
  putstr("\nTxRx-UHD-ZPU\n");
287
#endif
288
  printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM);
289
  printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM);
290

    
291
  //init readback for firmware minor version number
292
  fw_regs[U2_FW_REG_VER_MINOR] = USRP2_FW_VER_MINOR;
293

    
294
#ifdef BOOTLOADER
295
  //load the production FPGA image or firmware if appropriate
296
  do_the_bootload_thing();
297
  //if we get here we've fallen through to safe firmware
298
  set_default_mac_addr();
299
  set_default_ip_addr();
300
#endif
301

    
302
  print_mac_addr(ethernet_mac_addr()); newline();
303
  print_ip_addr(get_ip_addr()); newline();
304

    
305
  //1) register the addresses into the network stack
306
  register_addrs(ethernet_mac_addr(), get_ip_addr());
307
  pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_TX_DSP0_PORT);
308

    
309
  //2) register callbacks for udp ports we service
310
  init_udp_listeners();
311
  register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet);
312
  register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet);
313
  register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet);
314
  register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet);
315
  
316
#ifdef USRP2P
317
  register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet);
318
#endif
319

    
320
  udp_uart_init(USRP2_UDP_UART_BASE_PORT); //setup uart messaging
321

    
322
  //3) set the routing mode to slave to set defaults
323
  pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
324

    
325
  //4) setup ethernet hardware to bring the link up
326
  ethernet_register_link_changed_callback(link_changed_callback);
327
  ethernet_init();
328

    
329
  while(true){
330

    
331
    size_t num_lines;
332
    void *buff = pkt_ctrl_claim_incoming_buffer(&num_lines);
333
    if (buff != NULL){
334
        handle_inp_packet((uint32_t *)buff, num_lines);
335
        pkt_ctrl_release_incoming_buffer();
336
    }
337

    
338
    udp_uart_poll(); //uart message handling
339

    
340
    pic_interrupt_handler();
341
    /*
342
    int pending = pic_regs->pending;                // poll for under or overrun
343

344
    if (pending & PIC_UNDERRUN_INT){
345
      pic_regs->pending = PIC_UNDERRUN_INT;        // clear interrupt
346
      putchar('U');
347
    }
348

349
    if (pending & PIC_OVERRUN_INT){
350
      pic_regs->pending = PIC_OVERRUN_INT;        // clear interrupt
351
      putchar('O');
352
    }
353
    */
354
  }
355
}