Index: /trunk/libffado/tests/test-echomixer.cpp =================================================================== --- /trunk/libffado/tests/test-echomixer.cpp (revision 663) +++ /trunk/libffado/tests/test-echomixer.cpp (revision 663) @@ -0,0 +1,567 @@ +/* + * Copyright (C) 2007 by Pieter Palmers + * Copyright (C) 2005-2007 by Daniel Wagner + * + * This file is part of FFADO + * FFADO = Free Firewire (pro-)audio drivers for linux + * + * FFADO is based upon FreeBoB + * + * FFADO is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * FFADO is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FFADO; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA. + * + */ + +#include +#include + +#include "debugmodule/debugmodule.h" + +#include "libieee1394/configrom.h" +#include "libieee1394/ieee1394service.h" +#include "libutil/cmd_serialize.h" +#include "libavc/general/avc_generic.h" + +#include "fireworks/efc/efc_avc_cmd.h" +#include "fireworks/efc/efc_cmds_mixer.h" +#include "fireworks/efc/efc_cmds_monitor.h" +#include "fireworks/efc/efc_cmds_hardware.h" +using namespace FireWorks; + +#include +#include +#include + +using namespace std; +using namespace AVC; +using namespace Util; + +DECLARE_GLOBAL_DEBUG_MODULE; + +#define MAX_ARGS 1000 + +//////////////////////////////////////////////// +// arg parsing +//////////////////////////////////////////////// +const char *argp_program_version = "test-echomixer 0.1"; +const char *argp_program_bug_address = ""; +static char doc[] = "test-avccmd -- test program to examine the echo audio mixer."; +static char args_doc[] = "NODE_ID"; +static struct argp_option options[] = { + {"verbose", 'v', 0, 0, "Produce verbose output" }, + {"port", 'p', "PORT", 0, "Set port" }, + {"node", 'n', "NODE", 0, "Set node" }, + { 0 } +}; + +struct arguments +{ + arguments() + : nargs ( 0 ) + , verbose( false ) + , test( false ) + , port( 0 ) + { + args[0] = 0; + } + + char* args[MAX_ARGS]; + int nargs; + bool verbose; + bool test; + int port; + int node; +} arguments; + +// Parse a single option. +static error_t +parse_opt( int key, char* arg, struct argp_state* state ) +{ + // Get the input argument from `argp_parse', which we + // know is a pointer to our arguments structure. + struct arguments* arguments = ( struct arguments* ) state->input; + + char* tail; + switch (key) { + case 'v': + arguments->verbose = true; + break; + case 't': + arguments->test = true; + break; + case 'p': + errno = 0; + arguments->port = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case 'n': + errno = 0; + arguments->node = strtol(arg, &tail, 0); + if (errno) { + perror("argument parsing failed:"); + return errno; + } + break; + case ARGP_KEY_ARG: + if (state->arg_num >= MAX_ARGS) { + // Too many arguments. + argp_usage (state); + } + arguments->args[state->arg_num] = arg; + arguments->nargs++; + break; + case ARGP_KEY_END: + if(arguments->nargs<0) { + printf("not enough arguments\n"); + return -1; + } + + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { options, parse_opt, args_doc, doc }; + +bool doEfcOverAVC(Ieee1394Service& m_1394Service, int node, EfcCmd &c) +{ + EfcOverAVCCmd cmd( m_1394Service ); + cmd.setCommandType( AVC::AVCCommand::eCT_Control ); + cmd.setNodeId( node ); + cmd.setSubunitType( AVC::eST_Unit ); + cmd.setSubunitId( 0xff ); + + cmd.setVerbose( DEBUG_LEVEL_NORMAL ); + + cmd.m_cmd = &c; + + if ( !cmd.fire()) { + debugError( "EfcOverAVCCmd command failed\n" ); + c.showEfcCmd(); + return false; + } + + if ( c.m_header.retval != EfcCmd::eERV_Ok + && c.m_header.retval != EfcCmd::eERV_FlashBusy) { + debugError( "EFC command failed\n" ); + c.showEfcCmd(); + return false; + } + + return true; +} + +/////////////////////////// +// main +////////////////////////// +int +main(int argc, char **argv) +{ + // arg parsing + if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) { + fprintf( stderr, "Could not parse command line\n" ); + exit(-1); + } + errno = 0; + + Ieee1394Service *m_1394Service = new Ieee1394Service(); + if ( !m_1394Service ) { + debugFatal( "Could not create Ieee1349Service object\n" ); + return false; + } + + if ( !m_1394Service->initialize( arguments.port ) ) { + debugFatal( "Could not initialize Ieee1349Service object\n" ); + delete m_1394Service; + m_1394Service = 0; + return false; + } + + EfcHardwareInfoCmd m_HwInfo; + + if (!doEfcOverAVC(*m_1394Service, arguments.node, m_HwInfo)) { + debugFatal("Could not obtain FireWorks device info\n"); + return false; + } + m_HwInfo.showEfcCmd(); + +// uint32_t m_nb_1394_playback_channels; +// uint32_t m_nb_1394_record_channels; +// +// uint32_t m_nb_phys_audio_out; +// uint32_t m_nb_phys_audio_in; + + unsigned int ch=0; + + uint32_t pbk_vol[m_HwInfo.m_nb_1394_playback_channels][5]; + uint32_t rec_vol[m_HwInfo.m_nb_1394_record_channels][5]; + uint32_t out_vol[m_HwInfo.m_nb_phys_audio_out][5]; + uint32_t in_vol[m_HwInfo.m_nb_phys_audio_in][5]; + + memset(pbk_vol, 0, sizeof(uint32_t) * 5 * m_HwInfo.m_nb_1394_playback_channels); + memset(rec_vol, 0, sizeof(uint32_t) * 5 * m_HwInfo.m_nb_1394_record_channels); + memset(out_vol, 0, sizeof(uint32_t) * 5 * m_HwInfo.m_nb_phys_audio_out); + memset(in_vol, 0, sizeof(uint32_t) * 5 * m_HwInfo.m_nb_phys_audio_in); + + for (ch=0;ch +#include + +using namespace std; + +namespace FireWorks { + +const char *eMixerTargetToString(const enum eMixerTarget target) { + switch (target) { + case eMT_PhysicalOutputMix: + return "eMT_PhysicalOutputMix"; + case eMT_PhysicalInputMix: + return "eMT_PhysicalInputMix"; + case eMT_PlaybackMix: + return "eMT_PlaybackMix"; + case eMT_RecordMix: + return "eMT_RecordMix"; + default: + return "invalid"; + } +} + +const char *eMixerCommandToString(const enum eMixerCommand command) { + switch (command) { + case eMC_Gain: + return "eMC_Gain"; + case eMC_Solo: + return "eMC_Solo"; + case eMC_Mute: + return "eMC_Mute"; + case eMC_Pan: + return "eMC_Pan"; + case eMC_Nominal: + return "eMC_Nominal"; + default: + return "invalid"; + } +} + +EfcGenericMixerCmd::EfcGenericMixerCmd(enum eCmdType type, + enum eMixerTarget target, + enum eMixerCommand command) + : EfcCmd() + , m_channel ( -1 ) + , m_value ( 0 ) + , m_type ( type ) + , m_target ( target ) + , m_command ( command ) +{ + switch (target) { + case eMT_PhysicalOutputMix: + m_category_id=EFC_CAT_PHYSICAL_OUTPUT_MIX; + break; + case eMT_PhysicalInputMix: + m_category_id=EFC_CAT_PHYSICAL_INPUT_MIX; + break; + case eMT_PlaybackMix: + m_category_id=EFC_CAT_PLAYBACK_MIX; + break; + case eMT_RecordMix: + m_category_id=EFC_CAT_RECORD_MIX; + break; + default: + debugError("Invalid mixer target: %d\n", target); + } + + if (type == eCT_Get) { + switch (command) { + case eMC_Gain: + m_command_id=EFC_CMD_MIXER_GET_GAIN; + break; + case eMC_Solo: + m_command_id=EFC_CMD_MIXER_GET_SOLO; + break; + case eMC_Mute: + m_command_id=EFC_CMD_MIXER_GET_MUTE; + break; + case eMC_Pan: + m_command_id=EFC_CMD_MIXER_GET_PAN; + break; + case eMC_Nominal: + m_command_id=EFC_CMD_MIXER_GET_NOMINAL; + break; + default: + debugError("Invalid mixer get command: %d\n", command); + } + } else { + switch (command) { + case eMC_Gain: + m_command_id=EFC_CMD_MIXER_SET_GAIN; + break; + case eMC_Solo: + m_command_id=EFC_CMD_MIXER_SET_SOLO; + break; + case eMC_Mute: + m_command_id=EFC_CMD_MIXER_SET_MUTE; + break; + case eMC_Pan: + m_command_id=EFC_CMD_MIXER_SET_PAN; + break; + case eMC_Nominal: + m_command_id=EFC_CMD_MIXER_SET_NOMINAL; + break; + default: + debugError("Invalid mixer set command: %d\n", command); + } + } +} + +bool +EfcGenericMixerCmd::serialize( Util::IOSSerialize& se ) +{ + bool result=true; + + if (m_type == eCT_Get) { + // the length should be specified before + // the header is serialized + m_length=EFC_HEADER_LENGTH_QUADLETS+1; + + result &= EfcCmd::serialize ( se ); + + result &= se.write(htonl(m_channel), "Channel" ); + + } else { + // the length should be specified before + // the header is serialized + m_length=EFC_HEADER_LENGTH_QUADLETS+2; + + result &= EfcCmd::serialize ( se ); + + result &= se.write(htonl(m_channel), "Channel" ); + result &= se.write(htonl(m_value), "Value" ); + } + return result; +} + +bool +EfcGenericMixerCmd::deserialize( Util::IISDeserialize& de ) +{ + bool result=true; + + result &= EfcCmd::deserialize ( de ); + + EFC_DESERIALIZE_AND_SWAP(de, (quadlet_t *)&m_channel, result); + EFC_DESERIALIZE_AND_SWAP(de, &m_value, result); + + return result; +} + +void +EfcGenericMixerCmd::showEfcCmd() +{ + EfcCmd::showEfcCmd(); + debugOutput(DEBUG_LEVEL_NORMAL, "EFC %s %s %s:\n", + (m_type==eCT_Get?"GET":"SET"), + eMixerTargetToString(m_target), + eMixerCommandToString(m_command)); + debugOutput(DEBUG_LEVEL_NORMAL, " Channel : %ld\n", m_channel); + debugOutput(DEBUG_LEVEL_NORMAL, " Value : %lu\n", m_value); +} + +// --- The specific commands + + + +} // namespace FireWorks Index: /trunk/libffado/src/fireworks/efc/efc_cmds_monitor.cpp =================================================================== --- /trunk/libffado/src/fireworks/efc/efc_cmds_monitor.cpp (revision 663) +++ /trunk/libffado/src/fireworks/efc/efc_cmds_monitor.cpp (revision 663) @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2007 by Pieter Palmers + * + * This file is part of FFADO + * FFADO = Free Firewire (pro-)audio drivers for linux + * + * FFADO is based upon FreeBoB + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation; + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "efc_cmd.h" +#include "efc_cmds_monitor.h" + +#include +#include + +using namespace std; + +namespace FireWorks { + +const char *eMonitorCommandToString(const enum eMonitorCommand command) { + switch (command) { + case eMoC_Gain: + return "eMC_Gain"; + case eMoC_Solo: + return "eMoC_Solo"; + case eMoC_Mute: + return "eMoC_Mute"; + case eMoC_Pan: + return "eMoC_Pan"; + default: + return "invalid"; + } +} + +EfcGenericMonitorCmd::EfcGenericMonitorCmd(enum eCmdType type, + enum eMonitorCommand command) + : EfcCmd() + , m_input ( -1 ) + , m_output ( -1 ) + , m_value ( 0 ) + , m_type ( type ) + , m_command ( command ) +{ + m_category_id=EFC_CAT_MONITOR_MIX; + if (type == eCT_Get) { + switch (command) { + case eMoC_Gain: + m_command_id=EFC_CMD_MIXER_GET_GAIN; + break; + case eMoC_Solo: + m_command_id=EFC_CMD_MIXER_GET_SOLO; + break; + case eMoC_Mute: + m_command_id=EFC_CMD_MIXER_GET_MUTE; + break; + case eMoC_Pan: + m_command_id=EFC_CMD_MIXER_GET_PAN; + break; + default: + debugError("Invalid mixer get command: %d\n", command); + } + } else { + switch (command) { + case eMoC_Gain: + m_command_id=EFC_CMD_MIXER_SET_GAIN; + break; + case eMoC_Solo: + m_command_id=EFC_CMD_MIXER_SET_SOLO; + break; + case eMoC_Mute: + m_command_id=EFC_CMD_MIXER_SET_MUTE; + break; + case eMoC_Pan: + m_command_id=EFC_CMD_MIXER_SET_PAN; + break; + default: + debugError("Invalid mixer set command: %d\n", command); + } + } +} + +bool +EfcGenericMonitorCmd::serialize( Util::IOSSerialize& se ) +{ + bool result=true; + + if (m_type == eCT_Get) { + // the length should be specified before + // the header is serialized + m_length=EFC_HEADER_LENGTH_QUADLETS+2; + + result &= EfcCmd::serialize ( se ); + + result &= se.write(htonl(m_input), "Input" ); + result &= se.write(htonl(m_output), "Output" ); + + } else { + // the length should be specified before + // the header is serialized + m_length=EFC_HEADER_LENGTH_QUADLETS+3; + + result &= EfcCmd::serialize ( se ); + + result &= se.write(htonl(m_input), "Input" ); + result &= se.write(htonl(m_output), "Output" ); + result &= se.write(htonl(m_value), "Value" ); + } + return result; +} + +bool +EfcGenericMonitorCmd::deserialize( Util::IISDeserialize& de ) +{ + bool result=true; + + result &= EfcCmd::deserialize ( de ); + + EFC_DESERIALIZE_AND_SWAP(de, (quadlet_t *)&m_input, result); + EFC_DESERIALIZE_AND_SWAP(de, (quadlet_t *)&m_output, result); + EFC_DESERIALIZE_AND_SWAP(de, &m_value, result); + + return result; +} + +void +EfcGenericMonitorCmd::showEfcCmd() +{ + EfcCmd::showEfcCmd(); + debugOutput(DEBUG_LEVEL_NORMAL, "EFC %s MONITOR %s:\n", + (m_type==eCT_Get?"GET":"SET"), + eMonitorCommandToString(m_command)); + debugOutput(DEBUG_LEVEL_NORMAL, " Input : %ld\n", m_input); + debugOutput(DEBUG_LEVEL_NORMAL, " Output : %ld\n", m_output); + debugOutput(DEBUG_LEVEL_NORMAL, " Value : %lu\n", m_value); +} + +// --- The specific commands + + + +} // namespace FireWorks Index: /trunk/libffado/src/fireworks/efc/efc_cmds_mixer.h =================================================================== --- /trunk/libffado/src/fireworks/efc/efc_cmds_mixer.h (revision 663) +++ /trunk/libffado/src/fireworks/efc/efc_cmds_mixer.h (revision 663) @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2007 by Pieter Palmers + * + * This file is part of FFADO + * FFADO = Free Firewire (pro-)audio drivers for linux + * + * FFADO is based upon FreeBoB + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation; + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef FIREWORKS_EFC_CMD_MIXER_H +#define FIREWORKS_EFC_CMD_MIXER_H + +#include "efc_cmd.h" + +namespace FireWorks { + +enum eMixerTarget { + eMT_PhysicalOutputMix, + eMT_PhysicalInputMix, + eMT_PlaybackMix, + eMT_RecordMix, +}; +enum eMixerCommand { + eMC_Gain, + eMC_Solo, + eMC_Mute, + eMC_Pan, + eMC_Nominal, +}; + +class EfcGenericMixerCmd : public EfcCmd +{ +public: + enum eCmdType { + eCT_Get, + eCT_Set, + }; +public: + EfcGenericMixerCmd(enum eCmdType, enum eMixerTarget, enum eMixerCommand); + virtual ~EfcGenericMixerCmd() {}; + + virtual bool serialize( Util::IOSSerialize& se ); + virtual bool deserialize( Util::IISDeserialize& de ); + + virtual void showEfcCmd(); + + int32_t m_channel; + uint32_t m_value; + +private: + enum eCmdType m_type; + enum eMixerTarget m_target; + enum eMixerCommand m_command; +}; + +// --- Specific implementations +class EfcGetGainCmd : public EfcGenericMixerCmd +{ +public: + EfcGetGainCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Get, t, eMC_Gain) {}; + virtual ~EfcGetGainCmd() {}; + + virtual const char* getCmdName() const + { return "EfcGetGainCmd"; } +}; +class EfcSetGainCmd : public EfcGenericMixerCmd +{ +public: + EfcSetGainCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Set, t, eMC_Gain) {}; + virtual ~EfcSetGainCmd() {}; + + virtual const char* getCmdName() const + { return "EfcSetGainCmd"; } +}; + +class EfcGetSoloCmd : public EfcGenericMixerCmd +{ +public: + EfcGetSoloCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Get, t, eMC_Solo) {}; + virtual ~EfcGetSoloCmd() {}; + + virtual const char* getCmdName() const + { return "EfcGetSoloCmd"; } +}; +class EfcSetSoloCmd : public EfcGenericMixerCmd +{ +public: + EfcSetSoloCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Set, t, eMC_Solo) {}; + virtual ~EfcSetSoloCmd() {}; + + virtual const char* getCmdName() const + { return "EfcSetSoloCmd"; } +}; + +class EfcGetMuteCmd : public EfcGenericMixerCmd +{ +public: + EfcGetMuteCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Get, t, eMC_Mute) {}; + virtual ~EfcGetMuteCmd() {}; + + virtual const char* getCmdName() const + { return "EfcGetMuteCmd"; } +}; +class EfcSetMuteCmd : public EfcGenericMixerCmd +{ +public: + EfcSetMuteCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Set, t, eMC_Mute) {}; + virtual ~EfcSetMuteCmd() {}; + + virtual const char* getCmdName() const + { return "EfcSetMuteCmd"; } +}; + +class EfcGetPanCmd : public EfcGenericMixerCmd +{ +public: + EfcGetPanCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Get, t, eMC_Pan) {}; + virtual ~EfcGetPanCmd() {}; + + virtual const char* getCmdName() const + { return "EfcGetPanCmd"; } +}; +class EfcSetPanCmd : public EfcGenericMixerCmd +{ +public: + EfcSetPanCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Set, t, eMC_Pan) {}; + virtual ~EfcSetPanCmd() {}; + + virtual const char* getCmdName() const + { return "EfcSetPanCmd"; } +}; + +class EfcGetNominalCmd : public EfcGenericMixerCmd +{ +public: + EfcGetNominalCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Get, t, eMC_Nominal) {}; + virtual ~EfcGetNominalCmd() {}; + + virtual const char* getCmdName() const + { return "EfcGetNominalCmd"; } +}; +class EfcSetNominalCmd : public EfcGenericMixerCmd +{ +public: + EfcSetNominalCmd(enum eMixerTarget t) + : EfcGenericMixerCmd(eCT_Set, t, eMC_Nominal) {}; + virtual ~EfcSetNominalCmd() {}; + + virtual const char* getCmdName() const + { return "EfcSetNominalCmd"; } +}; + +} // namespace FireWorks + +#endif // FIREWORKS_EFC_CMD_MIXER_H