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