Imported Upstream version 3.2.2
[debian/gnuradio] / usrp2 / firmware / apps / tx_standalone.c
1 /*
2  * Copyright 2007 Free Software Foundation, Inc.
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 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "u2_init.h"
23 #include "memory_map.h"
24 #include "spi.h"
25 #include "hal_io.h"
26 #include "buffer_pool.h"
27 #include "pic.h"
28 #include "bool.h"
29 #include "ethernet.h"
30 #include "nonstdio.h"
31 #include "usrp2_eth_packet.h"
32 #include "memcpy_wa.h"
33 #include "dbsm.h"
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #define _AL4 __attribute__((aligned (4)))
39
40 #define USE_BUFFER_INTERRUPT    0       // 0 or 1
41
42
43 static int timer_delta = MASTER_CLK_RATE/1000;  // tick at 1kHz
44
45 /*
46  * This program can respond to queries from the host
47  * and stream rx samples.
48  *
49  * Buffer 1 is used by the cpu to send frames to the host.
50  * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow
51  * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow
52  */
53 //#define CPU_RX_BUF    0       // eth -> cpu
54 #define CPU_TX_BUF      1       // cpu -> eth
55
56 #define DSP_RX_BUF_0    2       // dsp rx -> eth (double buffer)
57 #define DSP_RX_BUF_1    3       // dsp rx -> eth
58 #define DSP_TX_BUF_0    4       // eth -> dsp tx (double buffer)
59 #define DSP_TX_BUF_1    5       // eth -> dsp tx
60
61
62 /*
63  * ================================================================
64  *      configure DSP RX double buffering state machine
65  * ================================================================
66  */
67
68
69 // 4 lines of ethernet hdr + 1 line (word0)
70 // DSP Rx writes timestamp followed by nlines_per_frame of samples
71 #define DSP_RX_FIRST_LINE                 5
72 #define DSP_RX_SAMPLES_PER_FRAME        128
73 #define DSP_RX_EXTRA_LINES                1     // writes timestamp
74
75 // Receive from DSP Rx
76 buf_cmd_args_t dsp_rx_recv_args = {
77   PORT_DSP,
78   DSP_RX_FIRST_LINE,
79   BP_LAST_LINE
80 };
81
82 // send to ethernet
83 buf_cmd_args_t dsp_rx_send_args = {
84   PORT_ETH,
85   0,            // starts with ethernet header in line 0
86   0,            // filled in from last_line register
87 };
88
89 dbsm_t dsp_rx_sm;       // the state machine
90
91 /*
92  * ================================================================
93  *      configure DSP TX double buffering state machine
94  * ================================================================
95  */
96
97 // 4 lines of ethernet hdr + 2 lines (word0 + timestamp)
98 // DSP Tx reads word0 (flags) + timestamp followed by samples
99
100 #define DSP_TX_FIRST_LINE                 4
101 #define DSP_TX_SAMPLES_PER_FRAME        250     // not used except w/ debugging
102 #define DSP_TX_EXTRA_LINES                2     // reads word0 + timestamp
103
104 // Receive from ethernet
105 buf_cmd_args_t dsp_tx_recv_args = {
106   PORT_ETH,
107   0,
108   BP_LAST_LINE
109 };
110
111 // send to DSP Tx
112 buf_cmd_args_t dsp_tx_send_args = {
113   PORT_DSP,
114   DSP_TX_FIRST_LINE,    // starts just past ethernet header
115   0                     // filled in from last_line register
116 };
117
118 dbsm_t dsp_tx_sm;       // the state machine
119
120 /*
121  * send constant buffer to DSP TX
122  */
123 static inline void 
124 SEND_CONST_TO_DSP_TX(void)
125 {
126   bp_send_from_buf(DSP_TX_BUF_0, PORT_DSP, 1,
127                    DSP_TX_FIRST_LINE,
128                    DSP_TX_FIRST_LINE + DSP_TX_EXTRA_LINES + DSP_TX_SAMPLES_PER_FRAME - 1);
129 }
130
131 // ----------------------------------------------------------------
132
133
134
135 // The mac address of the host we're sending to.
136 u2_mac_addr_t host_mac_addr;
137
138
139 void link_changed_callback(int speed);
140 static volatile bool link_is_up = false;        // eth handler sets this
141
142
143 void
144 timer_irq_handler(unsigned irq)
145 {
146   hal_set_timeout(timer_delta); // schedule next timeout
147 }
148
149 // Tx DSP underrun
150 void
151 underrun_irq_handler(unsigned irq)
152 {
153   dsp_tx_regs->clear_state = 1;
154   bp_clear_buf(DSP_TX_BUF_0);
155   bp_clear_buf(DSP_TX_BUF_1);
156   dbsm_stop(&dsp_tx_sm);
157
158   // FIXME anything else?
159
160   putstr("\nirq: underrun\n");
161 }
162
163 // Rx DSP overrun
164 void
165 overrun_irq_handler(unsigned irq)
166 {
167   dsp_rx_regs->clear_state = 1;
168   bp_clear_buf(DSP_RX_BUF_0);
169   bp_clear_buf(DSP_RX_BUF_1);
170   dbsm_stop(&dsp_rx_sm);
171
172   // FIXME anything else?
173
174   putstr("\nirq: overrun\n");
175 }
176
177 static void
178 start_tx_transfers(void)
179 {
180   bp_clear_buf(DSP_TX_BUF_0);   // FIXME, really goes in state machine
181   bp_clear_buf(DSP_TX_BUF_1);
182
183   // fill everything with a constant 32k + 0j
184
185   uint32_t const_sample = (32000 << 16) | 0;
186   int i;
187   for (i = 0; i < BP_NLINES; i++){
188     buffer_ram(DSP_TX_BUF_0)[i] = const_sample;
189     buffer_ram(DSP_TX_BUF_1)[i] = const_sample;
190   }
191
192   /*
193    * Construct  ethernet header and word0 and preload into two buffers
194    */
195   u2_eth_packet_t       pkt;
196   memset(&pkt, 0, sizeof(pkt));
197   //pkt.ehdr.dst = *host;
198   pkt.ehdr.ethertype = U2_ETHERTYPE;
199   u2p_set_word0(&pkt.fixed,
200                 U2P_TX_IMMEDIATE | U2P_TX_START_OF_BURST, 0);
201   u2p_set_timestamp(&pkt.fixed, T_NOW);
202
203   memcpy_wa(buffer_ram(DSP_TX_BUF_0), &pkt, sizeof(pkt));
204   memcpy_wa(buffer_ram(DSP_TX_BUF_1), &pkt, sizeof(pkt));
205
206
207   int tx_scale = 256;
208
209   // setup Tx DSP regs
210   dsp_tx_regs->clear_state = 1;                 // reset
211   dsp_tx_regs->freq = 408021893;                // 9.5 MHz [2**32 * fc/fsample]
212   dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale;
213   dsp_tx_regs->interp_rate = 32;
214
215   // kick off the state machine
216   // dbsm_start(&dsp_rx_sm);
217
218   SEND_CONST_TO_DSP_TX();       // send constant buffer to DSP TX
219 }
220
221
222 void
223 buffer_irq_handler(unsigned irq)
224 {
225   uint32_t  status = buffer_pool_status->status;
226
227   if (0){
228     putstr("irq: ");
229     puthex32(status);
230     putchar('\n');
231   }
232
233   if (status & BPS_ERROR_ALL){
234     // FIXME rare path, handle error conditions
235   }
236
237   if (status & BPS_DONE(DSP_TX_BUF_0)){
238     bp_clear_buf(DSP_TX_BUF_0);
239     SEND_CONST_TO_DSP_TX();
240     hal_toggle_leds(0x1);
241   }
242
243 }
244
245 int
246 main(void)
247 {
248   u2_init();
249
250   // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output
251   //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111");
252   //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111");
253
254   putstr("\ntx_only\n");
255   
256   // Control LEDs
257   hal_set_leds(0x0, 0x3);
258
259   if (USE_BUFFER_INTERRUPT)
260     pic_register_handler(IRQ_BUFFER,   buffer_irq_handler);
261
262   pic_register_handler(IRQ_OVERRUN,  overrun_irq_handler);
263   pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler);
264
265   //pic_register_handler(IRQ_TIMER, timer_irq_handler);
266   //hal_set_timeout(timer_delta);
267
268   ethernet_register_link_changed_callback(link_changed_callback);
269
270   ethernet_init();
271
272   // initialize double buffering state machine for DSP RX -> Ethernet
273   dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0,
274             &dsp_rx_recv_args, &dsp_rx_send_args,
275             dbsm_nop_inspector);
276
277   // setup receive from ETH
278   // bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE);
279
280 #if 0
281   if (hwconfig_simulation_p()){
282     // If we're simulating, pretend that we got a start command from the host
283     u2_mac_addr_t host = {{ 0x00, 0x0A, 0xE4, 0x3E, 0xD2, 0xD5 }};
284     start_rx_cmd(&host);
285   }
286 #endif
287
288   start_tx_transfers();         // send constant buffers to DSP TX
289
290   while(1){
291     if (!USE_BUFFER_INTERRUPT)
292       buffer_irq_handler(0);
293   }
294 }
295
296 // ----------------------------------------------------------------
297
298 // debugging output on tx pins
299 #define LS_MASK  0xE0000
300 #define LS_1000  0x80000
301 #define LS_100   0x40000
302 #define LS_10    0x20000
303
304 /*
305  * Called when eth phy state changes (w/ interrupts disabled)
306  */
307 void
308 link_changed_callback(int speed)
309 {
310   int v = 0;
311   switch(speed){
312   case 10:
313     v = LS_10;
314     link_is_up = true;
315     break;
316     
317   case 100:
318     v = LS_100;
319     link_is_up = true;
320     break;
321     
322   case 1000:
323     v = LS_100;
324     link_is_up = true;
325     break;
326
327   default:
328     v = 0;
329     link_is_up = false;
330     break;
331   }
332
333   //hal_gpio_set_tx(v, LS_MASK);        /* set debug bits on d'board */
334
335   // hal_set_leds(link_is_up ? 0x2 : 0x0, 0x2);
336
337   printf("\neth link changed: speed = %d\n", speed);
338 }