3 * Copyright 2007 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
25 #include <usrp_server.h>
27 #include <usrp_inband_usb_packet.h>
28 #include <mb_class_registry.h>
30 #include <usrp_usb_interface.h>
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>
40 static pmt_t s_shutdown = pmt_intern("%shutdown");
42 typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
44 const static bool verbose = false;
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),
59 std::cout << "[USRP_SERVER] Initializing...\n";
61 // Dictionary for arguments to all of the components
62 pmt_t usrp_dict = user_arg;
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);
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++) {
74 d_tx.push_back(define_port("tx"+str(port),
79 d_rx.push_back(define_port("rx"+str(port),
85 define_component("usrp", "usrp_usb_interface", usrp_dict);
86 connect("self", "cs_usrp", "usrp", "cs");
91 // FIXME: needs to be returned from open, if we want to use this
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());
100 for(int chan=0; chan < d_nrx_chan; chan++)
101 d_chaninfo_rx.push_back(channel_info());
105 for(int i=0; i < D_MAX_RID; i++)
106 d_rids.push_back(rid_info());
112 usrp_server::reset_channels()
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;
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;
128 usrp_server::~usrp_server()
134 usrp_server::initial_transition()
136 // the initial transition
140 usrp_server::handle_message(mb_message_sptr msg)
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();
151 if (pmt_eq(event, s_shutdown)) // ignore (for now)
154 invocation_handle = pmt_nth(0, data);
157 std::cout << "[USRP_SERVER] event: " << event << std::endl;
158 std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl;
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)
164 // A message from the USRP CS, which should *only* be responses
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.
172 //---------------- USRP RESPONSE ---------------//
173 if (pmt_eq(port_id, d_cs_usrp->port_symbol())) {
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));
181 if(pmt_eqv(status,PMT_T)) {
184 recall_defer_queue();
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));
194 if(pmt_eqv(status,PMT_T)) {
198 recall_defer_queue();
203 //--------------- USRP WRITE --------------//
204 else if (pmt_eq(event, s_response_usrp_write)) {
206 pmt_t status = pmt_nth(1, data);
207 long channel = pmt_to_long(pmt_nth(2, data));
210 // Do not report back responses if they were generated from a
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));
221 //--------------- USRP READ ---------------//
222 else if (pmt_eq(event, s_response_usrp_read)) {
224 pmt_t status = pmt_nth(1, data);
226 if(!pmt_eqv(status, PMT_T)) {
227 std::cerr << "[USRP_SERVER] Error receiving packet\n";
231 handle_response_usrp_read(data);
239 // Checking for defer on all other messages
242 std::cout << "[USRP_SERVER] Received msg while deferring ("
243 << msg->signal() << ")\n";
244 d_defer_queue.push(msg);
248 //--------- CONTROL / STATUS ------------//
249 if (pmt_eq(port_id, d_cs->port_symbol())){
251 //----------- OPEN -----------//
252 if (pmt_eq(event, s_cmd_open)){
254 // Reject if already open
256 d_cs->send(s_response_open, pmt_list2(invocation_handle, s_err_usrp_already_opened));
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);
267 //---------- CLOSE -----------//
268 else if (pmt_eq(event, s_cmd_close)){
271 d_cs->send(s_response_close, pmt_list2(invocation_handle, s_err_usrp_already_closed));
276 d_cs_usrp->send(s_cmd_usrp_close, pmt_list1(invocation_handle));
280 //---------- MAX CAPACITY ----------//
281 else if (pmt_eq(event, s_cmd_max_capacity)) {
284 d_cs->send(s_response_max_capacity,
285 pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
289 d_cs->send(s_response_max_capacity,
290 pmt_list3(invocation_handle,
292 pmt_from_long(max_capacity())));
295 //---------- NTX CHAN --------------//
296 else if (pmt_eq(event, s_cmd_ntx_chan)) {
299 d_cs->send(s_response_ntx_chan,
300 pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
304 d_cs->send(s_response_ntx_chan,
305 pmt_list3(invocation_handle,
307 pmt_from_long(d_ntx_chan)));
310 //---------- NRX CHAN -----------//
311 else if (pmt_eq(event, s_cmd_nrx_chan)) {
314 d_cs->send(s_response_nrx_chan,
315 pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0)));
319 d_cs->send(s_response_nrx_chan,
320 pmt_list3(invocation_handle,
322 pmt_from_long(d_nrx_chan)));
325 //--------- ALLOCATION? -----------//
326 else if (pmt_eq(event, s_cmd_current_capacity_allocation)) {
329 d_cs->send(s_response_current_capacity_allocation,
330 pmt_list3(invocation_handle,
331 s_err_usrp_not_opened,
336 d_cs->send(s_response_current_capacity_allocation,
337 pmt_list3(invocation_handle,
339 pmt_from_long(current_capacity_allocation())));
345 //-------------- TX ---------------//
346 if ((port = tx_port_index(port_id)) != -1) {
348 //------------ ALLOCATE (TX) ----------------//
349 if (pmt_eq(event, s_cmd_allocate_channel)){
352 d_tx[port]->send(s_response_allocate_channel,
353 pmt_list3(invocation_handle,
354 s_err_usrp_not_opened,
359 handle_cmd_allocate_channel(d_tx[port], d_chaninfo_tx, data);
363 //----------- DEALLOCATE (TX) ---------------//
364 if (pmt_eq(event, s_cmd_deallocate_channel)) {
367 d_tx[port]->send(s_response_deallocate_channel,
368 pmt_list3(invocation_handle,
369 s_err_usrp_not_opened,
374 handle_cmd_deallocate_channel(d_tx[port], d_chaninfo_tx, data);
378 //-------------- XMIT RAW FRAME -----------------/
379 if (pmt_eq(event, s_cmd_xmit_raw_frame)){
382 d_tx[port]->send(s_response_xmit_raw_frame,
383 pmt_list2(invocation_handle, s_err_usrp_not_opened));
387 handle_cmd_xmit_raw_frame(d_tx[port], d_chaninfo_tx, data);
391 //-------------- CONTROL PACKET -----------------/
392 if (pmt_eq(event, s_cmd_to_control_channel)) {
395 d_tx[port]->send(s_response_xmit_raw_frame,
396 pmt_list2(invocation_handle, s_err_usrp_not_opened));
400 handle_cmd_to_control_channel(d_tx[port], d_chaninfo_tx, data);
408 //-------------- RX ---------------//
409 if ((port = rx_port_index(port_id)) != -1) {
411 //------------ ALLOCATE (RX) ----------------//
412 if (pmt_eq(event, s_cmd_allocate_channel)) {
415 d_rx[port]->send(s_response_allocate_channel,
416 pmt_list3(invocation_handle,
417 s_err_usrp_not_opened,
422 handle_cmd_allocate_channel(d_rx[port], d_chaninfo_rx, data);
426 //----------- DEALLOCATE (RX) ---------------//
427 if (pmt_eq(event, s_cmd_deallocate_channel)) {
430 d_rx[port]->send(s_response_deallocate_channel,
431 pmt_list3(invocation_handle,
432 s_err_usrp_not_opened,
437 handle_cmd_deallocate_channel(d_rx[port], d_chaninfo_rx, data);
441 //-------------- START RECV ----------------//
442 if (pmt_eq(event, s_cmd_start_recv_raw_samples)) {
445 d_rx[port]->send(s_response_recv_raw_samples,
446 pmt_list2(invocation_handle, s_err_usrp_not_opened));
450 handle_cmd_start_recv_raw_samples(d_rx[port], d_chaninfo_rx, data);
454 //-------------- STOP RECV ----------------//
455 if (pmt_eq(event, s_cmd_stop_recv_raw_samples)) {
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);
470 std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl;
473 // Return -1 if it is not an RX port, or an index
474 int usrp_server::tx_port_index(pmt_t port_id) {
476 for(int i=0; i < (int) d_tx.size(); i++)
477 if(pmt_eq(d_tx[i]->port_symbol(), port_id))
483 // Return -1 if it is not an RX port, or an index
484 int usrp_server::rx_port_index(pmt_t port_id) {
486 for(int i=0; i < (int) d_rx.size(); i++)
487 if(pmt_eq(d_rx[i]->port_symbol(), port_id))
493 // Go through all TX and RX channels, sum up the assigned capacity
495 long usrp_server::current_capacity_allocation() {
498 for(int chan=0; chan < d_ntx_chan; chan++)
499 capacity += d_chaninfo_tx[chan].assigned_capacity;
501 for(int chan=0; chan < d_nrx_chan; chan++)
502 capacity += d_chaninfo_rx[chan].assigned_capacity;
508 usrp_server::handle_cmd_allocate_channel(
510 std::vector<struct channel_info> &chan_info,
513 pmt_t invocation_handle = pmt_nth(0, data);
514 long rqstd_capacity = pmt_to_long(pmt_nth(1, data));
517 // Check capacity exists
518 if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) {
520 // no capacity available
521 port->send(s_response_allocate_channel,
522 pmt_list3(invocation_handle,
523 s_err_requested_capacity_unavailable,
528 // Find a free channel, assign the capacity and respond
529 for(chan=0; chan < (long)chan_info.size(); chan++) {
532 std::cout << "[USRP_SERVER] Checking chan: " << chan
533 << " owner " << chan_info[chan].owner
534 << " size " << chan_info.size()
537 if(chan_info[chan].owner == PMT_NIL) {
539 chan_info[chan].owner = port->port_symbol();
540 chan_info[chan].assigned_capacity = rqstd_capacity;
542 port->send(s_response_allocate_channel,
543 pmt_list3(invocation_handle,
545 pmt_from_long(chan)));
548 std::cout << "[USRP_SERVER] Assigning channel: " << chan
549 << " to " << chan_info[chan].owner
557 std::cout << "[USRP_SERVER] Couldnt find a TX chan\n";
559 // no free TX chan found
560 port->send(s_response_allocate_channel,
561 pmt_list3(invocation_handle,
562 s_err_channel_unavailable,
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.
571 usrp_server::handle_cmd_deallocate_channel(
573 std::vector<struct channel_info> &chan_info,
577 pmt_t invocation_handle = pmt_nth(0, data);
578 long channel = pmt_to_long(pmt_nth(1, data));
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)))
585 chan_info[channel].assigned_capacity = 0;
586 chan_info[channel].owner = PMT_NIL;
588 port->send(s_response_deallocate_channel,
589 pmt_list2(invocation_handle,
594 void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) {
596 size_t n_bytes, psize;
597 long max_payload_len = transport_pkt::max_payload();
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);
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)))
610 // Read information from the properties of the packet
611 bool carrier_sense = false;
612 if(pmt_is_dict(properties)) {
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"),
618 if(pmt_eqv(p_carrier_sense, PMT_T))
619 carrier_sense = true;
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
628 static_cast<long>(std::ceil(n_bytes / (double)max_payload_len));
630 pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
632 transport_pkt *pkts =
633 (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, psize);
635 for(int n=0; n < n_packets; n++) {
638 std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len);
640 if(n == 0) { // first packet gets start of burst flag and timestamp
643 pkts[n].set_header(pkts[n].FL_START_OF_BURST
644 | pkts[n].FL_CARRIER_SENSE,
645 channel, 0, payload_len);
647 pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len);
649 pkts[n].set_timestamp(timestamp);
652 pkts[n].set_header(0, channel, 0, payload_len);
653 pkts[n].set_timestamp(0xffffffff);
656 memcpy(pkts[n].payload(),
657 (uint8_t *)samples+(max_payload_len * n),
663 pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst
666 std::cout << "[USRP_SERVER] Received raw frame invocation: "
667 << invocation_handle << std::endl;
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),
679 void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data)
682 pmt_t invocation_handle = pmt_nth(0, data);
683 pmt_t subpackets = pmt_nth(1, data);
685 long n_subpkts = pmt_length(subpackets);
686 long curr_subpkt = 0;
689 long payload_len = 0;
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.
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.
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.
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);
713 pkt->set_header(0, channel, 0, payload_len);
714 pkt->set_timestamp(0xffffffff);
716 while(curr_subpkt < n_subpkts) {
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);
722 //--------- PING FIXED --------------//
723 if(pmt_eq(subp_cmd, s_op_ping_fixed)) {
725 long urid = pmt_to_long(pmt_nth(0, subp_data));
726 long pingval = pmt_to_long(pmt_nth(1, subp_data));
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.
733 if((srid = next_rid()) == -1)
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;
741 // Adds a ping after the previous command in the pkt
742 if(!pkt->cs_ping(srid, pingval))
744 d_cs_usrp->send(s_cmd_usrp_write,
745 pmt_list3(invocation_handle,
746 pmt_from_long(channel),
750 d_rids[srid].owner = PMT_NIL;
756 std::cout << "[USRP_SERVER] Received ping command request"
757 << " assigning RID " << srid << std::endl;
761 //----------- WRITE REG ---------------//
762 if(pmt_eq(subp_cmd, s_op_write_reg)) {
764 long reg_num = pmt_to_long(pmt_nth(0, subp_data));
765 long val = pmt_to_long(pmt_nth(1, subp_data));
767 if(!pkt->cs_write_reg(reg_num, val))
769 d_cs_usrp->send(s_cmd_usrp_write,
770 pmt_list3(invocation_handle,
771 pmt_from_long(channel),
778 std::cout << "[USRP_SERVER] Received write register request "
780 << "Reg: " << reg_num << ", "
785 //------- WRITE REG MASKED ----------//
786 if(pmt_eq(subp_cmd, s_op_write_reg_masked)) {
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));
792 if(!pkt->cs_write_reg_masked(reg_num, val, mask))
794 d_cs_usrp->send(s_cmd_usrp_write,
795 pmt_list3(invocation_handle,
796 pmt_from_long(channel),
803 std::cout << "[USRP_SERVER] Received write register masked request\n";
806 //------------ READ REG --------------//
807 if(pmt_eq(subp_cmd, s_op_read_reg)) {
809 long urid = pmt_to_long(pmt_nth(0, subp_data));
810 long reg_num = pmt_to_long(pmt_nth(1, subp_data));
813 if((srid = next_rid()) == -1)
816 d_rids[srid].owner = port->port_symbol();
817 d_rids[srid].user_rid = urid;
819 if(!pkt->cs_read_reg(srid, reg_num))
821 d_cs_usrp->send(s_cmd_usrp_write,
822 pmt_list3(invocation_handle,
823 pmt_from_long(channel),
827 d_rids[srid].owner = PMT_NIL;
833 std::cout << "[USRP_SERVER] Received read register request"
834 << " assigning RID " << srid << std::endl;
837 //------------ DELAY --------------//
838 if(pmt_eq(subp_cmd, s_op_delay)) {
840 long ticks = pmt_to_long(pmt_nth(0, subp_data));
842 if(!pkt->cs_delay(ticks))
844 d_cs_usrp->send(s_cmd_usrp_write,
845 pmt_list3(invocation_handle,
846 pmt_from_long(channel),
853 std::cout << "[USRP_SERVER] Received delay request of "
854 << ticks << " ticks\n";
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)) {
862 long i2c_addr = pmt_to_long(pmt_nth(0, subp_data));
863 pmt_t data = pmt_nth(1, subp_data);
865 // Get a readable address to the data which also gives us the length
867 uint8_t *i2c_data = (uint8_t *) pmt_u8vector_writeable_elements(data, data_len);
869 // Make the USB packet
870 if(!pkt->cs_i2c_write(i2c_addr, i2c_data, data_len))
872 d_cs_usrp->send(s_cmd_usrp_write,
873 pmt_list3(invocation_handle,
874 pmt_from_long(channel),
881 std::cout << "[USRP_SERVER] Received I2C write\n";
884 //----------- I2C Read -------------//
885 if(pmt_eq(subp_cmd, s_op_i2c_read)) {
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));
892 if((srid = next_rid()) == -1)
895 d_rids[srid].owner = port->port_symbol();
896 d_rids[srid].user_rid = urid;
898 if(!pkt->cs_i2c_read(srid, i2c_addr, i2c_bytes))
901 d_cs_usrp->send(s_cmd_usrp_write,
902 pmt_list3(invocation_handle,
903 pmt_from_long(channel),
906 d_rids[srid].owner = PMT_NIL;
912 std::cout << "[USRP_SERVER] Received I2C read\n";
915 //--------- SPI WRITE -----------//
916 if(pmt_eq(subp_cmd, s_op_spi_write)) {
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);
923 // Get a readable address to the data which also gives us the length
925 uint8_t *spi_data = (uint8_t *) pmt_u8vector_writeable_elements(data, data_len);
927 // Make the USB packet
928 if(!pkt->cs_spi_write(enables, format, opt, spi_data, data_len))
930 d_cs_usrp->send(s_cmd_usrp_write,
931 pmt_list3(invocation_handle,
932 pmt_from_long(channel),
939 std::cout << "[USRP_SERVER] Received SPI write\n";
942 //--------- SPI READ -----------//
943 if(pmt_eq(subp_cmd, s_op_spi_read)) {
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));
952 if((srid = next_rid()) == -1)
955 d_rids[srid].owner = port->port_symbol();
956 d_rids[srid].user_rid = urid;
958 // Make the USB packet
959 if(!pkt->cs_spi_read(srid, enables, format, opt, n_bytes))
961 d_cs_usrp->send(s_cmd_usrp_write,
962 pmt_list3(invocation_handle,
963 pmt_from_long(channel),
967 d_rids[srid].owner = PMT_NIL;
973 std::cout << "[USRP_SERVER] Received SPI read\n";
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),
994 usrp_server::handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data)
996 pmt_t invocation_handle = pmt_nth(0, data);
997 long channel = pmt_to_long(pmt_nth(1, data));
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)))
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,
1016 // We only need to generate a 'start reading' command down to the
1017 // low level interface if no other channel is already reading
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) {
1025 std::cout << "[USRP_SERVER] Sending read request down to start recv\n";
1027 d_cs_usrp->send(s_cmd_usrp_start_reading, pmt_list1(invocation_handle));
1030 d_rx_chan_mask |= 1<<channel;
1036 usrp_server::handle_cmd_stop_recv_raw_samples(
1038 std::vector<struct channel_info> &chan_info,
1041 pmt_t invocation_handle = pmt_nth(0, data);
1042 long channel = pmt_to_long(pmt_nth(1, data));
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)))
1050 // Remove this hosts bit from the receiver mask
1051 d_rx_chan_mask &= ~(1<<channel);
1053 // We only need to generate a 'start reading' command down to the
1054 // low level interface if no other channel is already reading
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) {
1062 std::cout << "[USRP_SERVER] Sending stop reading request down\n";
1064 d_cs_usrp->send(s_cmd_usrp_stop_reading, pmt_list1(invocation_handle));
1070 // Read the packet header, determine the port by the channel owner
1072 usrp_server::handle_response_usrp_read(pmt_t data)
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);
1084 pmt_t pkt = pmt_nth(2, data);
1086 d_rx[0]->send(s_response_recv_raw_samples,
1090 pmt_from_long(0xffff),
1096 // Extract the packet and return appropriately
1097 transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, n_bytes);
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();
1104 // Ignore packets which seem to have incorrect size or size 0
1105 if(payload_len > pkt->max_payload() || payload_len == 0)
1108 // If the packet is a C/S packet, parse it separately
1109 if(channel == 0x1f) {
1110 parse_control_pkt(invocation_handle, pkt);
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
1117 pmt_t v_samples = pmt_make_u8vector(payload_len, 0);
1118 uint8_t *samples = pmt_u8vector_writeable_elements(v_samples, ignore);
1120 memcpy(samples, pkt->payload(), payload_len);
1122 // Build a properties dictionary to store things such as the RSSI
1123 pmt_t properties = pmt_make_dict();
1125 pmt_dict_set(properties,
1127 pmt_from_long(pkt->rssi()));
1130 pmt_dict_set(properties,
1131 pmt_intern("overrun"),
1135 pmt_dict_set(properties,
1136 pmt_intern("underrun"),
1139 d_rx[port]->send(s_response_recv_raw_samples,
1140 pmt_list5(invocation_handle,
1143 pmt_from_long(pkt->timestamp()),
1149 usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt)
1152 long payload_len = pkt->payload_len();
1153 long curr_payload = 0;
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.
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) {
1163 pmt_t sub_packet = pkt->read_subpacket(curr_payload);
1164 pmt_t op_symbol = pmt_nth(0, sub_packet);
1166 int len = pkt->cs_len(curr_payload);
1169 std::cout << "[USRP_SERVER] Parsing subpacket "
1170 << op_symbol << " ... length " << len << std::endl;
1172 //----------------- PING RESPONSE ------------------//
1173 if(pmt_eq(op_symbol, s_op_ping_fixed_reply)) {
1175 long srid = pmt_to_long(pmt_nth(1, sub_packet));
1176 pmt_t pingval = pmt_nth(2, sub_packet);
1178 long urid = d_rids[srid].user_rid;
1181 std::cout << "[USRP_SERVER] Found ping response "
1183 << "URID: " << urid << ", "
1184 << "SRID: " << srid << ", "
1185 << "VAL: " << pingval
1188 // Do some bounds checking incase of bogus/corrupt responses
1189 if(srid > D_MAX_RID)
1192 pmt_t owner = d_rids[srid].owner;
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,
1199 pmt_list2(s_op_ping_fixed_reply, // subp
1200 pmt_list2(pmt_from_long(urid),
1202 pmt_from_long(pkt->timestamp())));
1205 //----------------- READ REG RESPONSE ------------------//
1206 else if(pmt_eq(op_symbol, s_op_read_reg_reply)) {
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);
1212 long urid = d_rids[srid].user_rid;
1215 std::cout << "[USRP_SERVER] Found read register response "
1217 << "URID: " << urid << ", "
1218 << "SRID: " << srid << ", "
1219 << "REG: " << reg_num << ", "
1220 << "VAL: " << reg_val
1223 // Do some bounds checking to avoid seg faults
1224 if(srid > D_MAX_RID)
1227 pmt_t owner = d_rids[srid].owner;
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,
1234 pmt_list2(s_op_read_reg_reply, // subp
1235 pmt_list3(pmt_from_long(urid),
1238 pmt_from_long(pkt->timestamp())));
1241 //------------------ I2C READ REPLY -------------------//
1242 else if(pmt_eq(op_symbol, s_op_i2c_read_reply)) {
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);
1248 long urid = d_rids[srid].user_rid;
1251 std::cout << "[USRP_SERVER] Found i2c read reply "
1253 << "URID: " << urid << ", "
1254 << "SRID: " << srid << ", "
1255 << "Addr: " << i2c_addr << ", "
1256 << "Data: " << i2c_data
1259 // Do some bounds checking to avoid seg faults
1260 if(srid > D_MAX_RID)
1263 pmt_t owner = d_rids[srid].owner;
1265 if((port = tx_port_index(owner)) != -1)
1266 d_tx[port]->send(s_response_from_control_channel,
1267 pmt_list4(invocation_handle,
1269 pmt_list2(s_op_i2c_read_reply,
1270 pmt_list3(pmt_from_long(urid),
1273 pmt_from_long(pkt->timestamp())));
1276 //------------------ SPI READ REPLY -------------------//
1277 else if(pmt_eq(op_symbol, s_op_spi_read_reply)) {
1279 long srid = pmt_to_long(pmt_nth(1, sub_packet));
1280 pmt_t spi_data = pmt_nth(2, sub_packet);
1282 long urid = d_rids[srid].user_rid;
1285 std::cout << "[USRP_SERVER] Found SPI read reply "
1287 << "URID: " << urid << ", "
1288 << "SRID: " << srid << ", "
1289 << "Data: " << spi_data
1292 // Bounds check the RID
1293 if(srid > D_MAX_RID)
1296 pmt_t owner = d_rids[srid].owner;
1298 if((port = tx_port_index(owner)) != -1)
1299 d_tx[port]->send(s_response_from_control_channel,
1300 pmt_list4(invocation_handle,
1302 pmt_list2(s_op_spi_read_reply,
1303 pmt_list2(pmt_from_long(urid),
1305 pmt_from_long(pkt->timestamp())));
1308 // Each subpacket has an unaccounted for 2 bytes which is the opcode
1309 // and the length field
1310 curr_payload += len + 2;
1312 // All subpackets are 32-bit aligned
1313 int align_offset = 4 - (curr_payload % 4);
1315 if(align_offset != 4)
1316 curr_payload += align_offset;
1321 usrp_server::recall_defer_queue()
1324 std::vector<mb_message_sptr> recall;
1326 while(!d_defer_queue.empty()) {
1327 recall.push_back(d_defer_queue.front());
1328 d_defer_queue.pop();
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]);
1339 usrp_server::check_valid(mb_port_sptr port,
1341 std::vector<struct channel_info> &chan_info,
1345 pmt_t response_signal = pmt_nth(0, signal_info);
1346 pmt_t invocation_handle = pmt_nth(1, signal_info);
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));
1355 std::cout << "[USRP_SERVER] Invalid channel number for event "
1356 << response_signal << std::endl;
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));
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
1380 // Goes through the vector of RIDs and retreieves an
1381 // available one for use
1383 usrp_server::next_rid()
1385 for(int i = 0; i < D_MAX_RID; i++)
1386 if(pmt_eqv(d_rids[i].owner, PMT_NIL))
1392 REGISTER_MBLOCK_CLASS(usrp_server);