]> git.gag.com Git - debian/gnuradio/blob - usrp/host/lib/inband/usrp_server.cc
1948a43b2945de042bd356d1f39a7a6cfcf28905
[debian/gnuradio] / usrp / host / lib / inband / usrp_server.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <usrp_server.h>
26 #include <iostream>
27 #include <usrp_inband_usb_packet.h>
28 #include <mb_class_registry.h>
29 #include <vector>
30 #include <usrp_usb_interface.h>
31 #include <string.h>
32
33 #include <symbols_usrp_server_cs.h>
34 #include <symbols_usrp_channel.h>
35 #include <symbols_usrp_tx.h>
36 #include <symbols_usrp_rx.h>
37 #include <symbols_usrp_low_level_cs.h>
38 #include <symbols_usrp_interface_cs.h>
39
40 static pmt_t s_shutdown = pmt_intern("%shutdown");
41
42 typedef usrp_inband_usb_packet transport_pkt;   // makes conversion to gigabit easy
43
44 const static bool verbose = false;
45
46 static std::string
47 str(long x)
48 {
49   std::ostringstream s;
50   s << x;
51   return s.str();
52 }
53
54 usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg)
55   : mb_mblock(rt, instance_name, user_arg),
56   d_fake_rx(false)
57 {
58   if(verbose)
59     std::cout << "[USRP_SERVER] Initializing...\n";
60
61   // Dictionary for arguments to all of the components
62   pmt_t usrp_dict = user_arg;
63   
64   // control & status port
65   d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL);  
66   d_cs_usrp = define_port("cs_usrp", "usrp-interface-cs", false, mb_port::INTERNAL);    
67
68   // ports
69   //
70   // (if/when we do replicated ports, these will be replaced by a
71   //  single replicated port)
72   for(int port=0; port < N_PORTS; port++) {
73
74     d_tx.push_back(define_port("tx"+str(port), 
75                                "usrp-tx", 
76                                true, 
77                                mb_port::EXTERNAL));
78
79     d_rx.push_back(define_port("rx"+str(port), 
80                                "usrp-rx", 
81                                true, 
82                                mb_port::EXTERNAL));
83   }
84
85   define_component("usrp", "usrp_usb_interface", usrp_dict);
86   connect("self", "cs_usrp", "usrp", "cs");
87
88   d_defer=false;
89   d_opened=false;
90
91   // FIXME: needs to be returned from open, if we want to use this
92   d_nrx_chan = 2;
93   d_ntx_chan = 2;
94
95   // Initialize capacity on each channel to 0 and to no owner
96   // Also initialize the USRP standard tx/rx pointers to NULL
97   for(int chan=0; chan < d_ntx_chan; chan++)
98     d_chaninfo_tx.push_back(channel_info());
99
100   for(int chan=0; chan < d_nrx_chan; chan++)
101     d_chaninfo_rx.push_back(channel_info());
102
103   d_rx_chan_mask = 0;
104
105   for(int i=0; i < D_MAX_RID; i++) 
106     d_rids.push_back(rid_info());
107
108   //d_fake_rx=true;
109 }
110
111 void
112 usrp_server::reset_channels()
113 {
114
115   for(int chan=0; chan < d_ntx_chan; chan++) {
116     d_chaninfo_tx[chan].assigned_capacity = 0;
117     d_chaninfo_tx[chan].owner = PMT_NIL;
118   }
119
120   for(int chan=0; chan < d_nrx_chan; chan++) {
121     d_chaninfo_rx[chan].assigned_capacity = 0;
122     d_chaninfo_rx[chan].owner = PMT_NIL;
123   }
124
125   d_rx_chan_mask = 0;
126 }
127
128 usrp_server::~usrp_server()
129 {
130 }
131
132
133 void
134 usrp_server::initial_transition()
135 {
136   // the initial transition
137 }
138
139 void
140 usrp_server::handle_message(mb_message_sptr msg)
141 {
142   pmt_t event = msg->signal();          // the "name" of the message
143   pmt_t port_id = msg->port_id();       // which port it came in on
144   pmt_t data = msg->data();
145   pmt_t invocation_handle;
146   pmt_t metadata = msg->metadata();
147   pmt_t status;
148
149   long port;
150
151   if (pmt_eq(event, s_shutdown))        // ignore (for now)
152     return;
153
154   invocation_handle = pmt_nth(0, data);
155
156   if (0){
157     std::cout << "[USRP_SERVER] event: " << event << std::endl;
158     std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl;
159   }
160
161   // It would be nice if this were all table driven, and we could compute our
162   // state transition as f(current_state, port_id, signal)
163   
164   // A message from the USRP CS, which should *only* be responses
165   //
166   // It is important that this set come before checking messages of any other
167   // components.  This is since we always want to listen to the low level USRP
168   // server, even if we aren't initialized we are waiting for responses to
169   // become initialized.  Likewise, after the usrp_server is "closed", we still
170   // want to pass responses back from the low level.
171
172   //---------------- USRP RESPONSE ---------------//
173   if (pmt_eq(port_id, d_cs_usrp->port_symbol())) { 
174     
175     //-------------- USRP OPEN ------------------//
176     if(pmt_eq(event, s_response_usrp_open)) {
177       // pass the response back over the regular CS port
178       pmt_t status = pmt_nth(1, data);
179       d_cs->send(s_response_open, pmt_list2(invocation_handle, status));
180
181       if(pmt_eqv(status,PMT_T)) {
182         d_opened = true;
183         d_defer = false;
184         recall_defer_queue();
185       }
186
187       return;
188     }
189     //------------- USRP CLOSE -------------------//
190     else if (pmt_eq(event, s_response_usrp_close)) {
191       pmt_t status = pmt_nth(1, data);
192       d_cs->send(s_response_close, pmt_list2(invocation_handle, status));
193
194       if(pmt_eqv(status,PMT_T)) {
195         d_opened = false;
196         d_defer = false;
197         reset_channels();
198         recall_defer_queue();
199       }
200       
201       return;
202     }
203     //--------------- USRP WRITE --------------//
204     else if (pmt_eq(event, s_response_usrp_write)) {
205       
206       pmt_t status = pmt_nth(1, data);
207       long channel = pmt_to_long(pmt_nth(2, data));
208       long port;
209
210       // Do not report back responses if they were generated from a
211       // command packet
212       if(channel == 0x1f)
213         return;
214
215       // Find the port through the owner of the channel
216       if((port = tx_port_index(d_chaninfo_tx[channel].owner)) !=-1 )
217         d_tx[port]->send(s_response_xmit_raw_frame, 
218                          pmt_list2(invocation_handle, status));
219       return;
220     }
221     //--------------- USRP READ ---------------//
222     else if (pmt_eq(event, s_response_usrp_read)) {
223
224       pmt_t status = pmt_nth(1, data);
225
226       if(!pmt_eqv(status, PMT_T)) {
227         std::cerr << "[USRP_SERVER] Error receiving packet\n";
228         return;
229       }
230       else {
231         handle_response_usrp_read(data);
232         return;
233       }
234     }
235
236     goto unhandled;
237   }
238
239   // Checking for defer on all other messages
240   if(d_defer) {
241     if (verbose)
242       std::cout << "[USRP_SERVER] Received msg while deferring (" 
243                 << msg->signal() << ")\n";
244     d_defer_queue.push(msg);
245     return;
246   }
247   
248   //--------- CONTROL / STATUS ------------//
249   if (pmt_eq(port_id, d_cs->port_symbol())){
250     
251     //----------- OPEN -----------//
252     if (pmt_eq(event, s_cmd_open)){
253
254       // Reject if already open
255       if(d_opened) {
256         d_cs->send(s_response_open, pmt_list2(invocation_handle, s_err_usrp_already_opened));
257         return;
258       }
259
260       // the parameters are the same to the low level interface, so we just pass 'data' along
261       d_cs_usrp->send(s_cmd_usrp_open, data);
262
263       d_defer = true;
264       
265       return;
266     }
267     //---------- CLOSE -----------//
268     else if (pmt_eq(event, s_cmd_close)){
269       
270       if(!d_opened) { 
271         d_cs->send(s_response_close, pmt_list2(invocation_handle, s_err_usrp_already_closed));
272         return;
273       }
274       
275       d_defer = true;
276       d_cs_usrp->send(s_cmd_usrp_close, pmt_list1(invocation_handle));
277
278       return;
279     }
280     //---------- MAX CAPACITY ----------//
281     else if (pmt_eq(event, s_cmd_max_capacity)) {
282       
283       if(!d_opened) { 
284         d_cs->send(s_response_max_capacity, 
285                    pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
286         return;
287       }
288
289       d_cs->send(s_response_max_capacity, 
290                  pmt_list3(invocation_handle, 
291                            PMT_T, 
292                            pmt_from_long(max_capacity())));
293       return;
294     }
295     //---------- NTX CHAN --------------//
296     else if (pmt_eq(event, s_cmd_ntx_chan)) {
297
298       if(!d_opened) { 
299         d_cs->send(s_response_ntx_chan, 
300                    pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
301         return;
302       }
303
304       d_cs->send(s_response_ntx_chan, 
305                  pmt_list3(invocation_handle, 
306                            PMT_T, 
307                            pmt_from_long(d_ntx_chan)));
308       return;
309     }
310     //---------- NRX CHAN -----------//
311     else if (pmt_eq(event, s_cmd_nrx_chan)) {
312
313       if(!d_opened) { 
314         d_cs->send(s_response_nrx_chan, 
315                    pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
316         return;
317       }
318
319       d_cs->send(s_response_nrx_chan, 
320                  pmt_list3(invocation_handle, 
321                            PMT_T, 
322                            pmt_from_long(d_nrx_chan)));
323       return;
324     }   
325     //--------- ALLOCATION? -----------//
326     else if (pmt_eq(event, s_cmd_current_capacity_allocation)) {
327       
328       if(!d_opened) { 
329         d_cs->send(s_response_current_capacity_allocation, 
330                    pmt_list3(invocation_handle, 
331                              s_err_usrp_not_opened, 
332                              pmt_from_long(0)));
333         return;
334       }
335       
336       d_cs->send(s_response_current_capacity_allocation, 
337                  pmt_list3(invocation_handle, 
338                            PMT_T, 
339                            pmt_from_long(current_capacity_allocation())));
340       return;
341     }
342     goto unhandled;
343   }
344   
345   //-------------- TX ---------------//
346   if ((port = tx_port_index(port_id)) != -1) {
347     
348     //------------ ALLOCATE (TX) ----------------//
349     if (pmt_eq(event, s_cmd_allocate_channel)){
350       
351       if(!d_opened) { 
352         d_tx[port]->send(s_response_allocate_channel, 
353                           pmt_list3(invocation_handle, 
354                                     s_err_usrp_not_opened, 
355                                     pmt_from_long(0)));
356         return;
357       }
358         
359       handle_cmd_allocate_channel(d_tx[port], d_chaninfo_tx, data);
360       return;
361     }
362   
363     //----------- DEALLOCATE (TX) ---------------//
364     if (pmt_eq(event, s_cmd_deallocate_channel)) {
365     
366       if(!d_opened) {
367         d_tx[port]->send(s_response_deallocate_channel, 
368                          pmt_list3(invocation_handle, 
369                                    s_err_usrp_not_opened, 
370                                    pmt_from_long(0)));
371         return;
372       }
373
374       handle_cmd_deallocate_channel(d_tx[port], d_chaninfo_tx, data);
375       return;
376     }
377   
378     //-------------- XMIT RAW FRAME -----------------/
379     if (pmt_eq(event, s_cmd_xmit_raw_frame)){
380
381       if(!d_opened) { 
382         d_tx[port]->send(s_response_xmit_raw_frame, 
383                          pmt_list2(invocation_handle, s_err_usrp_not_opened));
384         return;
385       }
386       
387       handle_cmd_xmit_raw_frame(d_tx[port], d_chaninfo_tx, data);
388       return;
389     }
390     
391     //-------------- CONTROL PACKET -----------------/
392     if (pmt_eq(event, s_cmd_to_control_channel)) {
393       
394       if(!d_opened) { 
395         d_tx[port]->send(s_response_xmit_raw_frame, 
396                          pmt_list2(invocation_handle, s_err_usrp_not_opened));
397         return;
398       }
399       
400       handle_cmd_to_control_channel(d_tx[port], d_chaninfo_tx, data);
401       return;
402
403     }
404
405     goto unhandled;
406   }
407
408   //-------------- RX ---------------//
409   if ((port = rx_port_index(port_id)) != -1) {
410     
411     //------------ ALLOCATE (RX) ----------------//
412     if (pmt_eq(event, s_cmd_allocate_channel)) {
413       
414       if(!d_opened) { 
415         d_rx[port]->send(s_response_allocate_channel, 
416                           pmt_list3(invocation_handle, 
417                                     s_err_usrp_not_opened, 
418                                     pmt_from_long(0)));
419         return;
420       }
421         
422       handle_cmd_allocate_channel(d_rx[port], d_chaninfo_rx, data);
423       return;
424     }
425   
426     //----------- DEALLOCATE (RX) ---------------//
427     if (pmt_eq(event, s_cmd_deallocate_channel)) {
428     
429       if(!d_opened) {
430         d_rx[port]->send(s_response_deallocate_channel, 
431                          pmt_list3(invocation_handle, 
432                                    s_err_usrp_not_opened, 
433                                    pmt_from_long(0)));
434         return;
435       }
436
437       handle_cmd_deallocate_channel(d_rx[port], d_chaninfo_rx, data);
438       return;
439     }
440   
441     //-------------- START RECV ----------------//
442     if (pmt_eq(event, s_cmd_start_recv_raw_samples)) {
443     
444       if(!d_opened) {
445         d_rx[port]->send(s_response_recv_raw_samples,
446                          pmt_list2(invocation_handle, s_err_usrp_not_opened));
447         return;
448       }
449
450       handle_cmd_start_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
451       return;
452     }
453     
454     //-------------- STOP RECV ----------------//
455     if (pmt_eq(event, s_cmd_stop_recv_raw_samples)) {
456     
457       if(!d_opened) 
458         return;
459
460       // FIX ME : no response for stopping? even if error? (permissions)
461       handle_cmd_stop_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
462
463       return;
464     }
465
466     goto unhandled;
467   }
468
469  unhandled:
470   std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl;
471 }
472
473 // Return -1 if it is not an RX port, or an index
474 int usrp_server::tx_port_index(pmt_t port_id) {
475
476   for(int i=0; i < (int) d_tx.size(); i++) 
477     if(pmt_eq(d_tx[i]->port_symbol(), port_id))
478       return i;
479
480   return -1;
481 }
482
483 // Return -1 if it is not an RX port, or an index
484 int usrp_server::rx_port_index(pmt_t port_id) {
485   
486   for(int i=0; i < (int) d_rx.size(); i++) 
487     if(pmt_eq(d_rx[i]->port_symbol(), port_id))
488       return i;
489
490   return -1;
491 }
492
493 // Go through all TX and RX channels, sum up the assigned capacity
494 // and return it
495 long usrp_server::current_capacity_allocation() {
496   long capacity = 0;
497
498   for(int chan=0; chan < d_ntx_chan; chan++) 
499     capacity += d_chaninfo_tx[chan].assigned_capacity;
500
501   for(int chan=0; chan < d_nrx_chan; chan++)
502     capacity += d_chaninfo_rx[chan].assigned_capacity;
503
504   return capacity;
505 }
506     
507 void 
508 usrp_server::handle_cmd_allocate_channel(
509                                 mb_port_sptr port, 
510                                 std::vector<struct channel_info> &chan_info,
511                                 pmt_t data)
512 {
513   pmt_t invocation_handle = pmt_nth(0, data);
514   long rqstd_capacity = pmt_to_long(pmt_nth(1, data));
515   long chan;
516
517   // Check capacity exists
518   if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
519
520     // no capacity available
521     port->send(s_response_allocate_channel, 
522                pmt_list3(invocation_handle, 
523                          s_err_requested_capacity_unavailable, 
524                          PMT_NIL));
525     return;
526   }
527
528   // Find a free channel, assign the capacity and respond
529   for(chan=0; chan < (long)chan_info.size(); chan++) {
530
531     if(verbose)
532       std::cout << "[USRP_SERVER] Checking chan: " << chan
533                 << " owner " << chan_info[chan].owner
534                 << " size " << chan_info.size()
535                 << std::endl;
536
537     if(chan_info[chan].owner == PMT_NIL) {
538   
539       chan_info[chan].owner = port->port_symbol();
540       chan_info[chan].assigned_capacity = rqstd_capacity;
541       
542       port->send(s_response_allocate_channel, 
543                  pmt_list3(invocation_handle, 
544                            PMT_T, 
545                            pmt_from_long(chan)));
546
547       if(verbose)
548         std::cout << "[USRP_SERVER] Assigning channel: " << chan 
549                   << " to " << chan_info[chan].owner
550                   << std::endl;
551       return;
552     }
553   
554   }
555
556   if (verbose)
557     std::cout << "[USRP_SERVER] Couldnt find a TX chan\n";
558
559   // no free TX chan found
560   port->send(s_response_allocate_channel, 
561              pmt_list3(invocation_handle, 
562                        s_err_channel_unavailable, 
563                        PMT_NIL));
564   return;
565 }
566
567 // Check the port type and deallocate assigned capacity based on this, ensuring
568 // that the owner of the method invocation is the owner of the port and that the
569 // channel number is valid.
570 void 
571 usrp_server::handle_cmd_deallocate_channel(
572                               mb_port_sptr port, 
573                               std::vector<struct channel_info> &chan_info, 
574                               pmt_t data)
575 {
576
577   pmt_t invocation_handle = pmt_nth(0, data); 
578   long channel = pmt_to_long(pmt_nth(1, data));
579
580   // Ensure the channel is valid and the caller owns the port
581   if(!check_valid(port, channel, chan_info,
582                   pmt_list2(s_response_deallocate_channel, invocation_handle)))
583     return;
584   
585   chan_info[channel].assigned_capacity = 0;
586   chan_info[channel].owner = PMT_NIL;
587
588   port->send(s_response_deallocate_channel, 
589              pmt_list2(invocation_handle, 
590                        PMT_T));
591   return;
592 }
593
594 void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) {
595
596   size_t n_bytes, psize;
597   long max_payload_len = transport_pkt::max_payload();
598
599   pmt_t invocation_handle = pmt_nth(0, data);
600   long channel = pmt_to_long(pmt_nth(1, data));
601   const void *samples = pmt_uniform_vector_elements(pmt_nth(2, data), n_bytes);
602   long timestamp = pmt_to_long(pmt_nth(3, data));
603   pmt_t properties = pmt_nth(4, data);
604   
605   // Ensure the channel is valid and the caller owns the port
606   if(!check_valid(port, channel, chan_info,
607                   pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
608     return;
609
610   // Read information from the properties of the packet
611   bool carrier_sense = false;
612   if(pmt_is_dict(properties)) {
613
614     // Check if carrier sense is enabled for the frame
615     if(pmt_t p_carrier_sense = pmt_dict_ref(properties, 
616                                             pmt_intern("carrier-sense"), 
617                                             PMT_NIL)) {
618       if(pmt_eqv(p_carrier_sense, PMT_T)) 
619         carrier_sense = true;
620     }
621   }
622
623   
624   // Determine the number of packets to allocate contiguous memory for
625   // bursting over the USB and get a pointer to the memory to be used in
626   // building the packets
627   long n_packets = 
628     static_cast<long>(std::ceil(n_bytes / (double)max_payload_len));
629
630   pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
631
632   transport_pkt *pkts =
633     (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, psize);
634
635   for(int n=0; n < n_packets; n++) {
636
637     long payload_len = 
638       std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len);
639   
640     if(n == 0) { // first packet gets start of burst flag and timestamp
641       
642       if(carrier_sense)
643         pkts[n].set_header(pkts[n].FL_START_OF_BURST 
644                            | pkts[n].FL_CARRIER_SENSE, 
645                            channel, 0, payload_len);
646       else
647         pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len);
648
649       pkts[n].set_timestamp(timestamp);
650     
651     } else {
652       pkts[n].set_header(0, channel, 0, payload_len);
653       pkts[n].set_timestamp(0xffffffff);
654     }
655
656     memcpy(pkts[n].payload(), 
657            (uint8_t *)samples+(max_payload_len * n), 
658            payload_len);
659   
660   }
661
662
663   pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst
664
665   if (verbose && 0)
666     std::cout << "[USRP_SERVER] Received raw frame invocation: " 
667               << invocation_handle << std::endl;
668     
669   // The actual response to the write will be generated by a
670   // s_response_usrp_write
671   d_cs_usrp->send(s_cmd_usrp_write, 
672                   pmt_list3(invocation_handle, 
673                             pmt_from_long(channel), 
674                             v_packets));
675
676   return;
677 }
678
679 void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) 
680 {
681
682   pmt_t invocation_handle = pmt_nth(0, data);
683   pmt_t subpackets = pmt_nth(1, data);
684
685   long n_subpkts = pmt_length(subpackets);
686   long curr_subpkt = 0;
687
688   size_t psize;
689   long payload_len = 0;
690   long channel = 0x1f;
691
692   // The design of the following code is optimized for simplicity, not
693   // performance.  To performance optimize this code, the total size in bytes
694   // needed for all of the CS packets is needed to allocate contiguous memory
695   // which contains the USB packets for bursting over the bus.  However to do
696   // this the packets subpackets would need to be parsed twice and their sizes
697   // would need to be determined.
698   //
699   // The approach taken is to keep parsing the subpackets and putting them in to
700   // USB packets.  Once the USB packet is full, a write is sent for it and
701   // another packet is created.
702   //
703   // The subpacket creation methods will return false if the subpacket will not
704   // fit in to the current USB packet.  In these cases a new USB packet is
705   // created and the old is sent.
706   
707   new_packet:
708     // This code needs to become "smart" and only make a new packet when full
709     pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0);
710     transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_packet, psize);
711     payload_len = 0;
712     
713     pkt->set_header(0, channel, 0, payload_len);
714     pkt->set_timestamp(0xffffffff);
715
716   while(curr_subpkt < n_subpkts) {
717
718     pmt_t subp = pmt_nth(curr_subpkt, subpackets);
719     pmt_t subp_cmd = pmt_nth(0, subp);
720     pmt_t subp_data = pmt_nth(1, subp);
721
722     //--------- PING FIXED --------------//
723     if(pmt_eq(subp_cmd, s_op_ping_fixed)) {
724
725       long urid     = pmt_to_long(pmt_nth(0, subp_data));
726       long pingval  = pmt_to_long(pmt_nth(1, subp_data));
727
728       // USRP server sets request ID's to keep track of which application gets
729       // what response back.  To allow a full 6-bits for an RID to the user, we
730       // keep a mapping and replace the RID's as the packets go in and out.  If
731       // there are no RID's available, the command is thrown away silently. 
732       long srid;
733       if((srid = next_rid()) == -1)
734         goto subpkt_bail;
735
736       // We use a vector to store the owner of the ping request and will use it
737       // to send the request on any RX port they own. 
738       d_rids[srid].owner = port->port_symbol();
739       d_rids[srid].user_rid = urid;
740         
741       // Adds a ping after the previous command in the pkt
742       if(!pkt->cs_ping(srid, pingval))
743       {
744         d_cs_usrp->send(s_cmd_usrp_write, 
745                         pmt_list3(invocation_handle, 
746                                   pmt_from_long(channel), 
747                                   v_packet));
748
749         // Return the RID
750         d_rids[srid].owner = PMT_NIL;
751
752         goto new_packet;
753       }
754
755       if(verbose)
756         std::cout << "[USRP_SERVER] Received ping command request"
757                   << " assigning RID " << srid << std::endl;
758
759     }
760   
761     //----------- WRITE REG ---------------//
762     if(pmt_eq(subp_cmd, s_op_write_reg)) {
763       
764       long reg_num = pmt_to_long(pmt_nth(0, subp_data));
765       long val = pmt_to_long(pmt_nth(1, subp_data));
766
767       if(!pkt->cs_write_reg(reg_num, val))
768       {
769         d_cs_usrp->send(s_cmd_usrp_write, 
770                         pmt_list3(invocation_handle, 
771                                   pmt_from_long(channel), 
772                                   v_packet));
773         
774         goto new_packet;
775       }
776       
777       if(verbose)
778         std::cout << "[USRP_SERVER] Received write register request "
779                   << "("
780                   << "Reg: " << reg_num << ", "
781                   << "Val: " << val
782                   << ")\n";
783     }
784     
785     //------- WRITE REG MASKED ----------//
786     if(pmt_eq(subp_cmd, s_op_write_reg_masked)) {
787       
788       long reg_num = pmt_to_long(pmt_nth(0, subp_data));
789       long val = pmt_to_long(pmt_nth(1, subp_data));
790       long mask = pmt_to_long(pmt_nth(2, subp_data));
791
792       if(!pkt->cs_write_reg_masked(reg_num, val, mask))
793       {
794         d_cs_usrp->send(s_cmd_usrp_write, 
795                         pmt_list3(invocation_handle, 
796                                   pmt_from_long(channel), 
797                                   v_packet));
798         
799         goto new_packet;
800       }
801       
802       if(verbose)
803         std::cout << "[USRP_SERVER] Received write register masked request\n";
804     }
805     
806     //------------ READ REG --------------//
807     if(pmt_eq(subp_cmd, s_op_read_reg)) {
808       
809       long urid     = pmt_to_long(pmt_nth(0, subp_data));
810       long reg_num  = pmt_to_long(pmt_nth(1, subp_data));
811
812       long srid;
813       if((srid = next_rid()) == -1)
814         goto subpkt_bail;
815
816       d_rids[srid].owner = port->port_symbol();
817       d_rids[srid].user_rid = urid;
818
819       if(!pkt->cs_read_reg(srid, reg_num))
820       {
821         d_cs_usrp->send(s_cmd_usrp_write, 
822                         pmt_list3(invocation_handle, 
823                                   pmt_from_long(channel), 
824                                   v_packet));
825
826         // Return the rid
827         d_rids[srid].owner = PMT_NIL;
828         
829         goto new_packet;
830       }
831       
832       if(verbose)
833         std::cout << "[USRP_SERVER] Received read register request"
834                   << " assigning RID " << srid << std::endl;
835     }
836     
837     //------------ DELAY --------------//
838     if(pmt_eq(subp_cmd, s_op_delay)) {
839
840       long ticks = pmt_to_long(pmt_nth(0, subp_data));
841
842       if(!pkt->cs_delay(ticks))
843       {
844         d_cs_usrp->send(s_cmd_usrp_write, 
845                         pmt_list3(invocation_handle, 
846                                   pmt_from_long(channel), 
847                                   v_packet));
848         
849         goto new_packet;
850       }
851       
852       if(verbose)
853         std::cout << "[USRP_SERVER] Received delay request of "
854                   << ticks << " ticks\n";
855     }
856
857     //--------- I2C WRITE -----------//
858     // FIXME: could check that byte count does not exceed 2^8 which
859     // is the max length in the subpacket for # of bytes to read.
860     if(pmt_eq(subp_cmd, s_op_i2c_write)) {
861       
862       long i2c_addr = pmt_to_long(pmt_nth(0, subp_data));
863       pmt_t data = pmt_nth(1, subp_data);
864
865       // Get a readable address to the data which also gives us the length
866       size_t data_len;
867       uint8_t *i2c_data = (uint8_t *) pmt_u8vector_writeable_elements(data, data_len);
868
869       // Make the USB packet
870       if(!pkt->cs_i2c_write(i2c_addr, i2c_data, data_len))
871       {
872         d_cs_usrp->send(s_cmd_usrp_write, 
873                         pmt_list3(invocation_handle, 
874                                   pmt_from_long(channel), 
875                                   v_packet));
876         
877         goto new_packet;
878       }
879       
880       if(verbose)
881         std::cout << "[USRP_SERVER] Received I2C write\n";
882     }
883   
884     //----------- I2C Read -------------//
885     if(pmt_eq(subp_cmd, s_op_i2c_read)) {
886       
887       long urid       = pmt_to_long(pmt_nth(0, subp_data));
888       long i2c_addr   = pmt_to_long(pmt_nth(1, subp_data));
889       long i2c_bytes  = pmt_to_long(pmt_nth(2, subp_data));
890
891       long srid;
892       if((srid = next_rid()) == -1)
893         goto subpkt_bail;
894       
895       d_rids[srid].owner = port->port_symbol();
896       d_rids[srid].user_rid = urid;
897
898       if(!pkt->cs_i2c_read(srid, i2c_addr, i2c_bytes))
899       {
900         
901         d_cs_usrp->send(s_cmd_usrp_write, 
902                         pmt_list3(invocation_handle, 
903                                   pmt_from_long(channel), 
904                                   v_packet));
905
906         d_rids[srid].owner = PMT_NIL;
907
908         goto new_packet;
909       }
910       
911       if(verbose)
912         std::cout << "[USRP_SERVER] Received I2C read\n";
913     }
914     
915     //--------- SPI WRITE -----------//
916     if(pmt_eq(subp_cmd, s_op_spi_write)) {
917       
918       long enables = pmt_to_long(pmt_nth(0, subp_data));
919       long format = pmt_to_long(pmt_nth(1, subp_data));
920       long opt = pmt_to_long(pmt_nth(2, subp_data));
921       pmt_t data = pmt_nth(3, subp_data);
922
923       // Get a readable address to the data which also gives us the length
924       size_t data_len;
925       uint8_t *spi_data = (uint8_t *) pmt_u8vector_writeable_elements(data, data_len);
926
927       // Make the USB packet
928       if(!pkt->cs_spi_write(enables, format, opt, spi_data, data_len))
929       {
930         d_cs_usrp->send(s_cmd_usrp_write, 
931                         pmt_list3(invocation_handle, 
932                                   pmt_from_long(channel), 
933                                   v_packet));
934         
935         goto new_packet;
936       }
937       
938       if(verbose)
939         std::cout << "[USRP_SERVER] Received SPI write\n";
940     }
941     
942     //--------- SPI READ -----------//
943     if(pmt_eq(subp_cmd, s_op_spi_read)) {
944       
945       long urid     = pmt_to_long(pmt_nth(0, subp_data));
946       long enables  = pmt_to_long(pmt_nth(1, subp_data));
947       long format   = pmt_to_long(pmt_nth(2, subp_data));
948       long opt      = pmt_to_long(pmt_nth(3, subp_data));
949       long n_bytes  = pmt_to_long(pmt_nth(4, subp_data));
950       
951       long srid;
952       if((srid = next_rid()) == -1)
953         goto subpkt_bail;
954
955       d_rids[srid].owner = port->port_symbol();
956       d_rids[srid].user_rid = urid;
957
958       // Make the USB packet
959       if(!pkt->cs_spi_read(srid, enables, format, opt, n_bytes))
960       {
961         d_cs_usrp->send(s_cmd_usrp_write, 
962                         pmt_list3(invocation_handle, 
963                                   pmt_from_long(channel), 
964                                   v_packet));
965         
966         // Return the rid
967         d_rids[srid].owner = PMT_NIL;
968
969         goto new_packet;
970       }
971       
972       if(verbose)
973         std::cout << "[USRP_SERVER] Received SPI read\n";
974     }
975
976   subpkt_bail:
977     curr_subpkt++;
978
979   }
980
981
982   // If the current packets length is > 0, we know there are subpackets that
983   // need to be sent out still.
984   if(pkt->payload_len() > 0)
985     d_cs_usrp->send(s_cmd_usrp_write, 
986                     pmt_list3(invocation_handle, 
987                               pmt_from_long(channel), 
988                               v_packet));
989
990   return;
991 }
992
993 void
994 usrp_server::handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data)
995 {
996   pmt_t invocation_handle = pmt_nth(0, data);
997   long channel = pmt_to_long(pmt_nth(1, data));
998
999   // Ensure the channel is valid and the caller owns the port
1000   if(!check_valid(port, channel, chan_info,
1001                   pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
1002     return;
1003
1004   // Already started receiving samples? (another start before a stop)
1005   // Check the RX channel bitmask.
1006   if(d_rx_chan_mask & (1 << channel)) {
1007     port->send(s_response_recv_raw_samples,
1008                pmt_list5(invocation_handle,
1009                          s_err_already_receiving,
1010                          PMT_NIL,
1011                          PMT_NIL,
1012                          PMT_NIL));
1013     return;
1014   }
1015
1016   // We only need to generate a 'start reading' command down to the
1017   // low level interface if no other channel is already reading
1018   //
1019   // We carry this over the CS interface because the lower level
1020   // interface does not care about the channel, we only demux it
1021   // at the usrp_server on responses.
1022   if(d_rx_chan_mask == 0) {
1023     
1024     if(verbose)
1025       std::cout << "[USRP_SERVER] Sending read request down to start recv\n";
1026
1027     d_cs_usrp->send(s_cmd_usrp_start_reading, pmt_list1(invocation_handle));
1028   }
1029
1030   d_rx_chan_mask |= 1<<channel;
1031   
1032   return;
1033 }
1034
1035 void
1036 usrp_server::handle_cmd_stop_recv_raw_samples(
1037                         mb_port_sptr port, 
1038                         std::vector<struct channel_info> &chan_info, 
1039                         pmt_t data)
1040 {
1041   pmt_t invocation_handle = pmt_nth(0, data);
1042   long channel = pmt_to_long(pmt_nth(1, data));
1043
1044   // FIX ME : we have no responses to send an error...
1045   // Ensure the channel is valid and the caller owns the port
1046   //if(!check_valid(port, channel, chan_info,
1047   //                pmt_list2(s_response_xmit_raw_frame, invocation_handle)))
1048   //  return;
1049
1050   // Remove this hosts bit from the receiver mask
1051   d_rx_chan_mask &= ~(1<<channel);
1052
1053   // We only need to generate a 'start reading' command down to the
1054   // low level interface if no other channel is already reading
1055   //
1056   // We carry this over the CS interface because the lower level
1057   // interface does not care about the channel, we only demux it
1058   // at the usrp_server on responses.
1059   if(d_rx_chan_mask == 0) {
1060     
1061     if(verbose)
1062       std::cout << "[USRP_SERVER] Sending stop reading request down\n";
1063
1064     d_cs_usrp->send(s_cmd_usrp_stop_reading, pmt_list1(invocation_handle));
1065   }
1066   
1067   return;
1068 }
1069
1070 // Read the packet header, determine the port by the channel owner
1071 void
1072 usrp_server::handle_response_usrp_read(pmt_t data)
1073 {
1074
1075   pmt_t invocation_handle = pmt_nth(0, data);
1076   pmt_t status = pmt_nth(1, data);
1077   pmt_t v_pkt = pmt_nth(2, data);
1078
1079   size_t n_bytes;
1080   size_t ignore;
1081
1082   if (d_fake_rx) {
1083
1084     pmt_t pkt = pmt_nth(2, data);
1085
1086     d_rx[0]->send(s_response_recv_raw_samples,
1087                   pmt_list5(PMT_F,
1088                             PMT_T,
1089                             pkt,
1090                             pmt_from_long(0xffff),
1091                             PMT_NIL));
1092
1093     return;
1094   }
1095
1096   // Extract the packet and return appropriately
1097   transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, n_bytes);
1098
1099   // The channel is used to find the port to pass the samples on
1100   long channel = pkt->chan();
1101   long payload_len = pkt->payload_len();
1102   long port;
1103
1104   // Ignore packets which seem to have incorrect size or size 0
1105   if(payload_len > pkt->max_payload() || payload_len == 0)
1106     return;
1107   
1108   // If the packet is a C/S packet, parse it separately
1109   if(channel == 0x1f) {
1110     parse_control_pkt(invocation_handle, pkt);
1111     return;
1112   }
1113
1114   if((port = rx_port_index(d_chaninfo_rx[channel].owner)) == -1)
1115     return; // Don't know where to send the sample... possibility on abrupt close
1116     
1117   pmt_t v_samples = pmt_make_u8vector(payload_len, 0);
1118   uint8_t *samples = pmt_u8vector_writeable_elements(v_samples, ignore);
1119   
1120   memcpy(samples, pkt->payload(), payload_len);
1121
1122   // Build a properties dictionary to store things such as the RSSI
1123   pmt_t properties =  pmt_make_dict();
1124
1125   pmt_dict_set(properties,
1126                pmt_intern("rssi"),
1127                pmt_from_long(pkt->rssi()));
1128
1129   if(pkt->overrun())
1130     pmt_dict_set(properties,
1131                  pmt_intern("overrun"),
1132                  PMT_T);
1133
1134   if(pkt->underrun())
1135     pmt_dict_set(properties,
1136                  pmt_intern("underrun"),
1137                  PMT_T);
1138
1139   d_rx[port]->send(s_response_recv_raw_samples,
1140                    pmt_list5(invocation_handle,
1141                              status,
1142                              v_samples,
1143                              pmt_from_long(pkt->timestamp()),
1144                              properties));
1145   return;
1146 }
1147
1148 void
1149 usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt)
1150 {
1151
1152   long payload_len = pkt->payload_len();
1153   long curr_payload = 0;
1154   long port;
1155   
1156   // We dispatch based on the control packet type, however we can extract the
1157   // opcode and the length immediately which is consistent in all responses.
1158   //
1159   // Since each control packet can have multiple responses, we keep reading the
1160   // lengths of each subpacket until we reach the payload length.  
1161   while(curr_payload < payload_len) {
1162
1163     pmt_t sub_packet = pkt->read_subpacket(curr_payload);
1164     pmt_t op_symbol = pmt_nth(0, sub_packet);
1165
1166     int len = pkt->cs_len(curr_payload);
1167
1168     if(verbose)
1169       std::cout << "[USRP_SERVER] Parsing subpacket " 
1170                 << op_symbol << " ... length " << len << std::endl;
1171
1172     //----------------- PING RESPONSE ------------------//
1173     if(pmt_eq(op_symbol, s_op_ping_fixed_reply)) {
1174
1175       long srid     = pmt_to_long(pmt_nth(1, sub_packet));
1176       pmt_t pingval = pmt_nth(2, sub_packet);
1177
1178       long urid = d_rids[srid].user_rid;
1179       
1180       if(verbose)
1181         std::cout << "[USRP_SERVER] Found ping response "
1182                   << "("
1183                   << "URID: " << urid << ", "
1184                   << "SRID: " << srid << ", "
1185                   << "VAL: " << pingval 
1186                   << ")\n";
1187       
1188       // Do some bounds checking incase of bogus/corrupt responses
1189       if(srid > D_MAX_RID)
1190         return;
1191
1192       pmt_t owner = d_rids[srid].owner;
1193
1194       // FIXME: should be 1 response for all subpackets here ?
1195       if((port = tx_port_index(owner)) != -1)
1196         d_tx[port]->send(s_response_from_control_channel,
1197                          pmt_list4(invocation_handle,
1198                                    PMT_T,
1199                                    pmt_list2(s_op_ping_fixed_reply, // subp
1200                                              pmt_list2(pmt_from_long(urid), 
1201                                                        pingval)),
1202                                    pmt_from_long(pkt->timestamp())));
1203     }
1204     
1205     //----------------- READ REG RESPONSE ------------------//
1206     else if(pmt_eq(op_symbol, s_op_read_reg_reply)) {
1207
1208       long srid     = pmt_to_long(pmt_nth(1, sub_packet));
1209       pmt_t reg_num = pmt_nth(2, sub_packet);
1210       pmt_t reg_val = pmt_nth(3, sub_packet);
1211
1212       long urid = d_rids[srid].user_rid;
1213       
1214       if(verbose)
1215         std::cout << "[USRP_SERVER] Found read register response "
1216                   << "("
1217                   << "URID: " << urid << ", "
1218                   << "SRID: " << srid << ", "
1219                   << "REG: " << reg_num << ", "
1220                   << "VAL: " << reg_val 
1221                   << ")\n";
1222
1223       // Do some bounds checking to avoid seg faults
1224       if(srid > D_MAX_RID)
1225         return;
1226       
1227       pmt_t owner = d_rids[srid].owner;
1228
1229       // FIXME: should be 1 response for all subpackets here ?
1230       if((port = tx_port_index(owner)) != -1)
1231         d_tx[port]->send(s_response_from_control_channel,
1232                          pmt_list4(invocation_handle,
1233                                    PMT_T,
1234                                    pmt_list2(s_op_read_reg_reply, // subp
1235                                              pmt_list3(pmt_from_long(urid), 
1236                                                        reg_num, 
1237                                                        reg_val)),
1238                                    pmt_from_long(pkt->timestamp())));
1239     }
1240
1241     //------------------ I2C READ REPLY -------------------//
1242     else if(pmt_eq(op_symbol, s_op_i2c_read_reply)) {
1243
1244       long srid       = pmt_to_long(pmt_nth(1, sub_packet));
1245       pmt_t i2c_addr  = pmt_nth(2, sub_packet);
1246       pmt_t i2c_data  = pmt_nth(3, sub_packet);
1247
1248       long urid = d_rids[srid].user_rid;
1249
1250       if(verbose)
1251         std::cout << "[USRP_SERVER] Found i2c read reply "
1252                   << "("
1253                   << "URID: " << urid << ", "
1254                   << "SRID: " << srid << ", "
1255                   << "Addr: " << i2c_addr << ", "
1256                   << "Data: " << i2c_data
1257                   << ")\n";
1258       
1259       // Do some bounds checking to avoid seg faults
1260       if(srid > D_MAX_RID)
1261         return;
1262
1263       pmt_t owner = d_rids[srid].owner;
1264
1265       if((port = tx_port_index(owner)) != -1)
1266         d_tx[port]->send(s_response_from_control_channel,
1267                          pmt_list4(invocation_handle,
1268                                    PMT_T,
1269                                    pmt_list2(s_op_i2c_read_reply,
1270                                              pmt_list3(pmt_from_long(urid), 
1271                                                        i2c_addr,
1272                                                        i2c_data)),
1273                                    pmt_from_long(pkt->timestamp())));
1274     }
1275
1276     //------------------ SPI READ REPLY -------------------//
1277     else if(pmt_eq(op_symbol, s_op_spi_read_reply)) {
1278       
1279       long srid       = pmt_to_long(pmt_nth(1, sub_packet));
1280       pmt_t spi_data  = pmt_nth(2, sub_packet);
1281       
1282       long urid = d_rids[srid].user_rid;
1283
1284       if(verbose)
1285         std::cout << "[USRP_SERVER] Found SPI read reply "
1286                   << "("
1287                   << "URID: " << urid << ", "
1288                   << "SRID: " << srid << ", "
1289                   << "Data: " << spi_data
1290                   << ")\n";
1291
1292       // Bounds check the RID
1293       if(srid > D_MAX_RID)
1294         return;
1295
1296       pmt_t owner = d_rids[srid].owner;
1297
1298       if((port = tx_port_index(owner)) != -1)
1299         d_tx[port]->send(s_response_from_control_channel,
1300                          pmt_list4(invocation_handle,
1301                                    PMT_T,
1302                                    pmt_list2(s_op_spi_read_reply,
1303                                              pmt_list2(pmt_from_long(urid), 
1304                                                        spi_data)),
1305                                    pmt_from_long(pkt->timestamp())));
1306     }
1307
1308     // Each subpacket has an unaccounted for 2 bytes which is the opcode
1309     // and the length field
1310     curr_payload += len + 2;
1311     
1312     // All subpackets are 32-bit aligned
1313     int align_offset = 4 - (curr_payload % 4);
1314
1315     if(align_offset != 4)
1316       curr_payload += align_offset;
1317   }
1318 }
1319
1320 void
1321 usrp_server::recall_defer_queue()
1322 {
1323
1324   std::vector<mb_message_sptr> recall;
1325
1326   while(!d_defer_queue.empty()) {
1327     recall.push_back(d_defer_queue.front());
1328     d_defer_queue.pop();
1329   }
1330
1331   // Parse the messages that were queued while waiting for an open response
1332   for(int i=0; i < (int)recall.size(); i++) 
1333     handle_message(recall[i]);
1334
1335   return;
1336 }
1337
1338 bool
1339 usrp_server::check_valid(mb_port_sptr port,
1340                          long channel,
1341                          std::vector<struct channel_info> &chan_info,
1342                          pmt_t signal_info)
1343 {
1344
1345   pmt_t response_signal = pmt_nth(0, signal_info);
1346   pmt_t invocation_handle = pmt_nth(1, signal_info);
1347
1348   // not a valid channel number?
1349   if(channel >= (long)chan_info.size() && channel != 0x1f) {
1350     port->send(response_signal, 
1351                pmt_list2(invocation_handle, 
1352                          s_err_channel_invalid));
1353
1354     if(verbose)
1355       std::cout << "[USRP_SERVER] Invalid channel number for event " 
1356                 << response_signal << std::endl;
1357     return false;
1358   }
1359   
1360   // not the owner of the port?
1361   if(chan_info[channel].owner != port->port_symbol()) {
1362     port->send(response_signal, 
1363                pmt_list2(invocation_handle, 
1364                          s_err_channel_permission_denied));
1365     
1366     if(verbose)
1367       std::cout << "[USRP_SERVER] Invalid permissions"
1368                 << " for " << response_signal
1369                 << " from " << port->port_symbol()
1370                 << " proper owner is " << chan_info[channel].owner
1371                 << " on channel " << channel
1372                 << " invocation " << invocation_handle
1373                 << std::endl;
1374     return false;
1375   }
1376
1377   return true;
1378 }
1379
1380 // Goes through the vector of RIDs and retreieves an
1381 // available one for use
1382 long
1383 usrp_server::next_rid()
1384 {
1385   for(int i = 0; i < D_MAX_RID; i++)
1386     if(pmt_eqv(d_rids[i].owner, PMT_NIL))
1387       return i;
1388
1389   return -1;
1390 }
1391
1392 REGISTER_MBLOCK_CLASS(usrp_server);