1 |
/* |
---|
2 |
* Copyright (C) 2005-2009 by Pieter Palmers |
---|
3 |
* |
---|
4 |
* This file is part of FFADO |
---|
5 |
* FFADO = Free Firewire (pro-)audio drivers for linux |
---|
6 |
* |
---|
7 |
* FFADO is based upon FreeBoB |
---|
8 |
* |
---|
9 |
* This program is free software: you can redistribute it and/or modify |
---|
10 |
* it under the terms of the GNU General Public License as published by |
---|
11 |
* the Free Software Foundation, either version 2 of the License, or |
---|
12 |
* (at your option) version 3 of the License. |
---|
13 |
* |
---|
14 |
* This program is distributed in the hope that it will be useful, |
---|
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
17 |
* GNU General Public License for more details. |
---|
18 |
* |
---|
19 |
* You should have received a copy of the GNU General Public License |
---|
20 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
21 |
* |
---|
22 |
*/ |
---|
23 |
|
---|
24 |
#include "dice_avdevice.h" |
---|
25 |
|
---|
26 |
#include "dice_eap.h" |
---|
27 |
#include "dice_defines.h" |
---|
28 |
|
---|
29 |
#include "libutil/SystemTimeSource.h" |
---|
30 |
#include "libutil/ByteSwap.h" |
---|
31 |
|
---|
32 |
#include <cstdio> |
---|
33 |
|
---|
34 |
namespace Dice { |
---|
35 |
|
---|
36 |
// ----------- helper functions ------------- |
---|
37 |
|
---|
38 |
#if 0 |
---|
39 |
static const char * |
---|
40 |
srcBlockToString(const char id) |
---|
41 |
{ |
---|
42 |
switch(id) { |
---|
43 |
case eRS_AES: return "AES "; |
---|
44 |
case eRS_ADAT: return "ADAT"; |
---|
45 |
case eRS_Mixer: return "MXR "; |
---|
46 |
case eRS_InS0: return "INS0"; |
---|
47 |
case eRS_InS1: return "INS1"; |
---|
48 |
case eRS_ARM: return "ARM "; |
---|
49 |
case eRS_ARX0: return "AVS0"; |
---|
50 |
case eRS_ARX1: return "AVS1"; |
---|
51 |
case eRS_Muted: return "MUTE"; |
---|
52 |
default : return "RSVD"; |
---|
53 |
} |
---|
54 |
} |
---|
55 |
|
---|
56 |
static const char * |
---|
57 |
dstBlockToString(const char id) |
---|
58 |
{ |
---|
59 |
switch(id) { |
---|
60 |
case eRD_AES: return "AES "; |
---|
61 |
case eRD_ADAT: return "ADAT"; |
---|
62 |
case eRD_Mixer0: return "MXR0"; |
---|
63 |
case eRD_Mixer1: return "MXR1"; |
---|
64 |
case eRD_InS0: return "INS0"; |
---|
65 |
case eRD_InS1: return "INS1"; |
---|
66 |
case eRD_ARM: return "ARM "; |
---|
67 |
case eRD_ATX0: return "AVS0"; |
---|
68 |
case eRD_ATX1: return "AVS1"; |
---|
69 |
case eRD_Muted: return "MUTE"; |
---|
70 |
default : return "RSVD"; |
---|
71 |
} |
---|
72 |
} |
---|
73 |
#endif |
---|
74 |
|
---|
75 |
IMPL_DEBUG_MODULE( EAP, EAP, DEBUG_LEVEL_NORMAL ); |
---|
76 |
|
---|
77 |
EAP::EAP(Device &d) |
---|
78 |
: Control::Container(&d, "EAP") |
---|
79 |
, m_device(d) |
---|
80 |
, m_mixer( NULL ) |
---|
81 |
, m_router( NULL ) |
---|
82 |
, m_current_cfg_routing_low ( RouterConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_LOW_ROUTER ) ) |
---|
83 |
, m_current_cfg_routing_mid ( RouterConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_MID_ROUTER ) ) |
---|
84 |
, m_current_cfg_routing_high( RouterConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_HIGH_ROUTER) ) |
---|
85 |
, m_current_cfg_stream_low ( StreamConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_LOW_STREAM ) ) |
---|
86 |
, m_current_cfg_stream_mid ( StreamConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_MID_STREAM ) ) |
---|
87 |
, m_current_cfg_stream_high ( StreamConfig(*this, eRT_CurrentCfg, DICE_EAP_CURRCFG_HIGH_STREAM) ) |
---|
88 |
{ |
---|
89 |
} |
---|
90 |
|
---|
91 |
EAP::~EAP() |
---|
92 |
{ |
---|
93 |
// remove all control elements registered to this device (w/o free) |
---|
94 |
clearElements(false); |
---|
95 |
|
---|
96 |
// delete the helper classes |
---|
97 |
if(m_mixer) delete m_mixer; |
---|
98 |
if(m_router) delete m_router; |
---|
99 |
} |
---|
100 |
|
---|
101 |
// offsets and sizes are returned in quadlets, but we use byte values, hence the *= 4 |
---|
102 |
#define DICE_EAP_READREG_AND_CHECK(base, addr, var) { \ |
---|
103 |
if(!readReg(base, addr, &var)) { \ |
---|
104 |
debugError("Could not initialize " #var "\n"); \ |
---|
105 |
return false; \ |
---|
106 |
} \ |
---|
107 |
var *= 4; \ |
---|
108 |
} |
---|
109 |
|
---|
110 |
bool |
---|
111 |
EAP::init() { |
---|
112 |
if(!supportsEAP(m_device)) { |
---|
113 |
debugWarning("no EAP mixer (device does not support EAP)\n"); |
---|
114 |
return false; |
---|
115 |
} |
---|
116 |
|
---|
117 |
// offsets and sizes are returned in quadlets, but we use byte values |
---|
118 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CAPABILITY_SPACE_OFF, m_capability_offset); |
---|
119 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CAPABILITY_SPACE_SZ, m_capability_size); |
---|
120 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CMD_SPACE_OFF, m_cmd_offset); |
---|
121 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CMD_SPACE_SZ, m_cmd_size); |
---|
122 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_MIXER_SPACE_OFF, m_mixer_offset); |
---|
123 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_MIXER_SPACE_SZ, m_mixer_size); |
---|
124 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_PEAK_SPACE_OFF, m_peak_offset); |
---|
125 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_PEAK_SPACE_SZ, m_peak_size); |
---|
126 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_ROUTING_SPACE_OFF, m_new_routing_offset); |
---|
127 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_ROUTING_SPACE_SZ, m_new_routing_size); |
---|
128 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_STREAM_CFG_SPACE_OFF, m_new_stream_cfg_offset); |
---|
129 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_NEW_STREAM_CFG_SPACE_SZ, m_new_stream_cfg_size); |
---|
130 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CURR_CFG_SPACE_OFF, m_curr_cfg_offset); |
---|
131 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_CURR_CFG_SPACE_SZ, m_curr_cfg_size); |
---|
132 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_STAND_ALONE_CFG_SPACE_OFF, m_standalone_offset); |
---|
133 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_STAND_ALONE_CFG_SPACE_SZ, m_standalone_size); |
---|
134 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_APP_SPACE_OFF, m_app_offset); |
---|
135 |
DICE_EAP_READREG_AND_CHECK(eRT_Base, DICE_EAP_APP_SPACE_SZ, m_app_size); |
---|
136 |
|
---|
137 |
// initialize the capability info |
---|
138 |
quadlet_t tmp; |
---|
139 |
if(!readReg(eRT_Capability, DICE_EAP_CAPABILITY_ROUTER, &tmp)) { |
---|
140 |
debugError("Could not read router capabilities\n"); |
---|
141 |
return false; |
---|
142 |
} |
---|
143 |
m_router_exposed = (tmp >> DICE_EAP_CAP_ROUTER_EXPOSED) & 0x01; |
---|
144 |
m_router_readonly = (tmp >> DICE_EAP_CAP_ROUTER_READONLY) & 0x01; |
---|
145 |
m_router_flashstored = (tmp >> DICE_EAP_CAP_ROUTER_FLASHSTORED) & 0x01; |
---|
146 |
m_router_nb_entries = (tmp >> DICE_EAP_CAP_ROUTER_MAXROUTES) & 0xFFFF; |
---|
147 |
|
---|
148 |
if(!readReg(eRT_Capability, DICE_EAP_CAPABILITY_MIXER, &tmp)) { |
---|
149 |
debugError("Could not read mixer capabilities\n"); |
---|
150 |
return false; |
---|
151 |
} |
---|
152 |
m_mixer_exposed = (tmp >> DICE_EAP_CAP_MIXER_EXPOSED) & 0x01; |
---|
153 |
m_mixer_readonly = (tmp >> DICE_EAP_CAP_MIXER_READONLY) & 0x01; |
---|
154 |
m_mixer_flashstored = (tmp >> DICE_EAP_CAP_MIXER_FLASHSTORED) & 0x01; |
---|
155 |
m_mixer_tx_id = (tmp >> DICE_EAP_CAP_MIXER_IN_DEV) & 0x000F; |
---|
156 |
m_mixer_rx_id = (tmp >> DICE_EAP_CAP_MIXER_OUT_DEV) & 0x000F; |
---|
157 |
m_mixer_nb_tx = (tmp >> DICE_EAP_CAP_MIXER_INPUTS) & 0x00FF; |
---|
158 |
m_mixer_nb_rx = (tmp >> DICE_EAP_CAP_MIXER_OUTPUTS) & 0x00FF; |
---|
159 |
|
---|
160 |
if(!readReg(eRT_Capability, DICE_EAP_CAPABILITY_GENERAL, &tmp)) { |
---|
161 |
debugError("Could not read general capabilities\n"); |
---|
162 |
return false; |
---|
163 |
} |
---|
164 |
m_general_support_dynstream = (tmp >> DICE_EAP_CAP_GENERAL_STRM_CFG_EN) & 0x01; |
---|
165 |
m_general_support_flash = (tmp >> DICE_EAP_CAP_GENERAL_FLASH_EN) & 0x01; |
---|
166 |
m_general_peak_enabled = (tmp >> DICE_EAP_CAP_GENERAL_PEAK_EN) & 0x01; |
---|
167 |
m_general_max_tx = (tmp >> DICE_EAP_CAP_GENERAL_MAX_TX_STREAM) & 0x0F; |
---|
168 |
m_general_max_rx = (tmp >> DICE_EAP_CAP_GENERAL_MAX_RX_STREAM) & 0x0F; |
---|
169 |
m_general_stream_cfg_stored = (tmp >> DICE_EAP_CAP_GENERAL_STRM_CFG_FLS) & 0x01; |
---|
170 |
m_general_chip = (tmp >> DICE_EAP_CAP_GENERAL_CHIP) & 0xFFFF; |
---|
171 |
|
---|
172 |
// update our view on the current configuration |
---|
173 |
if(!updateConfigurationCache()) { |
---|
174 |
debugError("Could not initialize configuration cache\n"); |
---|
175 |
return false; |
---|
176 |
} |
---|
177 |
|
---|
178 |
// initialize the helper classes |
---|
179 |
if (m_mixer_exposed) { |
---|
180 |
// initialize the mixer |
---|
181 |
m_mixer = new EAP::Mixer(*this); |
---|
182 |
if(m_mixer == NULL) { |
---|
183 |
debugError("Could not allocate memory for mixer\n"); |
---|
184 |
return false; |
---|
185 |
} |
---|
186 |
if(!m_mixer->init()) { |
---|
187 |
debugError("Could not initialize mixer\n"); |
---|
188 |
delete m_mixer; |
---|
189 |
m_mixer = NULL; |
---|
190 |
return false; |
---|
191 |
} |
---|
192 |
// add the mixer to the EAP control container |
---|
193 |
if(!addElement(m_mixer)) { |
---|
194 |
debugWarning("Failed to add mixer to control tree\n"); |
---|
195 |
} |
---|
196 |
|
---|
197 |
// initialize the peak meter |
---|
198 |
m_router = new EAP::Router(*this); |
---|
199 |
if(m_router == NULL) { |
---|
200 |
debugError("Could not allocate memory for router\n"); |
---|
201 |
return false; |
---|
202 |
} |
---|
203 |
m_router->update(); |
---|
204 |
|
---|
205 |
// add the router to the EAP control container |
---|
206 |
if(!addElement(m_router)) { |
---|
207 |
debugWarning("Failed to add router to control tree\n"); |
---|
208 |
} |
---|
209 |
} |
---|
210 |
|
---|
211 |
return true; |
---|
212 |
} |
---|
213 |
|
---|
214 |
|
---|
215 |
void |
---|
216 |
EAP::update() |
---|
217 |
{ |
---|
218 |
// update EAP from the last init |
---|
219 |
// update router sources and destinations |
---|
220 |
if (m_router) { |
---|
221 |
m_router->update(); |
---|
222 |
} |
---|
223 |
} |
---|
224 |
|
---|
225 |
void |
---|
226 |
EAP::setupSources() { |
---|
227 |
// define router sources (possibly depending on the samplerate) |
---|
228 |
switch(m_device.getCurrentConfig()) { |
---|
229 |
case Device::eDC_Low: setupSources_low(); return; |
---|
230 |
case Device::eDC_Mid: setupSources_mid(); return; |
---|
231 |
case Device::eDC_High: setupSources_high(); return; |
---|
232 |
default: |
---|
233 |
debugError("Unsupported configuration mode\n"); |
---|
234 |
return; |
---|
235 |
} |
---|
236 |
} |
---|
237 |
|
---|
238 |
void |
---|
239 |
EAP::setupSources_low() { |
---|
240 |
// add the routing sources for a DICE chip |
---|
241 |
switch(m_general_chip) { |
---|
242 |
case DICE_EAP_CAP_GENERAL_CHIP_DICEII: |
---|
243 |
// router/EAP currently not supported |
---|
244 |
break; |
---|
245 |
case DICE_EAP_CAP_GENERAL_CHIP_DICEJR: |
---|
246 |
// second audio port (unique to the junior) |
---|
247 |
addSource("InS1", 0, 8, eRS_InS1); |
---|
248 |
case DICE_EAP_CAP_GENERAL_CHIP_DICEMINI: |
---|
249 |
/// these are common to the mini and junior |
---|
250 |
// the AES receiver |
---|
251 |
addSource("AES", 0, 8, eRS_AES); |
---|
252 |
// the ADAT receiver |
---|
253 |
addSource("ADAT", 0, 8, eRS_ADAT); |
---|
254 |
// the Mixer outputs |
---|
255 |
addSource("MixerOut", 0, 16, eRS_Mixer); |
---|
256 |
// the first audio port |
---|
257 |
addSource("InS0", 0, 8, eRS_InS0); |
---|
258 |
// the ARM audio port |
---|
259 |
addSource("ARM", 0, 8, eRS_ARM); |
---|
260 |
// the 1394 stream receivers |
---|
261 |
addSource("1394_0", 0, 16, eRS_ARX0); |
---|
262 |
addSource("1394_1", 0, 16, eRS_ARX1); |
---|
263 |
// mute |
---|
264 |
addSource("Mute", 0, 1, eRS_Muted); |
---|
265 |
break; |
---|
266 |
default: |
---|
267 |
// this is an unsupported chip |
---|
268 |
break; |
---|
269 |
} |
---|
270 |
} |
---|
271 |
|
---|
272 |
void |
---|
273 |
EAP::setupSources_mid() { |
---|
274 |
setupSources_low(); |
---|
275 |
} |
---|
276 |
|
---|
277 |
void |
---|
278 |
EAP::setupSources_high() { |
---|
279 |
setupSources_low(); |
---|
280 |
} |
---|
281 |
|
---|
282 |
void |
---|
283 |
EAP::setupDestinations() { |
---|
284 |
switch(m_device.getCurrentConfig()) { |
---|
285 |
case Device::eDC_Low: setupDestinations_low(); return; |
---|
286 |
case Device::eDC_Mid: setupDestinations_mid(); return; |
---|
287 |
case Device::eDC_High: setupDestinations_high(); return; |
---|
288 |
default: |
---|
289 |
debugError("Unsupported configuration mode\n"); |
---|
290 |
return; |
---|
291 |
} |
---|
292 |
} |
---|
293 |
|
---|
294 |
void |
---|
295 |
EAP::setupDestinations_low() { |
---|
296 |
// add the routing destinations for a DICE chip |
---|
297 |
switch(m_general_chip) { |
---|
298 |
case DICE_EAP_CAP_GENERAL_CHIP_DICEII: |
---|
299 |
// router/EAP currently not supported |
---|
300 |
break; |
---|
301 |
case DICE_EAP_CAP_GENERAL_CHIP_DICEJR: |
---|
302 |
// second audio port (unique to the junior) |
---|
303 |
addDestination("InS1", 0, 8, eRD_InS1); |
---|
304 |
case DICE_EAP_CAP_GENERAL_CHIP_DICEMINI: |
---|
305 |
/// these are common to the mini and junior |
---|
306 |
// the AES receiver |
---|
307 |
addDestination("AES", 0, 8, eRD_AES); |
---|
308 |
// the ADAT receiver |
---|
309 |
addDestination("ADAT", 0, 8, eRD_ADAT); |
---|
310 |
// the Mixer outputs |
---|
311 |
addDestination("MixerIn", 0, 16, eRD_Mixer0); |
---|
312 |
addDestination("MixerIn", 0, 2, eRD_Mixer1, 16); |
---|
313 |
// the first audio port |
---|
314 |
addDestination("InS0", 0, 8, eRD_InS0); |
---|
315 |
// the ARM audio port |
---|
316 |
addDestination("ARM", 0, 8, eRD_ARM); |
---|
317 |
// the 1394 stream receivers |
---|
318 |
addDestination("1394_0", 0, 16, eRD_ATX0); |
---|
319 |
addDestination("1394_1", 0, 16, eRD_ATX1); |
---|
320 |
// mute |
---|
321 |
addDestination("Mute", 0, 1, eRD_Muted); |
---|
322 |
break; |
---|
323 |
default: |
---|
324 |
// this is an unsupported chip |
---|
325 |
break; |
---|
326 |
} |
---|
327 |
} |
---|
328 |
void |
---|
329 |
EAP::setupDestinations_mid() { |
---|
330 |
setupDestinations_low(); |
---|
331 |
} |
---|
332 |
void |
---|
333 |
EAP::setupDestinations_high() { |
---|
334 |
setupDestinations_low(); |
---|
335 |
} |
---|
336 |
|
---|
337 |
void |
---|
338 |
EAP::addSource(const std::string name, unsigned int base, unsigned int count, |
---|
339 |
enum eRouteSource srcid, unsigned int offset) |
---|
340 |
{ |
---|
341 |
m_router->addSource(name, srcid, base, count, offset); |
---|
342 |
} |
---|
343 |
void |
---|
344 |
EAP::addDestination(const std::string name, unsigned int base, unsigned int count, |
---|
345 |
enum eRouteDestination destid, unsigned int offset) |
---|
346 |
{ |
---|
347 |
m_router->addDestination(name, destid, base, count, offset); |
---|
348 |
} |
---|
349 |
|
---|
350 |
bool |
---|
351 |
EAP::updateConfigurationCache() |
---|
352 |
{ |
---|
353 |
if(!m_current_cfg_routing_low.read()) { |
---|
354 |
debugError("Could not initialize current routing configuration (low rates)\n"); |
---|
355 |
return false; |
---|
356 |
} |
---|
357 |
if(!m_current_cfg_routing_mid.read()) { |
---|
358 |
debugError("Could not initialize current routing configuration (mid rates)\n"); |
---|
359 |
return false; |
---|
360 |
} |
---|
361 |
if(!m_current_cfg_routing_high.read()) { |
---|
362 |
debugError("Could not initialize current routing configuration (high rates)\n"); |
---|
363 |
return false; |
---|
364 |
} |
---|
365 |
if(!m_current_cfg_stream_low.read()) { |
---|
366 |
debugError("Could not initialize current stream configuration (low rates)\n"); |
---|
367 |
return false; |
---|
368 |
} |
---|
369 |
if(!m_current_cfg_stream_mid.read()) { |
---|
370 |
debugError("Could not initialize current stream configuration (mid rates)\n"); |
---|
371 |
return false; |
---|
372 |
} |
---|
373 |
if(!m_current_cfg_stream_high.read()) { |
---|
374 |
debugError("Could not initialize current stream configuration (high rates)\n"); |
---|
375 |
return false; |
---|
376 |
} |
---|
377 |
if(m_mixer) m_mixer->updateNameCache(); |
---|
378 |
return true; |
---|
379 |
} |
---|
380 |
|
---|
381 |
/** |
---|
382 |
* Returns the router configuration for the current rate mode |
---|
383 |
*/ |
---|
384 |
EAP::RouterConfig * |
---|
385 |
EAP::getActiveRouterConfig() |
---|
386 |
{ |
---|
387 |
switch(m_device.getCurrentConfig()) { |
---|
388 |
case Device::eDC_Low: return &m_current_cfg_routing_low; |
---|
389 |
case Device::eDC_Mid: return &m_current_cfg_routing_mid; |
---|
390 |
case Device::eDC_High: return &m_current_cfg_routing_high; |
---|
391 |
default: |
---|
392 |
debugError("Unsupported configuration mode\n"); |
---|
393 |
return NULL; |
---|
394 |
} |
---|
395 |
} |
---|
396 |
|
---|
397 |
/** |
---|
398 |
* Returns the stream configuration for the current rate mode |
---|
399 |
*/ |
---|
400 |
EAP::StreamConfig * |
---|
401 |
EAP::getActiveStreamConfig() |
---|
402 |
{ |
---|
403 |
switch(m_device.getCurrentConfig()) { |
---|
404 |
case Device::eDC_Low: return &m_current_cfg_stream_low; |
---|
405 |
case Device::eDC_Mid: return &m_current_cfg_stream_mid; |
---|
406 |
case Device::eDC_High: return &m_current_cfg_stream_high; |
---|
407 |
default: |
---|
408 |
debugError("Unsupported configuration mode\n"); |
---|
409 |
return NULL; |
---|
410 |
} |
---|
411 |
} |
---|
412 |
|
---|
413 |
/** |
---|
414 |
* Uploads a new router configuration to the device |
---|
415 |
* @param rcfg The new RouterConfig |
---|
416 |
* @param low store as config for the low rates |
---|
417 |
* @param mid store as config for the mid rates |
---|
418 |
* @param high store as config for the high rates |
---|
419 |
* @return true if successful, false otherwise |
---|
420 |
*/ |
---|
421 |
bool |
---|
422 |
EAP::updateRouterConfig(RouterConfig& rcfg, bool low, bool mid, bool high) { |
---|
423 |
// write the router config to the appropriate memory space on the device |
---|
424 |
if(!rcfg.write(eRT_NewRouting, 0)) { |
---|
425 |
debugError("Could not write new router configuration\n"); |
---|
426 |
return false; |
---|
427 |
} |
---|
428 |
// perform the store operation |
---|
429 |
if(!loadRouterConfig(low, mid, high)) { |
---|
430 |
debugError("Could not activate new router configuration\n"); |
---|
431 |
updateConfigurationCache(); // for consistency |
---|
432 |
return false; |
---|
433 |
} |
---|
434 |
return updateConfigurationCache(); |
---|
435 |
} |
---|
436 |
|
---|
437 |
/** |
---|
438 |
* Uploads a new router configuration to replace the configuration |
---|
439 |
* for the current rate. |
---|
440 |
* @param rcfg The new RouterConfig |
---|
441 |
* @return true if successful, false otherwise |
---|
442 |
*/ |
---|
443 |
bool |
---|
444 |
EAP::updateCurrentRouterConfig(RouterConfig& rcfg) { |
---|
445 |
switch(m_device.getCurrentConfig()) { |
---|
446 |
case Device::eDC_Low: return updateRouterConfig(rcfg, true, false, false); |
---|
447 |
case Device::eDC_Mid: return updateRouterConfig(rcfg, false, true, false); |
---|
448 |
case Device::eDC_High: return updateRouterConfig(rcfg, false, false, true); |
---|
449 |
default: |
---|
450 |
debugError("Unsupported configuration mode\n"); |
---|
451 |
return false; |
---|
452 |
} |
---|
453 |
} |
---|
454 |
|
---|
455 |
/** |
---|
456 |
* Uploads a new stream configuration to the device |
---|
457 |
* @param scfg The new StreamConfig |
---|
458 |
* @param low store as config for the low rates |
---|
459 |
* @param mid store as config for the mid rates |
---|
460 |
* @param high store as config for the high rates |
---|
461 |
* @return true if successful, false otherwise |
---|
462 |
*/ |
---|
463 |
bool |
---|
464 |
EAP::updateStreamConfig(StreamConfig& scfg, bool low, bool mid, bool high) { |
---|
465 |
// write the stream config to the appropriate memory space on the device |
---|
466 |
if(!scfg.write(eRT_NewStreamCfg, 0)) { |
---|
467 |
debugError("Could not write new stream configuration\n"); |
---|
468 |
return false; |
---|
469 |
} |
---|
470 |
// perform the store operation |
---|
471 |
if(!loadStreamConfig(low, mid, high)) { |
---|
472 |
debugError("Could not activate new stream configuration\n"); |
---|
473 |
updateConfigurationCache(); // for consistency |
---|
474 |
return false; |
---|
475 |
} |
---|
476 |
return updateConfigurationCache(); |
---|
477 |
} |
---|
478 |
|
---|
479 |
/** |
---|
480 |
* Uploads a new router and stream configuration to the device |
---|
481 |
* @param rcfg The new RouterConfig |
---|
482 |
* @param scfg The new StreamConfig |
---|
483 |
* @param low store as config for the low rates |
---|
484 |
* @param mid store as config for the mid rates |
---|
485 |
* @param high store as config for the high rates |
---|
486 |
* @return true if successful, false otherwise |
---|
487 |
*/ |
---|
488 |
bool |
---|
489 |
EAP::updateStreamConfig(RouterConfig& rcfg, StreamConfig& scfg, bool low, bool mid, bool high) { |
---|
490 |
// write the router config to the appropriate memory space on the device |
---|
491 |
if(!rcfg.write(eRT_NewRouting, 0)) { |
---|
492 |
debugError("Could not write new router configuration\n"); |
---|
493 |
return false; |
---|
494 |
} |
---|
495 |
// write the stream config to the appropriate memory space on the device |
---|
496 |
if(!scfg.write(eRT_NewStreamCfg, 0)) { |
---|
497 |
debugError("Could not write new stream configuration\n"); |
---|
498 |
return false; |
---|
499 |
} |
---|
500 |
// perform the store operation |
---|
501 |
if(!loadRouterAndStreamConfig(low, mid, high)) { |
---|
502 |
debugError("Could not activate new router/stream configuration\n"); |
---|
503 |
updateConfigurationCache(); // for consistency |
---|
504 |
return false; |
---|
505 |
} |
---|
506 |
return updateConfigurationCache(); |
---|
507 |
} |
---|
508 |
|
---|
509 |
|
---|
510 |
bool |
---|
511 |
EAP::loadFlashConfig() { |
---|
512 |
bool retval = true; |
---|
513 |
debugWarning("Untested code\n"); |
---|
514 |
fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_FLASH_CFG; |
---|
515 |
cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE; |
---|
516 |
if(!commandHelper(cmd)) { |
---|
517 |
debugWarning("Command failed\n"); |
---|
518 |
retval = false; |
---|
519 |
} |
---|
520 |
retval &= updateConfigurationCache(); |
---|
521 |
return retval; |
---|
522 |
} |
---|
523 |
|
---|
524 |
bool |
---|
525 |
EAP::storeFlashConfig() { |
---|
526 |
//debugWarning("Untested code\n") // Works. -Arnold; |
---|
527 |
fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_ST_FLASH_CFG; |
---|
528 |
cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE; |
---|
529 |
return commandHelper(cmd); |
---|
530 |
} |
---|
531 |
|
---|
532 |
// helpers |
---|
533 |
void |
---|
534 |
EAP::show() |
---|
535 |
{ |
---|
536 |
printMessage("== DICE EAP ==\n"); |
---|
537 |
printMessage("Parameter Space info:\n"); |
---|
538 |
printMessage(" Capability : offset=%04X size=%06d\n", m_capability_offset, m_capability_size); |
---|
539 |
printMessage(" Command : offset=%04X size=%06d\n", m_cmd_offset, m_cmd_size); |
---|
540 |
printMessage(" Mixer : offset=%04X size=%06d\n", m_mixer_offset, m_mixer_size); |
---|
541 |
printMessage(" Peak : offset=%04X size=%06d\n", m_peak_offset, m_peak_size); |
---|
542 |
printMessage(" New Routing Cfg : offset=%04X size=%06d\n", m_new_routing_offset, m_new_routing_size); |
---|
543 |
printMessage(" New Stream Cfg : offset=%04X size=%06d\n", m_new_stream_cfg_offset, m_new_stream_cfg_size); |
---|
544 |
printMessage(" Current Cfg : offset=%04X size=%06d\n", m_curr_cfg_offset, m_curr_cfg_size); |
---|
545 |
printMessage(" Standalone Cfg : offset=%04X size=%06d\n", m_standalone_offset, m_standalone_size); |
---|
546 |
printMessage(" Application Space : offset=%04X size=%06d\n", m_app_offset, m_app_size); |
---|
547 |
|
---|
548 |
printMessage("Capabilities:\n"); |
---|
549 |
printMessage(" Router: %sexposed, %swritable, %sstored, %d routes\n", |
---|
550 |
(m_router_exposed?"":"not "), |
---|
551 |
(m_router_readonly?"not ":""), |
---|
552 |
(m_router_flashstored?"":"not "), |
---|
553 |
m_router_nb_entries); |
---|
554 |
printMessage(" Mixer : %sexposed, %swritable, %sstored\n", |
---|
555 |
(m_mixer_exposed?"":"not "), |
---|
556 |
(m_mixer_readonly?"not ":""), |
---|
557 |
(m_mixer_flashstored?"":"not ")); |
---|
558 |
printMessage(" tx id: (%d==eRD_Mixer0) ? %s, rx id: (%d==eRS_Mixer) ? %s\n", |
---|
559 |
m_mixer_tx_id, (m_mixer_tx_id == eRD_Mixer0)?"true":"false", |
---|
560 |
m_mixer_rx_id, (m_mixer_rx_id == eRS_Mixer) ?"true":"false"); |
---|
561 |
printMessage(" nb tx channels: %d, nb rx channels: %d\n", m_mixer_nb_tx, m_mixer_nb_rx); |
---|
562 |
printMessage(" General: dynamic stream config %ssupported\n", |
---|
563 |
(m_general_support_dynstream?"":"not ")); |
---|
564 |
printMessage(" flash load and store %ssupported\n", |
---|
565 |
(m_general_support_flash?"":"not ")); |
---|
566 |
printMessage(" peak metering %s\n", |
---|
567 |
(m_general_peak_enabled?"enabled":"disabled")); |
---|
568 |
printMessage(" stream config %sstored\n", |
---|
569 |
(m_general_stream_cfg_stored?"":"not ")); |
---|
570 |
printMessage(" max TX streams: %d, max RX streams: %d\n", |
---|
571 |
m_general_max_tx, m_general_max_rx); |
---|
572 |
|
---|
573 |
if(m_general_chip == DICE_EAP_CAP_GENERAL_CHIP_DICEII) { |
---|
574 |
printMessage(" Chip: DICE-II\n"); |
---|
575 |
} else if(m_general_chip == DICE_EAP_CAP_GENERAL_CHIP_DICEMINI) { |
---|
576 |
printMessage(" Chip: DICE Mini (TCD2210)\n"); |
---|
577 |
} else if(m_general_chip == DICE_EAP_CAP_GENERAL_CHIP_DICEJR) { |
---|
578 |
printMessage(" Chip: DICE Junior (TCD2220)\n"); |
---|
579 |
} |
---|
580 |
|
---|
581 |
printMessage("--- Mixer configuration ---\n"); |
---|
582 |
if(m_mixer) { |
---|
583 |
m_mixer->show(); |
---|
584 |
} |
---|
585 |
printMessage("--- Router/Peak space ---\n"); |
---|
586 |
if(m_router) { |
---|
587 |
m_router->show(); |
---|
588 |
} |
---|
589 |
|
---|
590 |
printMessage("--- Active Router ---\n"); |
---|
591 |
RouterConfig *rcfg = getActiveRouterConfig(); |
---|
592 |
if(rcfg) { |
---|
593 |
rcfg->show(); |
---|
594 |
} |
---|
595 |
printMessage("--- Active Stream ---\n"); |
---|
596 |
StreamConfig *scfg = getActiveStreamConfig(); |
---|
597 |
if(scfg) { |
---|
598 |
scfg->show(); |
---|
599 |
} |
---|
600 |
|
---|
601 |
// fixme |
---|
602 |
// size_t len = 0x1000; |
---|
603 |
// quadlet_t tmp[len]; |
---|
604 |
// if(!readRegBlock( eRT_CurrentCfg, DICE_EAP_CURRCFG_LOW_STREAM, tmp, len*4) ) { |
---|
605 |
// debugError("Failed to read block\n"); |
---|
606 |
// } else { |
---|
607 |
// hexDumpQuadlets(tmp, len); |
---|
608 |
// } |
---|
609 |
|
---|
610 |
} |
---|
611 |
void |
---|
612 |
EAP::showApplication() |
---|
613 |
{ |
---|
614 |
printMessage("--- Application space ---\n"); |
---|
615 |
fb_quadlet_t* tmp = (fb_quadlet_t *)calloc(128, sizeof(fb_quadlet_t)); |
---|
616 |
unsigned int appsize = m_app_size; /// m_app_size is rather big. Start with the first four block of 128 quadlets... |
---|
617 |
unsigned int offset = 0; |
---|
618 |
while ( appsize > 0 ) { |
---|
619 |
if ( ! readRegBlock( eRT_Application, offset, tmp, ((appsize<128)?appsize:128)*sizeof(fb_quadlet_t) ) ) |
---|
620 |
appsize = 0; |
---|
621 |
else { |
---|
622 |
hexDumpQuadlets(tmp, 128); |
---|
623 |
offset += 128*sizeof(fb_quadlet_t); |
---|
624 |
appsize -= 128*sizeof(fb_quadlet_t); |
---|
625 |
} |
---|
626 |
} |
---|
627 |
} |
---|
628 |
|
---|
629 |
// EAP load/store operations |
---|
630 |
|
---|
631 |
enum EAP::eWaitReturn |
---|
632 |
EAP::operationBusy() { |
---|
633 |
fb_quadlet_t tmp; |
---|
634 |
if(!readReg(eRT_Command, DICE_EAP_COMMAND_OPCODE, &tmp)) { |
---|
635 |
debugError("Could not read opcode register\n"); |
---|
636 |
return eWR_Error; |
---|
637 |
} |
---|
638 |
if( (tmp & DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE) == DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE) { |
---|
639 |
return eWR_Busy; |
---|
640 |
} else { |
---|
641 |
return eWR_Done; |
---|
642 |
} |
---|
643 |
} |
---|
644 |
|
---|
645 |
enum EAP::eWaitReturn |
---|
646 |
EAP::waitForOperationEnd(int max_wait_time_ms) { |
---|
647 |
int max_waits = max_wait_time_ms; |
---|
648 |
|
---|
649 |
while(max_waits--) { |
---|
650 |
enum eWaitReturn retval = operationBusy(); |
---|
651 |
switch(retval) { |
---|
652 |
case eWR_Busy: |
---|
653 |
break; // not done yet, keep waiting |
---|
654 |
case eWR_Done: |
---|
655 |
return eWR_Done; |
---|
656 |
case eWR_Error: |
---|
657 |
case eWR_Timeout: |
---|
658 |
debugError("Error while waiting for operation to end. (%d)\n", retval); |
---|
659 |
} |
---|
660 |
Util::SystemTimeSource::SleepUsecRelative(1000); |
---|
661 |
} |
---|
662 |
return eWR_Timeout; |
---|
663 |
} |
---|
664 |
|
---|
665 |
bool |
---|
666 |
EAP::commandHelper(fb_quadlet_t cmd) { |
---|
667 |
// check whether another command is still running |
---|
668 |
if(operationBusy() == eWR_Busy) { |
---|
669 |
debugError("Other operation in progress\n"); |
---|
670 |
return false; |
---|
671 |
} |
---|
672 |
|
---|
673 |
// execute the command |
---|
674 |
if(!writeReg(eRT_Command, DICE_EAP_COMMAND_OPCODE, cmd)) { |
---|
675 |
debugError("Could not write opcode register\n"); |
---|
676 |
return false; |
---|
677 |
} |
---|
678 |
|
---|
679 |
// wait for the operation to end |
---|
680 |
enum eWaitReturn retval = waitForOperationEnd(); |
---|
681 |
switch(retval) { |
---|
682 |
case eWR_Done: |
---|
683 |
break; // do nothing |
---|
684 |
case eWR_Timeout: |
---|
685 |
debugWarning("Time-out while waiting for operation to end. (%d)\n", retval); |
---|
686 |
return false; |
---|
687 |
case eWR_Error: |
---|
688 |
case eWR_Busy: // can't be returned |
---|
689 |
debugError("Error while waiting for operation to end. (%d)\n", retval); |
---|
690 |
return false; |
---|
691 |
} |
---|
692 |
|
---|
693 |
// check the return value |
---|
694 |
if(!readReg(eRT_Command, DICE_EAP_COMMAND_RETVAL, &cmd)) { |
---|
695 |
debugError("Could not read return value register\n"); |
---|
696 |
return false; |
---|
697 |
} |
---|
698 |
if(cmd != 0) { |
---|
699 |
debugWarning("Command failed\n"); |
---|
700 |
return false; |
---|
701 |
} else { |
---|
702 |
debugOutput(DEBUG_LEVEL_VERBOSE, "Command successful\n"); |
---|
703 |
return true; |
---|
704 |
} |
---|
705 |
} |
---|
706 |
|
---|
707 |
bool |
---|
708 |
EAP::loadRouterConfig(bool low, bool mid, bool high) { |
---|
709 |
fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_ROUTER; |
---|
710 |
if(low) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_LOW; |
---|
711 |
if(mid) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_MID; |
---|
712 |
if(high) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_HIGH; |
---|
713 |
cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE; |
---|
714 |
return commandHelper(cmd); |
---|
715 |
} |
---|
716 |
|
---|
717 |
bool |
---|
718 |
EAP::loadStreamConfig(bool low, bool mid, bool high) { |
---|
719 |
debugWarning("Untested code\n"); |
---|
720 |
fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_STRM_CFG; |
---|
721 |
if(low) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_LOW; |
---|
722 |
if(mid) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_MID; |
---|
723 |
if(high) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_HIGH; |
---|
724 |
cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE; |
---|
725 |
return commandHelper(cmd); |
---|
726 |
} |
---|
727 |
|
---|
728 |
bool |
---|
729 |
EAP::loadRouterAndStreamConfig(bool low, bool mid, bool high) { |
---|
730 |
debugWarning("Untested code\n"); |
---|
731 |
fb_quadlet_t cmd = DICE_EAP_CMD_OPCODE_LD_RTR_STRM_CFG; |
---|
732 |
if(low) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_LOW; |
---|
733 |
if(mid) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_MID; |
---|
734 |
if(high) cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_HIGH; |
---|
735 |
cmd |= DICE_EAP_CMD_OPCODE_FLAG_LD_EXECUTE; |
---|
736 |
return commandHelper(cmd); |
---|
737 |
} |
---|
738 |
|
---|
739 |
/* |
---|
740 |
I/O operations |
---|
741 |
*/ |
---|
742 |
bool |
---|
743 |
EAP::readReg(enum eRegBase base, unsigned offset, fb_quadlet_t *result) { |
---|
744 |
fb_nodeaddr_t addr = offsetGen(base, offset, 4); |
---|
745 |
return m_device.readReg(addr, result); |
---|
746 |
} |
---|
747 |
|
---|
748 |
bool |
---|
749 |
EAP::writeReg(enum eRegBase base, unsigned offset, fb_quadlet_t data) { |
---|
750 |
fb_nodeaddr_t addr = offsetGen(base, offset, 4); |
---|
751 |
return m_device.writeReg(addr, data); |
---|
752 |
} |
---|
753 |
|
---|
754 |
bool |
---|
755 |
EAP::readRegBlock(enum eRegBase base, unsigned offset, fb_quadlet_t *data, size_t length) { |
---|
756 |
fb_nodeaddr_t addr = offsetGen(base, offset, length); |
---|
757 |
return m_device.readRegBlock(addr, data, length); |
---|
758 |
} |
---|
759 |
|
---|
760 |
bool |
---|
761 |
EAP::writeRegBlock(enum eRegBase base, unsigned offset, fb_quadlet_t *data, size_t length) { |
---|
762 |
fb_nodeaddr_t addr = offsetGen(base, offset, length); |
---|
763 |
return m_device.writeRegBlock(addr, data, length); |
---|
764 |
} |
---|
765 |
|
---|
766 |
fb_nodeaddr_t |
---|
767 |
EAP::offsetGen(enum eRegBase base, unsigned offset, size_t length) { |
---|
768 |
fb_nodeaddr_t addr; |
---|
769 |
fb_nodeaddr_t maxlen; |
---|
770 |
switch(base) { |
---|
771 |
case eRT_Base: |
---|
772 |
addr = 0; |
---|
773 |
maxlen = DICE_EAP_MAX_SIZE; |
---|
774 |
break; |
---|
775 |
case eRT_Capability: |
---|
776 |
addr = m_capability_offset; |
---|
777 |
maxlen = m_capability_size; |
---|
778 |
break; |
---|
779 |
case eRT_Command: |
---|
780 |
addr = m_cmd_offset; |
---|
781 |
maxlen = m_cmd_size; |
---|
782 |
break; |
---|
783 |
case eRT_Mixer: |
---|
784 |
addr = m_mixer_offset; |
---|
785 |
maxlen = m_mixer_size; |
---|
786 |
break; |
---|
787 |
case eRT_Peak: |
---|
788 |
addr = m_peak_offset; |
---|
789 |
maxlen = m_peak_size; |
---|
790 |
break; |
---|
791 |
case eRT_NewRouting: |
---|
792 |
addr = m_new_routing_offset; |
---|
793 |
maxlen = m_new_routing_size; |
---|
794 |
break; |
---|
795 |
case eRT_NewStreamCfg: |
---|
796 |
addr = m_new_stream_cfg_offset; |
---|
797 |
maxlen = m_new_stream_cfg_size; |
---|
798 |
break; |
---|
799 |
case eRT_CurrentCfg: |
---|
800 |
addr = m_curr_cfg_offset; |
---|
801 |
maxlen = m_curr_cfg_size; |
---|
802 |
break; |
---|
803 |
case eRT_Standalone: |
---|
804 |
addr = m_standalone_offset; |
---|
805 |
maxlen = m_standalone_size; |
---|
806 |
break; |
---|
807 |
case eRT_Application: |
---|
808 |
addr = m_app_offset; |
---|
809 |
maxlen = m_app_size; |
---|
810 |
break; |
---|
811 |
default: |
---|
812 |
debugError("Unsupported base address\n"); |
---|
813 |
return 0; |
---|
814 |
}; |
---|
815 |
|
---|
816 |
// out-of-range check |
---|
817 |
if(length > maxlen) { |
---|
818 |
debugError("requested length too large: %zd > %"PRIu64"\n", length, maxlen); |
---|
819 |
return DICE_INVALID_OFFSET; |
---|
820 |
} |
---|
821 |
return DICE_EAP_BASE + addr + offset; |
---|
822 |
} |
---|
823 |
|
---|
824 |
/** |
---|
825 |
* Check whether a device supports eap |
---|
826 |
* @param d the device to check |
---|
827 |
* @return true if the device supports EAP |
---|
828 |
*/ |
---|
829 |
bool |
---|
830 |
EAP::supportsEAP(Device &d) |
---|
831 |
{ |
---|
832 |
DebugModule &m_debugModule = d.m_debugModule; |
---|
833 |
quadlet_t tmp; |
---|
834 |
if(!d.readReg(DICE_EAP_BASE, &tmp)) { |
---|
835 |
debugOutput(DEBUG_LEVEL_VERBOSE, "Could not read from DICE EAP base address\n"); |
---|
836 |
return false; |
---|
837 |
} |
---|
838 |
if(!d.readReg(DICE_EAP_BASE + DICE_EAP_ZERO_MARKER_1, &tmp)) { |
---|
839 |
debugOutput(DEBUG_LEVEL_VERBOSE, "Could not read from DICE EAP zero marker\n"); |
---|
840 |
return false; |
---|
841 |
} |
---|
842 |
if(tmp != 0) { |
---|
843 |
debugOutput(DEBUG_LEVEL_VERBOSE, "DICE EAP zero marker not zero\n"); |
---|
844 |
return false; |
---|
845 |
} |
---|
846 |
return true; |
---|
847 |
} |
---|
848 |
|
---|
849 |
// -------------------------------- Mixer ---------------------------------- |
---|
850 |
// Dice matrix-mixer is a one-dimensional array with inputs index varying |
---|
851 |
// first |
---|
852 |
// |
---|
853 |
// "ffado convention" is that inputs are rows and outputs are columns |
---|
854 |
// |
---|
855 |
EAP::Mixer::Mixer(EAP &p) |
---|
856 |
: Control::MatrixMixer(&p.m_device, "MatrixMixer") |
---|
857 |
, m_eap(p) |
---|
858 |
, m_coeff(NULL) |
---|
859 |
, m_debugModule(p.m_debugModule) |
---|
860 |
{ |
---|
861 |
} |
---|
862 |
|
---|
863 |
EAP::Mixer::~Mixer() |
---|
864 |
{ |
---|
865 |
if (m_coeff) { |
---|
866 |
free(m_coeff); |
---|
867 |
m_coeff = NULL; |
---|
868 |
} |
---|
869 |
} |
---|
870 |
|
---|
871 |
bool |
---|
872 |
EAP::Mixer::init() |
---|
873 |
{ |
---|
874 |
if(!m_eap.m_mixer_exposed) { |
---|
875 |
debugError("Device does not expose mixer\n"); |
---|
876 |
return false; |
---|
877 |
} |
---|
878 |
|
---|
879 |
// remove previous coefficient array |
---|
880 |
if(m_coeff) { |
---|
881 |
free(m_coeff); |
---|
882 |
m_coeff = NULL; |
---|
883 |
} |
---|
884 |
|
---|
885 |
// allocate coefficient array |
---|
886 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
887 |
int nb_outputs = m_eap.m_mixer_nb_rx; |
---|
888 |
|
---|
889 |
m_coeff = (fb_quadlet_t *)calloc(nb_outputs * nb_inputs, sizeof(fb_quadlet_t)); |
---|
890 |
|
---|
891 |
// load initial values |
---|
892 |
if(!loadCoefficients()) { |
---|
893 |
debugWarning("Could not initialize coefficients\n"); |
---|
894 |
return false; |
---|
895 |
} |
---|
896 |
updateNameCache(); |
---|
897 |
return true; |
---|
898 |
} |
---|
899 |
|
---|
900 |
bool |
---|
901 |
EAP::Mixer::loadCoefficients() |
---|
902 |
{ |
---|
903 |
if(m_coeff == NULL) { |
---|
904 |
debugError("Coefficient cache not initialized\n"); |
---|
905 |
return false; |
---|
906 |
} |
---|
907 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
908 |
int nb_outputs = m_eap.m_mixer_nb_rx; |
---|
909 |
if(!m_eap.readRegBlock(eRT_Mixer, 4, m_coeff, nb_inputs * nb_outputs * 4)) { |
---|
910 |
debugError("Failed to read coefficients\n"); |
---|
911 |
return false; |
---|
912 |
} |
---|
913 |
return true; |
---|
914 |
} |
---|
915 |
|
---|
916 |
bool |
---|
917 |
EAP::Mixer::storeCoefficients() |
---|
918 |
{ |
---|
919 |
if(m_coeff == NULL) { |
---|
920 |
debugError("Coefficient cache not initialized\n"); |
---|
921 |
return false; |
---|
922 |
} |
---|
923 |
if(m_eap.m_mixer_readonly) { |
---|
924 |
debugWarning("Mixer is read-only\n"); |
---|
925 |
return false; |
---|
926 |
} |
---|
927 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
928 |
int nb_outputs = m_eap.m_mixer_nb_rx; |
---|
929 |
if(!m_eap.writeRegBlock(eRT_Mixer, 4, m_coeff, nb_inputs * nb_outputs * 4)) { |
---|
930 |
debugError("Failed to read coefficients\n"); |
---|
931 |
return false; |
---|
932 |
} |
---|
933 |
return true; |
---|
934 |
} |
---|
935 |
|
---|
936 |
void |
---|
937 |
EAP::Mixer::updateNameCache() |
---|
938 |
{ |
---|
939 |
debugWarning("What is this function about?\n"); |
---|
940 |
#if 0 |
---|
941 |
// figure out the number of i/o's |
---|
942 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
943 |
int nb_outputs = m_eap.m_mixer_nb_rx; |
---|
944 |
|
---|
945 |
// clear the previous map |
---|
946 |
m_input_route_map.clear(); |
---|
947 |
m_output_route_map.clear(); |
---|
948 |
|
---|
949 |
// find the active router configuration |
---|
950 |
RouterConfig * rcfg = m_eap.getActiveRouterConfig(); |
---|
951 |
if(rcfg == NULL) { |
---|
952 |
debugError("Could not get active routing info\n"); |
---|
953 |
return; |
---|
954 |
} |
---|
955 |
|
---|
956 |
// find the inputs |
---|
957 |
for(int i=0; i < nb_inputs; i++) { |
---|
958 |
int ch = i; |
---|
959 |
// the destination id of the mixer input |
---|
960 |
int dest_int = m_eap.m_mixer_tx_id; |
---|
961 |
|
---|
962 |
// from the DICE mixer spec: |
---|
963 |
// we can have 16 channels per "block" |
---|
964 |
// if there are more, consecutive block id's are assumed |
---|
965 |
while(ch > 15) { |
---|
966 |
ch -= 16; |
---|
967 |
dest_int += 1; |
---|
968 |
} |
---|
969 |
// the destination block and channel corresponding with this |
---|
970 |
// mixer input is now known |
---|
971 |
enum eRouteDestination dest = rcfg->intToRouteDestination(dest_int); |
---|
972 |
|
---|
973 |
// get the source for this mixer channel |
---|
974 |
m_input_route_map[i] = rcfg->getRouteForDestination(dest, ch); |
---|
975 |
|
---|
976 |
debugOutput(DEBUG_LEVEL_VERBOSE, "Mixer input channel %2d source: %s (%d)\n", i, |
---|
977 |
srcBlockToString(m_input_route_map[i].src), |
---|
978 |
m_input_route_map[i].srcChannel); |
---|
979 |
} |
---|
980 |
|
---|
981 |
// find where the outputs are connected to |
---|
982 |
for(int i=0; i < nb_outputs; i++) { |
---|
983 |
int ch = i; |
---|
984 |
// the source id of the mixer input |
---|
985 |
int src_int = m_eap.m_mixer_rx_id; |
---|
986 |
|
---|
987 |
// from the DICE mixer spec: |
---|
988 |
// we can have 16 channels per "block" |
---|
989 |
// if there are more, consecutive block id's are assumed |
---|
990 |
while(ch > 15) { |
---|
991 |
ch -= 16; |
---|
992 |
src_int += 1; |
---|
993 |
} |
---|
994 |
|
---|
995 |
// the source block and channel corresponding with this |
---|
996 |
// mixer output is now known |
---|
997 |
enum eRouteSource src = rcfg->intToRouteSource(src_int); |
---|
998 |
|
---|
999 |
// get the routing destinations for this mixer channel |
---|
1000 |
m_output_route_map[i] = rcfg->getRoutesForSource(src, ch); |
---|
1001 |
|
---|
1002 |
#ifdef DEBUG |
---|
1003 |
std::string destinations; |
---|
1004 |
for ( RouterConfig::RouteVectorIterator it = m_output_route_map[i].begin(); |
---|
1005 |
it != m_output_route_map[i].end(); |
---|
1006 |
++it ) |
---|
1007 |
{ |
---|
1008 |
RouterConfig::Route r = *it; |
---|
1009 |
// check whether the destination is valid |
---|
1010 |
if((r.dst != eRD_Invalid) && (r.dstChannel >= 0)) { |
---|
1011 |
char tmp[128]; |
---|
1012 |
snprintf(tmp, 128, "%s:%d,", dstBlockToString(r.dst), r.dstChannel); |
---|
1013 |
destinations += tmp; |
---|
1014 |
} |
---|
1015 |
} |
---|
1016 |
debugOutput(DEBUG_LEVEL_VERBOSE, "Mixer output channel %2d destinations: %s\n", i, destinations.c_str()); |
---|
1017 |
#endif |
---|
1018 |
} |
---|
1019 |
#endif |
---|
1020 |
} |
---|
1021 |
|
---|
1022 |
void |
---|
1023 |
EAP::Mixer::show() |
---|
1024 |
{ |
---|
1025 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
1026 |
int nb_outputs = m_eap.m_mixer_nb_rx; |
---|
1027 |
|
---|
1028 |
updateNameCache(); |
---|
1029 |
|
---|
1030 |
const size_t bufflen = 4096; |
---|
1031 |
char tmp[bufflen]; |
---|
1032 |
int cnt; |
---|
1033 |
|
---|
1034 |
// |
---|
1035 |
// Caution the user that, displaying as further, because inputs index varies first |
---|
1036 |
// inputs will appears as columns at the opposite of the "ffado convention" |
---|
1037 |
printMessage(" -- inputs index -->>\n"); |
---|
1038 |
cnt = 0; |
---|
1039 |
for(int j=0; j < nb_inputs; j++) { |
---|
1040 |
cnt += snprintf(tmp+cnt, bufflen-cnt, " %02d ", j); |
---|
1041 |
} |
---|
1042 |
printMessage("%s\n", tmp); |
---|
1043 |
|
---|
1044 |
cnt = 0; |
---|
1045 |
for(int j=0; j < nb_inputs; j++) { |
---|
1046 |
cnt += snprintf(tmp+cnt, bufflen-cnt, "%s ", getRowName(j).data()); |
---|
1047 |
} |
---|
1048 |
printMessage("%s\n", tmp); |
---|
1049 |
|
---|
1050 |
// display coefficients |
---|
1051 |
for(int i=0; i < nb_outputs; i++) { |
---|
1052 |
cnt = 0; |
---|
1053 |
for(int j=0; j < nb_inputs; j++) { |
---|
1054 |
cnt += snprintf(tmp+cnt, bufflen-cnt, "%07d ", *(m_coeff + nb_inputs * i + j)); |
---|
1055 |
} |
---|
1056 |
|
---|
1057 |
// Display destinations name |
---|
1058 |
cnt += snprintf(tmp+cnt, bufflen-cnt, "=[%02d]=> %s", i, getColName(i).data()); |
---|
1059 |
printMessage("%s\n", tmp); |
---|
1060 |
} |
---|
1061 |
|
---|
1062 |
} |
---|
1063 |
|
---|
1064 |
int |
---|
1065 |
EAP::Mixer::canWrite( const int row, const int col) |
---|
1066 |
{ |
---|
1067 |
if(m_eap.m_mixer_readonly) { |
---|
1068 |
return false; |
---|
1069 |
} |
---|
1070 |
return (row >= 0 && row < m_eap.m_mixer_nb_tx && col >= 0 && col < m_eap.m_mixer_nb_rx); |
---|
1071 |
} |
---|
1072 |
|
---|
1073 |
double |
---|
1074 |
EAP::Mixer::setValue( const int row, const int col, const double val) |
---|
1075 |
{ |
---|
1076 |
if(m_eap.m_mixer_readonly) { |
---|
1077 |
debugWarning("Mixer is read-only\n"); |
---|
1078 |
return false; |
---|
1079 |
} |
---|
1080 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
1081 |
int addr = ((nb_inputs * col) + row) * 4; |
---|
1082 |
quadlet_t tmp = (quadlet_t) val; |
---|
1083 |
if(!m_eap.writeRegBlock(eRT_Mixer, 4+addr, &tmp, 4)) { |
---|
1084 |
debugError("Failed to write coefficient\n"); |
---|
1085 |
return 0; |
---|
1086 |
} |
---|
1087 |
return (double)(tmp); |
---|
1088 |
} |
---|
1089 |
|
---|
1090 |
double |
---|
1091 |
EAP::Mixer::getValue( const int row, const int col) |
---|
1092 |
{ |
---|
1093 |
int nb_inputs = m_eap.m_mixer_nb_tx; |
---|
1094 |
int addr = ((nb_inputs * col) + row) * 4; |
---|
1095 |
quadlet_t tmp; |
---|
1096 |
if(!m_eap.readRegBlock(eRT_Mixer, 4+addr, &tmp, 4)) { |
---|
1097 |
debugError("Failed to read coefficient\n"); |
---|
1098 |
return 0; |
---|
1099 |
} |
---|
1100 |
return (double)(tmp); |
---|
1101 |
} |
---|
1102 |
|
---|
1103 |
int |
---|
1104 |
EAP::Mixer::getRowCount() |
---|
1105 |
{ |
---|
1106 |
return m_eap.m_mixer_nb_tx; |
---|
1107 |
} |
---|
1108 |
|
---|
1109 |
int |
---|
1110 |
EAP::Mixer::getColCount() |
---|
1111 |
{ |
---|
1112 |
return m_eap.m_mixer_nb_rx; |
---|
1113 |
} |
---|
1114 |
|
---|
1115 |
// full map updates are unsupported |
---|
1116 |
bool |
---|
1117 |
EAP::Mixer::getCoefficientMap(int &) { |
---|
1118 |
return false; |
---|
1119 |
} |
---|
1120 |
|
---|
1121 |
bool |
---|
1122 |
EAP::Mixer::storeCoefficientMap(int &) { |
---|
1123 |
if(m_eap.m_mixer_readonly) { |
---|
1124 |
debugWarning("Mixer is read-only\n"); |
---|
1125 |
return false; |
---|
1126 |
} |
---|
1127 |
return false; |
---|
1128 |
} |
---|
1129 |
|
---|
1130 |
// Names |
---|
1131 |
std::string |
---|
1132 |
EAP::Mixer::getRowName(const int row) { |
---|
1133 |
std::string mixer_src; |
---|
1134 |
if (row < 0 || row > m_eap.m_mixer_nb_tx) return "Invalid"; |
---|
1135 |
unsigned int dstid = (eRD_Mixer0<<4) + row; // Mixer has consecutive ID's |
---|
1136 |
debugOutput(DEBUG_LEVEL_VERBOSE, "EAP::Mixer::getRowName( %d ): ID's %d\n", row, dstid); |
---|
1137 |
if (m_eap.m_router){ |
---|
1138 |
std::string mixer_dst = m_eap.m_router->getDestinationName(dstid); |
---|
1139 |
mixer_src = m_eap.m_router->getSourceForDestination(mixer_dst); |
---|
1140 |
debugOutput(DEBUG_LEVEL_VERBOSE, "EAP::Mixer::found %s as source for %s\n", mixer_src.data(), |
---|
1141 |
mixer_dst.data()); |
---|
1142 |
} |
---|
1143 |
else { |
---|
1144 |
char tmp[32]; |
---|
1145 |
snprintf(tmp, 32, "MixIn:%d", row); |
---|
1146 |
mixer_src = tmp; |
---|
1147 |
} |
---|
1148 |
|
---|
1149 |
return mixer_src; |
---|
1150 |
} |
---|
1151 |
|
---|
1152 |
std::string |
---|
1153 |
EAP::Mixer::getColName(const int col) { |
---|
1154 |
std::string mixer_dst; |
---|
1155 |
stringlist dest_names; |
---|
1156 |
|
---|
1157 |
// invalid col index |
---|
1158 |
if (col < 0 || col > m_eap.m_mixer_nb_rx) { |
---|
1159 |
mixer_dst.append("Invalid"); |
---|
1160 |
return mixer_dst; |
---|
1161 |
} |
---|
1162 |
|
---|
1163 |
unsigned int srcid = (eRS_Mixer<<4) + col; // Mixer has consecutive ID's |
---|
1164 |
debugOutput(DEBUG_LEVEL_VERBOSE, "EAP::Mixer::getColName( %d ): ID's %d\n", col, srcid); |
---|
1165 |
if (m_eap.m_router){ |
---|
1166 |
std::string mixer_src = m_eap.m_router->getSourceName(srcid); |
---|
1167 |
dest_names = m_eap.m_router->getDestinationsForSource(mixer_src); |
---|
1168 |
if (dest_names.size() > 0) { |
---|
1169 |
stringlist::iterator it_d = dest_names.begin(); |
---|
1170 |
stringlist::iterator it_d_end_m1 = dest_names.end(); --it_d_end_m1; |
---|
1171 |
while (it_d != it_d_end_m1) { |
---|
1172 |
mixer_dst.append((*it_d).c_str()); mixer_dst.append("; "); |
---|
1173 |
it_d++; |
---|
1174 |
} |
---|
1175 |
} |
---|
1176 |
} else { |
---|
1177 |
char tmp[32]; |
---|
1178 |
snprintf(tmp, 32, "MixOut:%d", col); |
---|
1179 |
mixer_dst.append(tmp); |
---|
1180 |
} |
---|
1181 |
|
---|
1182 |
return mixer_dst; |
---|
1183 |
} |
---|
1184 |
|
---|
1185 |
// |
---|
1186 |
// ----------- Router ------------- |
---|
1187 |
// |
---|
1188 |
|
---|
1189 |
EAP::Router::Router(EAP &p) |
---|
1190 |
: Control::CrossbarRouter(&p.m_device, "Router") |
---|
1191 |
, m_eap(p) |
---|
1192 |
, m_peak( *(new PeakSpace(p)) ) |
---|
1193 |
, m_debugModule(p.m_debugModule) |
---|
1194 |
{ |
---|
1195 |
} |
---|
1196 |
|
---|
1197 |
EAP::Router::~Router() |
---|
1198 |
{ |
---|
1199 |
delete &m_peak; |
---|
1200 |
} |
---|
1201 |
|
---|
1202 |
void |
---|
1203 |
EAP::Router::update() |
---|
1204 |
{ |
---|
1205 |
// Clear and |
---|
1206 |
// define new sources and destinations for the router |
---|
1207 |
m_sources.clear(); |
---|
1208 |
m_eap.setupSources(); |
---|
1209 |
m_destinations.clear(); |
---|
1210 |
m_eap.setupDestinations(); |
---|
1211 |
return; |
---|
1212 |
} |
---|
1213 |
|
---|
1214 |
void |
---|
1215 |
EAP::Router::addSource(const std::string& basename, enum eRouteSource srcid, |
---|
1216 |
unsigned int base, unsigned int cnt, unsigned int offset) |
---|
1217 |
{ |
---|
1218 |
std::string name = basename + ":"; |
---|
1219 |
char tmp[4]; |
---|
1220 |
for (unsigned int i=0; i<cnt; i++) { |
---|
1221 |
snprintf(tmp, 4, "%02d", offset+i); |
---|
1222 |
m_sources[name+tmp] = (srcid<<4) + base+i; |
---|
1223 |
} |
---|
1224 |
} |
---|
1225 |
|
---|
1226 |
void |
---|
1227 |
EAP::Router::addDestination(const std::string& basename, enum eRouteDestination dstid, |
---|
1228 |
unsigned int base, unsigned int cnt, unsigned int offset) |
---|
1229 |
{ |
---|
1230 |
std::string name = basename + ":"; |
---|
1231 |
char tmp[4]; |
---|
1232 |
for (unsigned int i=0; i<cnt; i++) { |
---|
1233 |
snprintf(tmp, 4, "%02d", offset+i); |
---|
1234 |
m_destinations[name+tmp] = (dstid<<4) + base+i; |
---|
1235 |
} |
---|
1236 |
} |
---|
1237 |
|
---|
1238 |
std::string |
---|
1239 |
EAP::Router::getSourceName(const int srcid) |
---|
1240 |
{ |
---|
1241 |
for (std::map<std::string, int>::iterator it=m_sources.begin(); it!=m_sources.end(); ++it) { |
---|
1242 |
if (it->second == srcid) { |
---|
1243 |
return it->first; |
---|
1244 |
} |
---|
1245 |
} |
---|
1246 |
return ""; |
---|
1247 |
} |
---|
1248 |
|
---|
1249 |
std::string |
---|
1250 |
EAP::Router::getDestinationName(const int dstid) |
---|
1251 |
{ |
---|
1252 |
for (std::map<std::string, int>::iterator it=m_destinations.begin(); it!=m_destinations.end(); ++it) { |
---|
1253 |
if (it->second == dstid) { |
---|
1254 |
return it->first; |
---|
1255 |
} |
---|
1256 |
} |
---|
1257 |
return ""; |
---|
1258 |
} |
---|
1259 |
|
---|
1260 |
int |
---|
1261 |
EAP::Router::getSourceIndex(std::string name) |
---|
1262 |
{ |
---|
1263 |
if (m_sources.count(name) < 1) |
---|
1264 |
return -1; |
---|
1265 |
return m_sources[name]; |
---|
1266 |
} |
---|
1267 |
|
---|
1268 |
int |
---|
1269 |
EAP::Router::getDestinationIndex(std::string name) |
---|
1270 |
{ |
---|
1271 |
if (m_destinations.count(name) < 1) |
---|
1272 |
return -1; |
---|
1273 |
return m_destinations[name]; |
---|
1274 |
} |
---|
1275 |
|
---|
1276 |
stringlist |
---|
1277 |
EAP::Router::getSourceNames() |
---|
1278 |
{ |
---|
1279 |
stringlist n; |
---|
1280 |
|
---|
1281 |
for (std::map<std::string, int>::iterator it=m_sources.begin(); it!=m_sources.end(); ++it) |
---|
1282 |
n.push_back(it->first); |
---|
1283 |
return n; |
---|
1284 |
} |
---|
1285 |
|
---|
1286 |
stringlist |
---|
1287 |
EAP::Router::getDestinationNames() |
---|
1288 |
{ |
---|
1289 |
stringlist n; |
---|
1290 |
for (std::map<std::string, int>::iterator it=m_destinations.begin(); it!=m_destinations.end(); ++it) |
---|
1291 |
n.push_back(it->first); |
---|
1292 |
return n; |
---|
1293 |
} |
---|
1294 |
|
---|
1295 |
stringlist |
---|
1296 |
EAP::Router::getDestinationsForSource(const std::string& srcname) { |
---|
1297 |
RouterConfig* rcfg = m_eap.getActiveRouterConfig(); |
---|
1298 |
if(rcfg == NULL) { |
---|
1299 |
debugError("Could not request active router configuration\n"); |
---|
1300 |
return stringlist(); |
---|
1301 |
} |
---|
1302 |
stringlist ret; |
---|
1303 |
std::vector<unsigned char> dests = rcfg->getDestinationsForSource(m_sources[srcname]); |
---|
1304 |
for (unsigned int i=0; i<dests.size(); ++i) { |
---|
1305 |
ret.push_back(getDestinationName(dests[i])); |
---|
1306 |
} |
---|
1307 |
return ret; |
---|
1308 |
} |
---|
1309 |
std::string |
---|
1310 |
EAP::Router::getSourceForDestination(const std::string& dstname) { |
---|
1311 |
RouterConfig* rcfg = m_eap.getActiveRouterConfig(); |
---|
1312 |
if(rcfg == NULL) { |
---|
1313 |
debugError("Could not request active router configuration\n"); |
---|
1314 |
return ""; |
---|
1315 |
} |
---|
1316 |
int source = rcfg->getSourceForDestination(m_destinations[dstname]); |
---|
1317 |
return getSourceName(source); |
---|
1318 |
} |
---|
1319 |
|
---|
1320 |
|
---|
1321 |
bool |
---|
1322 |
EAP::Router::canConnect(const int source, const int dest) |
---|
1323 |
{ |
---|
1324 |
debugWarning("TODO: Implement canConnect(0x%02x, 0x%02x)\n", source, dest); |
---|
1325 |
|
---|
1326 |
// we can connect anything |
---|
1327 |
// FIXME: can we? |
---|
1328 |
return true; |
---|
1329 |
} |
---|
1330 |
|
---|
1331 |
bool |
---|
1332 |
EAP::Router::setConnectionState(const int source, const int dest, const bool enable) |
---|
1333 |
{ |
---|
1334 |
debugOutput(DEBUG_LEVEL_VERBOSE,"Router::setConnectionState(0x%02x -> 0x%02x ? %i)\n", source, dest, enable); |
---|
1335 |
// get the routing configuration |
---|
1336 |
RouterConfig *rcfg = m_eap.getActiveRouterConfig(); |
---|
1337 |
if(rcfg == NULL) { |
---|
1338 |
debugError("Could not request active router configuration\n"); |
---|
1339 |
return false; |
---|
1340 |
} |
---|
1341 |
|
---|
1342 |
bool ret = false; |
---|
1343 |
if (enable) { |
---|
1344 |
ret = rcfg->setupRoute(source, dest); |
---|
1345 |
} else { |
---|
1346 |
ret = rcfg->removeRoute(source, dest); |
---|
1347 |
} |
---|
1348 |
m_eap.updateCurrentRouterConfig(*rcfg); |
---|
1349 |
return ret; |
---|
1350 |
} |
---|
1351 |
|
---|
1352 |
bool |
---|
1353 |
EAP::Router::getConnectionState(const int source, const int dest) |
---|
1354 |
{ |
---|
1355 |
// get the routing configuration |
---|
1356 |
RouterConfig *rcfg = m_eap.getActiveRouterConfig(); |
---|
1357 |
if(rcfg == NULL) { |
---|
1358 |
debugError("Could not request active router configuration\n"); |
---|
1359 |
return false; |
---|
1360 |
} |
---|
1361 |
if (rcfg->getSourceForDestination(dest) == source) { |
---|
1362 |
return true; |
---|
1363 |
} |
---|
1364 |
return false; |
---|
1365 |
} |
---|
1366 |
|
---|
1367 |
bool |
---|
1368 |
EAP::Router::canConnect(const std::string& src, const std::string& dst) |
---|
1369 |
{ |
---|
1370 |
int srcidx = getSourceIndex(src); |
---|
1371 |
int dstidx = getDestinationIndex(dst); |
---|
1372 |
return canConnect(srcidx, dstidx); |
---|
1373 |
} |
---|
1374 |
|
---|
1375 |
bool |
---|
1376 |
EAP::Router::setConnectionState(const std::string& src, const std::string& dst, const bool enable) |
---|
1377 |
{ |
---|
1378 |
int srcidx = getSourceIndex(src); |
---|
1379 |
int dstidx = getDestinationIndex(dst); |
---|
1380 |
return setConnectionState(srcidx, dstidx, enable); |
---|
1381 |
} |
---|
1382 |
|
---|
1383 |
bool |
---|
1384 |
EAP::Router::getConnectionState(const std::string& src, const std::string& dst) |
---|
1385 |
{ |
---|
1386 |
int srcidx = getSourceIndex(src); |
---|
1387 |
int dstidx = getDestinationIndex(dst); |
---|
1388 |
return getConnectionState(srcidx, dstidx); |
---|
1389 |
} |
---|
1390 |
|
---|
1391 |
|
---|
1392 |
bool |
---|
1393 |
EAP::Router::clearAllConnections() |
---|
1394 |
{ |
---|
1395 |
// build a new empty routing configuration |
---|
1396 |
RouterConfig newcfg = EAP::RouterConfig(m_eap); |
---|
1397 |
|
---|
1398 |
// upload the new router config |
---|
1399 |
if(!m_eap.updateCurrentRouterConfig(newcfg)) { |
---|
1400 |
debugError("Could not update router config\n"); |
---|
1401 |
return false; |
---|
1402 |
} |
---|
1403 |
return true; |
---|
1404 |
} |
---|
1405 |
|
---|
1406 |
bool |
---|
1407 |
EAP::Router::hasPeakMetering() |
---|
1408 |
{ |
---|
1409 |
return m_eap.m_router_exposed; |
---|
1410 |
} |
---|
1411 |
|
---|
1412 |
double |
---|
1413 |
EAP::Router::getPeakValue(const std::string& dest) |
---|
1414 |
{ |
---|
1415 |
m_peak.read(); |
---|
1416 |
unsigned char dst = m_destinations[dest]; |
---|
1417 |
return m_peak.getPeak(dst); |
---|
1418 |
} |
---|
1419 |
|
---|
1420 |
std::map<std::string, double> |
---|
1421 |
EAP::Router::getPeakValues() |
---|
1422 |
{ |
---|
1423 |
m_peak.read(); |
---|
1424 |
std::map<std::string, double> ret; |
---|
1425 |
std::map<unsigned char, int> peaks = m_peak.getPeaks(); |
---|
1426 |
for (std::map<unsigned char, int>::iterator it=peaks.begin(); it!=peaks.end(); ++it) { |
---|
1427 |
ret[getDestinationName(it->first)] = it->second; |
---|
1428 |
} |
---|
1429 |
return ret; |
---|
1430 |
} |
---|
1431 |
|
---|
1432 |
void |
---|
1433 |
EAP::Router::show() |
---|
1434 |
{ |
---|
1435 |
// print the peak space as it also contains the routing configuration |
---|
1436 |
printMessage("Router sources:\n"); |
---|
1437 |
for ( std::map<std::string, int>::iterator it=m_sources.begin(); it!=m_sources.end(); ++it ) { |
---|
1438 |
printMessage(" 0x%02x : %s\n", (*it).second, (*it).first.c_str()); |
---|
1439 |
} |
---|
1440 |
printMessage("Router destinations:\n"); |
---|
1441 |
for ( std::map<std::string, int>::iterator it=m_destinations.begin(); it!=m_destinations.end(); ++it ) { |
---|
1442 |
printMessage(" 0x%02x : %s\n", (*it).second, (*it).first.c_str()); |
---|
1443 |
} |
---|
1444 |
printMessage("Router connections:\n"); |
---|
1445 |
stringlist sources = getSourceNames(); |
---|
1446 |
stringlist destinations = getDestinationNames(); |
---|
1447 |
for (stringlist::iterator it1=sources.begin(); it1!=sources.end(); ++it1) { |
---|
1448 |
for (stringlist::iterator it2=destinations.begin(); it2!=destinations.end(); ++it2) { |
---|
1449 |
if (getConnectionState(*it1, *it2)) { |
---|
1450 |
printMessage(" %s -> %s\n", it1->c_str(), it2->c_str()); |
---|
1451 |
} |
---|
1452 |
} |
---|
1453 |
} |
---|
1454 |
printMessage("Active router config:\n"); |
---|
1455 |
m_eap.getActiveRouterConfig()->show(); |
---|
1456 |
printMessage("Active peak config:\n"); |
---|
1457 |
m_peak.read(); |
---|
1458 |
m_peak.show(); |
---|
1459 |
} |
---|
1460 |
|
---|
1461 |
// ----------- routing config ------------- |
---|
1462 |
EAP::RouterConfig::RouterConfig(EAP &p) |
---|
1463 |
: m_eap(p) |
---|
1464 |
, m_base(eRT_None), m_offset(0) |
---|
1465 |
, m_debugModule(p.m_debugModule) |
---|
1466 |
{} |
---|
1467 |
|
---|
1468 |
EAP::RouterConfig::RouterConfig(EAP &p, enum eRegBase b, unsigned int o) |
---|
1469 |
: m_eap(p) |
---|
1470 |
, m_base(b), m_offset(o) |
---|
1471 |
, m_debugModule(p.m_debugModule) |
---|
1472 |
{} |
---|
1473 |
|
---|
1474 |
EAP::RouterConfig::~RouterConfig() |
---|
1475 |
{} |
---|
1476 |
|
---|
1477 |
bool |
---|
1478 |
EAP::RouterConfig::read(enum eRegBase base, unsigned offset) |
---|
1479 |
{ |
---|
1480 |
// first clear the current route vector |
---|
1481 |
m_routes2.clear(); |
---|
1482 |
|
---|
1483 |
uint32_t nb_routes; |
---|
1484 |
if(!m_eap.readRegBlock(base, offset, &nb_routes, 4)) { |
---|
1485 |
debugError("Failed to read number of entries\n"); |
---|
1486 |
return false; |
---|
1487 |
} |
---|
1488 |
if(nb_routes == 0) { |
---|
1489 |
debugWarning("No routes found. Base 0x%x, offset 0x%x\n", base, offset); |
---|
1490 |
} |
---|
1491 |
|
---|
1492 |
// read the route info |
---|
1493 |
uint32_t tmp_entries[nb_routes]; |
---|
1494 |
if(!m_eap.readRegBlock(base, offset+4, tmp_entries, nb_routes*4)) { |
---|
1495 |
debugError("Failed to read router config block information\n"); |
---|
1496 |
return false; |
---|
1497 |
} |
---|
1498 |
|
---|
1499 |
// decode into the routing map |
---|
1500 |
for(unsigned int i=0; i < nb_routes; i++) { |
---|
1501 |
m_routes2[tmp_entries[i]&0xff] = (tmp_entries[i]>>8)&0xff; |
---|
1502 |
} |
---|
1503 |
return true; |
---|
1504 |
} |
---|
1505 |
|
---|
1506 |
bool |
---|
1507 |
EAP::RouterConfig::write(enum eRegBase base, unsigned offset) |
---|
1508 |
{ |
---|
1509 |
uint32_t nb_routes = m_routes2.size(); |
---|
1510 |
if(nb_routes == 0) { |
---|
1511 |
debugWarning("Writing 0 routes? This will deactivate routing and make the device very silent...\n"); |
---|
1512 |
} |
---|
1513 |
if (nb_routes > 128) { |
---|
1514 |
debugError("More then 128 are not possible, only the first 128 routes will get saved!\n"); |
---|
1515 |
nb_routes = 128; |
---|
1516 |
} |
---|
1517 |
uint32_t tmp_entries[nb_routes]; |
---|
1518 |
|
---|
1519 |
// encode from the routing vector |
---|
1520 |
int i=0; |
---|
1521 |
for (RouteVectorV2::iterator it=m_routes2.begin(); it!=m_routes2.end(); ++it) { |
---|
1522 |
tmp_entries[i] = ((it->second<<8) + it->first)&0xffff; |
---|
1523 |
++i; |
---|
1524 |
} |
---|
1525 |
|
---|
1526 |
uint32_t zeros[129]; |
---|
1527 |
for (int i=0; i<129; ++i) zeros[i] = 0; |
---|
1528 |
if(!m_eap.writeRegBlock(base, offset, zeros, 129*4)) { |
---|
1529 |
debugError("Failed to write zeros to router config block\n"); |
---|
1530 |
return false; |
---|
1531 |
} |
---|
1532 |
|
---|
1533 |
// write the result to the device |
---|
1534 |
if(!m_eap.writeRegBlock(base, offset+4, tmp_entries, nb_routes*4)) { |
---|
1535 |
debugError("Failed to write router config block information\n"); |
---|
1536 |
return false; |
---|
1537 |
} |
---|
1538 |
if(!m_eap.writeRegBlock(base, offset, &nb_routes, 4)) { |
---|
1539 |
debugError("Failed to write number of entries\n"); |
---|
1540 |
return false; |
---|
1541 |
} |
---|
1542 |
return true; |
---|
1543 |
} |
---|
1544 |
|
---|
1545 |
bool |
---|
1546 |
EAP::RouterConfig::setupRoute(unsigned char src, unsigned char dest) { |
---|
1547 |
debugOutput(DEBUG_LEVEL_VERBOSE,"RouterConfig::setupRoute( 0x%02x, 0x%02x )\n", src, dest); |
---|
1548 |
m_routes2[dest] = src; |
---|
1549 |
return true; |
---|
1550 |
} |
---|
1551 |
|
---|
1552 |
bool |
---|
1553 |
EAP::RouterConfig::removeRoute(unsigned char src, unsigned char dest) { |
---|
1554 |
debugOutput(DEBUG_LEVEL_VERBOSE,"RouterConfig::removeRoute( 0x%02x, 0x%02x )\n", src, dest); |
---|
1555 |
if (m_routes2.count(dest) > 0) { |
---|
1556 |
if (src != m_routes2[dest]) { |
---|
1557 |
return false; |
---|
1558 |
} |
---|
1559 |
return removeRoute(dest); |
---|
1560 |
} |
---|
1561 |
return true; |
---|
1562 |
} |
---|
1563 |
|
---|
1564 |
bool |
---|
1565 |
EAP::RouterConfig::removeRoute(unsigned char dest) { |
---|
1566 |
debugOutput(DEBUG_LEVEL_VERBOSE,"RouterConfig::removeRoute( 0x%02x )\n", dest); |
---|
1567 |
m_routes2.erase(dest); |
---|
1568 |
if (m_routes2.count(dest) < 1) { |
---|
1569 |
return false; |
---|
1570 |
} |
---|
1571 |
return true; |
---|
1572 |
} |
---|
1573 |
|
---|
1574 |
unsigned char |
---|
1575 |
EAP::RouterConfig::getSourceForDestination(unsigned char dest) { |
---|
1576 |
if (m_routes2.count(dest) > 0) { |
---|
1577 |
return m_routes2[dest]; |
---|
1578 |
} |
---|
1579 |
return -1; |
---|
1580 |
} |
---|
1581 |
|
---|
1582 |
std::vector<unsigned char> |
---|
1583 |
EAP::RouterConfig::getDestinationsForSource(unsigned char source) { |
---|
1584 |
std::vector<unsigned char> ret; |
---|
1585 |
for (RouteVectorV2::iterator it=m_routes2.begin(); it!=m_routes2.end(); ++it) { |
---|
1586 |
if (it->second == source) { |
---|
1587 |
ret.push_back(it->first); |
---|
1588 |
} |
---|
1589 |
} |
---|
1590 |
return ret; |
---|
1591 |
} |
---|
1592 |
|
---|
1593 |
void |
---|
1594 |
EAP::RouterConfig::show() |
---|
1595 |
{ |
---|
1596 |
for ( RouteVectorV2::iterator it=m_routes2.begin(); it!=m_routes2.end(); ++it ) { |
---|
1597 |
printMessage("0x%02x -> 0x%02x\n", it->second, it->first); |
---|
1598 |
} |
---|
1599 |
} |
---|
1600 |
|
---|
1601 |
// |
---|
1602 |
// ----------- peak space ------------- |
---|
1603 |
// |
---|
1604 |
|
---|
1605 |
bool |
---|
1606 |
EAP::PeakSpace::read(enum eRegBase base, unsigned offset) |
---|
1607 |
{ |
---|
1608 |
uint32_t nb_routes; |
---|
1609 |
// we have to figure out the number of entries through the currently |
---|
1610 |
// active router config |
---|
1611 |
RouterConfig *rcfg = m_eap.getActiveRouterConfig(); |
---|
1612 |
if(rcfg == NULL) { |
---|
1613 |
debugError("Could not get active router config\n"); |
---|
1614 |
return false; |
---|
1615 |
} |
---|
1616 |
nb_routes = rcfg->getNbRoutes(); |
---|
1617 |
|
---|
1618 |
// read the peak/route info |
---|
1619 |
uint32_t tmp_entries[nb_routes]; |
---|
1620 |
if(!m_eap.readRegBlock(base, offset, tmp_entries, nb_routes*4)) { |
---|
1621 |
debugError("Failed to read peak block information\n"); |
---|
1622 |
return false; |
---|
1623 |
} |
---|
1624 |
// parse the peaks into the map |
---|
1625 |
for (unsigned int i=0; i<nb_routes; ++i) { |
---|
1626 |
unsigned char dest = tmp_entries[i]&0xff; |
---|
1627 |
int peak = (tmp_entries[i]&0xfff0000)>>16; |
---|
1628 |
if (m_peaks.count(dest) == 0 || m_peaks[dest] < peak) { |
---|
1629 |
m_peaks[dest] = peak; |
---|
1630 |
} |
---|
1631 |
} |
---|
1632 |
return true; |
---|
1633 |
} |
---|
1634 |
|
---|
1635 |
|
---|
1636 |
void |
---|
1637 |
EAP::PeakSpace::show() |
---|
1638 |
{ |
---|
1639 |
printMessage(" %zi peaks\n", m_peaks.size()); |
---|
1640 |
for (std::map<unsigned char, int>::iterator it=m_peaks.begin(); it!=m_peaks.end(); ++it) { |
---|
1641 |
printMessage("0x%02x : %i\n", it->first, it->second); |
---|
1642 |
} |
---|
1643 |
} |
---|
1644 |
|
---|
1645 |
int |
---|
1646 |
EAP::PeakSpace::getPeak(unsigned char dst) { |
---|
1647 |
int ret = m_peaks[dst]; |
---|
1648 |
m_peaks.erase(dst); |
---|
1649 |
return ret; |
---|
1650 |
} |
---|
1651 |
|
---|
1652 |
std::map<unsigned char, int> |
---|
1653 |
EAP::PeakSpace::getPeaks() { |
---|
1654 |
// Create a new empty map |
---|
1655 |
std::map<unsigned char, int> ret; |
---|
1656 |
// Swap the peak map with the new and empty one |
---|
1657 |
ret.swap(m_peaks); |
---|
1658 |
// Return the now filled map of the peaks :-) |
---|
1659 |
return ret; |
---|
1660 |
} |
---|
1661 |
|
---|
1662 |
// ----------- stream config block ------------- |
---|
1663 |
EAP::StreamConfig::StreamConfig(EAP &p, enum eRegBase b, unsigned int o) |
---|
1664 |
: m_eap(p) |
---|
1665 |
, m_base(b), m_offset(o) |
---|
1666 |
, m_nb_tx(0), m_nb_rx(0) |
---|
1667 |
, m_tx_configs(NULL), m_rx_configs(NULL) |
---|
1668 |
, m_debugModule(p.m_debugModule) |
---|
1669 |
{ |
---|
1670 |
|
---|
1671 |
} |
---|
1672 |
|
---|
1673 |
EAP::StreamConfig::~StreamConfig() |
---|
1674 |
{ |
---|
1675 |
if(m_tx_configs) delete[]m_tx_configs; |
---|
1676 |
if(m_rx_configs) delete[]m_rx_configs; |
---|
1677 |
} |
---|
1678 |
|
---|
1679 |
bool |
---|
1680 |
EAP::StreamConfig::read(enum eRegBase base, unsigned offset) |
---|
1681 |
{ |
---|
1682 |
if(!m_eap.readRegBlock(base, offset, &m_nb_tx, 4)) { |
---|
1683 |
debugError("Failed to read number of tx entries\n"); |
---|
1684 |
return false; |
---|
1685 |
} |
---|
1686 |
if(!m_eap.readRegBlock(base, offset+4, &m_nb_rx, 4)) { |
---|
1687 |
debugError("Failed to read number of rx entries\n"); |
---|
1688 |
return false; |
---|
1689 |
} |
---|
1690 |
debugOutput(DEBUG_LEVEL_VERBOSE, " Entries: TX: %u, RX: %u\n", m_nb_tx, m_nb_rx); |
---|
1691 |
|
---|
1692 |
if(m_tx_configs) { |
---|
1693 |
delete[]m_tx_configs; |
---|
1694 |
m_tx_configs = NULL; |
---|
1695 |
} |
---|
1696 |
if(m_rx_configs) { |
---|
1697 |
delete[]m_rx_configs; |
---|
1698 |
m_rx_configs = NULL; |
---|
1699 |
} |
---|
1700 |
|
---|
1701 |
offset += 8; |
---|
1702 |
if(m_nb_tx > 0) { |
---|
1703 |
m_tx_configs = new struct ConfigBlock[m_nb_tx]; |
---|
1704 |
for(unsigned int i=0; i<m_nb_tx; i++) { |
---|
1705 |
fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_tx_configs[i])); |
---|
1706 |
if(!m_eap.readRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) { |
---|
1707 |
debugError("Failed to read tx entry %d\n", i); |
---|
1708 |
return false; |
---|
1709 |
} |
---|
1710 |
offset += sizeof(struct ConfigBlock); |
---|
1711 |
} |
---|
1712 |
} |
---|
1713 |
|
---|
1714 |
if(m_nb_rx > 0) { |
---|
1715 |
m_rx_configs = new struct ConfigBlock[m_nb_rx]; |
---|
1716 |
for(unsigned int i=0; i<m_nb_rx; i++) { |
---|
1717 |
fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_rx_configs[i])); |
---|
1718 |
if(!m_eap.readRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) { |
---|
1719 |
debugError("Failed to read rx entry %d\n", i); |
---|
1720 |
return false; |
---|
1721 |
} |
---|
1722 |
offset += sizeof(struct ConfigBlock); |
---|
1723 |
} |
---|
1724 |
} |
---|
1725 |
return true; |
---|
1726 |
} |
---|
1727 |
|
---|
1728 |
bool |
---|
1729 |
EAP::StreamConfig::write(enum eRegBase base, unsigned offset) |
---|
1730 |
{ |
---|
1731 |
if(!m_eap.writeRegBlock(base, offset, &m_nb_tx, 4)) { |
---|
1732 |
debugError("Failed to write number of tx entries\n"); |
---|
1733 |
return false; |
---|
1734 |
} |
---|
1735 |
if(!m_eap.writeRegBlock(base, offset+4, &m_nb_rx, 4)) { |
---|
1736 |
debugError("Failed to write number of rx entries\n"); |
---|
1737 |
return false; |
---|
1738 |
} |
---|
1739 |
|
---|
1740 |
offset += 8; |
---|
1741 |
for(unsigned int i=0; i<m_nb_tx; i++) { |
---|
1742 |
fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_tx_configs[i])); |
---|
1743 |
if(!m_eap.writeRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) { |
---|
1744 |
debugError("Failed to write tx entry %d\n", i); |
---|
1745 |
return false; |
---|
1746 |
} |
---|
1747 |
offset += sizeof(struct ConfigBlock); |
---|
1748 |
} |
---|
1749 |
|
---|
1750 |
for(unsigned int i=0; i<m_nb_rx; i++) { |
---|
1751 |
fb_quadlet_t *ptr = reinterpret_cast<fb_quadlet_t *>(&(m_rx_configs[i])); |
---|
1752 |
if(!m_eap.writeRegBlock(base, offset, ptr, sizeof(struct ConfigBlock))) { |
---|
1753 |
debugError("Failed to write rx entry %d\n", i); |
---|
1754 |
return false; |
---|
1755 |
} |
---|
1756 |
offset += sizeof(struct ConfigBlock); |
---|
1757 |
} |
---|
1758 |
return true; |
---|
1759 |
} |
---|
1760 |
|
---|
1761 |
stringlist |
---|
1762 |
EAP::StreamConfig::getNamesForBlock(struct ConfigBlock &b) |
---|
1763 |
{ |
---|
1764 |
stringlist names; |
---|
1765 |
char namestring[DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_BYTES+1]; |
---|
1766 |
|
---|
1767 |
memcpy(namestring, b.names, DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_BYTES); |
---|
1768 |
|
---|
1769 |
// Strings from the device are always little-endian, |
---|
1770 |
// so byteswap for big-endian machines |
---|
1771 |
#if __BYTE_ORDER == __BIG_ENDIAN |
---|
1772 |
byteSwapBlock((quadlet_t *)namestring, DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_QUADS); |
---|
1773 |
#endif |
---|
1774 |
|
---|
1775 |
namestring[DICE_EAP_CHANNEL_CONFIG_NAMESTR_LEN_BYTES]='\0'; |
---|
1776 |
return m_eap.m_device.splitNameString(std::string(namestring)); |
---|
1777 |
} |
---|
1778 |
|
---|
1779 |
void |
---|
1780 |
EAP::StreamConfig::showConfigBlock(struct ConfigBlock &b) |
---|
1781 |
{ |
---|
1782 |
printMessage(" Channel count : %u audio, %u midi\n", b.nb_audio, b.nb_midi); |
---|
1783 |
printMessage(" AC3 Map : 0x%08X\n", b.ac3_map); |
---|
1784 |
stringlist channel_names = getNamesForBlock(b); |
---|
1785 |
printMessage(" Channel names :\n"); |
---|
1786 |
for ( stringlist::iterator it = channel_names.begin(); |
---|
1787 |
it != channel_names.end(); |
---|
1788 |
++it ) |
---|
1789 |
{ |
---|
1790 |
printMessage(" %s\n", (*it).c_str()); |
---|
1791 |
} |
---|
1792 |
} |
---|
1793 |
|
---|
1794 |
void |
---|
1795 |
EAP::StreamConfig::show() |
---|
1796 |
{ |
---|
1797 |
for(unsigned int i=0; i<m_nb_tx; i++) { |
---|
1798 |
printMessage("TX Config block %d\n", i); |
---|
1799 |
showConfigBlock(m_tx_configs[i]); |
---|
1800 |
} |
---|
1801 |
for(unsigned int i=0; i<m_nb_rx; i++) { |
---|
1802 |
printMessage("RX Config block %d\n", i); |
---|
1803 |
showConfigBlock(m_rx_configs[i]); |
---|
1804 |
} |
---|
1805 |
} |
---|
1806 |
|
---|
1807 |
} // namespace Dice |
---|
1808 |
|
---|
1809 |
|
---|
1810 |
// vim: et |
---|