Imported Upstream version 3.2.2
[debian/gnuradio] / mblock / src / lib / qa_disconnect.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008 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 <mblock/mblock.h>
26 #include <mblock/protocol_class.h>
27 #include <mblock/message.h>
28 #include <mblock/class_registry.h>
29 #include <iostream>
30 #include <cstdio>
31 #include <sstream>
32 #include <bitset>
33
34 static pmt_t s_in = pmt_intern("in");
35 static pmt_t s_out = pmt_intern("out");
36 static pmt_t s_data = pmt_intern("data");
37 static pmt_t s_ack = pmt_intern("ack");
38 static pmt_t s_select_pipe = pmt_intern("select-pipe");
39 static pmt_t s_long0 = pmt_from_long(0);
40 static pmt_t s_sys_port = pmt_intern("%sys-port");
41 static pmt_t s_shutdown = pmt_intern("%shutdown");
42
43 class qa_disconnect_mux : public mb_mblock
44 {
45   mb_port_sptr  d_in;
46   mb_port_sptr  d_out;
47   mb_port_sptr  d_cs;
48
49 public:
50   qa_disconnect_mux(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
51   void initial_transition();
52   void handle_message(mb_message_sptr msg);
53 };
54
55 qa_disconnect_mux::qa_disconnect_mux(mb_runtime *runtime,
56                                      const std::string &instance_name,
57                                      pmt_t user_arg)
58   : mb_mblock(runtime, instance_name, user_arg)
59 {
60   d_in  = define_port("in", "qa-bitset", false, mb_port::RELAY);
61   d_out = define_port("out", "qa-bitset", true, mb_port::RELAY);
62   d_cs  = define_port("cs", "qa-disconnect-cs", true, mb_port::EXTERNAL);
63
64   define_component("pipeline0", "qa_bitset8", pmt_from_long(0));
65   define_component("pipeline1", "qa_bitset8", pmt_from_long(8));
66 }
67
68 void
69 qa_disconnect_mux::initial_transition(){}
70
71 void
72 qa_disconnect_mux::handle_message(mb_message_sptr msg)
73 {
74   if (pmt_eq(msg->port_id(), d_cs->port_symbol())       // select-pipe on cs
75       && pmt_eq(msg->signal(), s_select_pipe)){         
76
77     long which_pipe = pmt_to_long(pmt_nth(0, msg->data()));
78
79     disconnect_component("pipeline0");
80     disconnect_component("pipeline1");
81
82     switch(which_pipe){
83
84     case 0:
85       connect("self", "in",  "pipeline0", "in");
86       connect("self", "out", "pipeline0", "out");
87       break;
88
89     case 1:
90       connect("self", "in",  "pipeline1", "in");
91       connect("self", "out", "pipeline1", "out");
92       break;
93     }
94
95     d_cs->send(s_ack, msg->data());
96     return;
97   }
98 }
99
100 REGISTER_MBLOCK_CLASS(qa_disconnect_mux);
101
102 // ------------------------------------------------------------------------
103
104 class qa_disconnect_top : public mb_mblock
105 {
106   enum state_t {
107     UNINITIALIZED,
108     WAIT_FOR_ACK,
109     WAIT_FOR_DATA
110   };
111
112   state_t       d_state;
113   int           d_msg_number;
114   int           d_nmsgs_to_send;
115
116   mb_port_sptr  d_in;
117   mb_port_sptr  d_out;
118   mb_port_sptr  d_cs;
119
120   void check_pipe_send_next_msg();
121   void send_next_msg();
122   void select_pipe(int n);
123
124   // alternate pipes every 128 messages
125   static int  which_pipe(int msg_number) { return (msg_number >> 7) & 0x1; }
126   bool time_to_switch() { return (d_msg_number & 0x7f) == 0; }
127   
128 public:
129   qa_disconnect_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
130   void initial_transition();
131   void handle_message(mb_message_sptr msg);
132 };
133
134 qa_disconnect_top::qa_disconnect_top(mb_runtime *runtime,
135                                      const std::string &instance_name,
136                                      pmt_t user_arg)
137   : mb_mblock(runtime, instance_name, user_arg),
138     d_state(UNINITIALIZED), d_msg_number(0)
139 {
140   d_nmsgs_to_send = pmt_to_long(pmt_nth(0, user_arg));
141
142   d_in  = define_port("in", "qa-bitset", false, mb_port::INTERNAL);
143   d_out = define_port("out", "qa-bitset", true, mb_port::INTERNAL);
144   d_cs  = define_port("cs", "qa-disconnect-cs", false, mb_port::INTERNAL);
145
146   define_component("mux", "qa_disconnect_mux", PMT_F);
147
148   connect("self", "cs",  "mux", "cs");
149   connect("self", "out", "mux", "in");
150   connect("self", "in",  "mux", "out");
151 }
152
153 void
154 qa_disconnect_top::initial_transition()
155 {
156   check_pipe_send_next_msg();
157 }
158
159 void
160 qa_disconnect_top::handle_message(mb_message_sptr msg)
161 {
162   if (0)
163     std::cerr << "qa_disconnect_top::handle_msg state = "
164               << d_state << "\n  msg = " << msg << std::endl;
165
166   if (pmt_eq(msg->port_id(), d_cs->port_symbol())       // ack on cs
167       && pmt_eq(msg->signal(), s_ack)
168       && d_state == WAIT_FOR_ACK){
169
170     send_next_msg();
171     return;
172   }
173
174   if (pmt_eq(msg->port_id(), d_in->port_symbol())       // data on in
175       && pmt_eq(msg->signal(), s_data)
176       && d_state == WAIT_FOR_DATA){
177
178     /*  
179      * Confirm that msg passed through the pipe that we expect...
180      */
181     static const long expected_mask[2] = { 0x000000ff, 0x0000ff00 };
182
183     long msg_number = pmt_to_long(pmt_car(msg->data()));
184     long mask = pmt_to_long(pmt_cdr(msg->data()));
185
186     if (mask != expected_mask[which_pipe(msg_number)]){
187       fprintf(stderr, "\nqa_disconnect_top: wrong mask in msg_number = 0x%08lx\n",
188               msg_number);
189       fprintf(stderr, "  expected = 0x%08lx, actual = 0x%08lx\n",
190               expected_mask[which_pipe(msg_number)], mask);
191       shutdown_all(PMT_F);
192       return;
193     }
194
195     if (msg_number == d_nmsgs_to_send - 1){     // we're done (and were successful)
196       shutdown_all(PMT_T);
197       return;
198     }
199
200     check_pipe_send_next_msg();
201     return;
202   }
203
204   if (pmt_eq(msg->port_id(), s_sys_port)        // ignore %shutdown on %sys-port
205       && pmt_eq(msg->signal(), s_shutdown))
206     return;
207
208   std::cerr << "qa_disconnect_top: unhandled msg: state = "
209             << d_state << "\n  msg = " << msg << std::endl;
210 }
211
212 void
213 qa_disconnect_top::select_pipe(int n)
214 {
215   d_cs->send(s_select_pipe, pmt_list1(pmt_from_long(n)));
216   d_state = WAIT_FOR_ACK;
217 }
218
219 void
220 qa_disconnect_top::send_next_msg()
221 {
222   d_state = WAIT_FOR_DATA;
223   if (d_msg_number == d_nmsgs_to_send)  // we've sent all we're supposed to
224     return;
225
226   d_out->send(s_data, pmt_cons(pmt_from_long(d_msg_number), s_long0));
227   d_msg_number++;
228 }
229
230 void
231 qa_disconnect_top::check_pipe_send_next_msg()
232 {
233   if (time_to_switch())
234     select_pipe(which_pipe(d_msg_number));
235   else
236     send_next_msg();
237 }
238
239 REGISTER_MBLOCK_CLASS(qa_disconnect_top);