switch source package format to 3.0 quilt
[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.src = *ethernet_mac_addr();
199   pkt.ehdr.ethertype = U2_ETHERTYPE;
200   u2p_set_word0(&pkt.fixed,
201                 U2P_TX_IMMEDIATE | U2P_TX_START_OF_BURST, 0);
202   u2p_set_timestamp(&pkt.fixed, T_NOW);
203
204   memcpy_wa(buffer_ram(DSP_TX_BUF_0), &pkt, sizeof(pkt));
205   memcpy_wa(buffer_ram(DSP_TX_BUF_1), &pkt, sizeof(pkt));
206
207
208   int tx_scale = 256;
209
210   // setup Tx DSP regs
211   dsp_tx_regs->clear_state = 1;                 // reset
212   dsp_tx_regs->freq = 408021893;                // 9.5 MHz [2**32 * fc/fsample]
213   dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale;
214   dsp_tx_regs->interp_rate = 32;
215
216   // kick off the state machine
217   // dbsm_start(&dsp_rx_sm);
218
219   SEND_CONST_TO_DSP_TX();       // send constant buffer to DSP TX
220 }
221
222
223 void
224 buffer_irq_handler(unsigned irq)
225 {
226   uint32_t  status = buffer_pool_status->status;
227
228   if (0){
229     putstr("irq: ");
230     puthex32(status);
231     putchar('\n');
232   }
233
234   if (status & BPS_ERROR_ALL){
235     // FIXME rare path, handle error conditions
236   }
237
238   if (status & BPS_DONE(DSP_TX_BUF_0)){
239     bp_clear_buf(DSP_TX_BUF_0);
240     SEND_CONST_TO_DSP_TX();
241     hal_toggle_leds(0x1);
242   }
243
244 }
245
246 int
247 main(void)
248 {
249   u2_init();
250
251   // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output
252   //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111");
253   //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111");
254
255   putstr("\ntx_only\n");
256   
257   // Control LEDs
258   hal_set_leds(0x0, 0x3);
259
260   if (USE_BUFFER_INTERRUPT)
261     pic_register_handler(IRQ_BUFFER,   buffer_irq_handler);
262
263   pic_register_handler(IRQ_OVERRUN,  overrun_irq_handler);
264   pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler);
265
266   //pic_register_handler(IRQ_TIMER, timer_irq_handler);
267   //hal_set_timeout(timer_delta);
268
269   ethernet_register_link_changed_callback(link_changed_callback);
270
271   ethernet_init();
272
273   // initialize double buffering state machine for DSP RX -> Ethernet
274   dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0,
275             &dsp_rx_recv_args, &dsp_rx_send_args,
276             dbsm_nop_inspector);
277
278   // setup receive from ETH
279   // bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE);
280
281 #if 0
282   if (hwconfig_simulation_p()){
283     // If we're simulating, pretend that we got a start command from the host
284     u2_mac_addr_t host = {{ 0x00, 0x0A, 0xE4, 0x3E, 0xD2, 0xD5 }};
285     start_rx_cmd(&host);
286   }
287 #endif
288
289   start_tx_transfers();         // send constant buffers to DSP TX
290
291   while(1){
292     if (!USE_BUFFER_INTERRUPT)
293       buffer_irq_handler(0);
294   }
295 }
296
297 // ----------------------------------------------------------------
298
299 // debugging output on tx pins
300 #define LS_MASK  0xE0000
301 #define LS_1000  0x80000
302 #define LS_100   0x40000
303 #define LS_10    0x20000
304
305 /*
306  * Called when eth phy state changes (w/ interrupts disabled)
307  */
308 void
309 link_changed_callback(int speed)
310 {
311   int v = 0;
312   switch(speed){
313   case 10:
314     v = LS_10;
315     link_is_up = true;
316     break;
317     
318   case 100:
319     v = LS_100;
320     link_is_up = true;
321     break;
322     
323   case 1000:
324     v = LS_100;
325     link_is_up = true;
326     break;
327
328   default:
329     v = 0;
330     link_is_up = false;
331     break;
332   }
333
334   //hal_gpio_set_tx(v, LS_MASK);        /* set debug bits on d'board */
335
336   // hal_set_leds(link_is_up ? 0x2 : 0x0, 0x2);
337
338   printf("\neth link changed: speed = %d\n", speed);
339 }