/*
* Copyright (C) 2005-2007 by Daniel Wagner
* Copyright (C) 2005-2007 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free Firewire (pro-)audio drivers for linux
*
* FFADO is based upon FreeBoB
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see .
*
*/
#include "avc_function_block.h"
#include "libutil/cmd_serialize.h"
#include "libieee1394/ieee1394service.h"
namespace AVC {
/////////////////////////////////
FunctionBlockFeatureVolume::FunctionBlockFeatureVolume()
: IBusData()
, m_controlDataLength( 2 )
, m_volume( 0 )
{
}
FunctionBlockFeatureVolume::FunctionBlockFeatureVolume( const FunctionBlockFeatureVolume& rhs )
: m_controlDataLength( rhs.m_controlDataLength )
, m_volume( rhs.m_volume )
{
}
FunctionBlockFeatureVolume::~FunctionBlockFeatureVolume()
{
}
bool
FunctionBlockFeatureVolume::serialize( Util::IOSSerialize& se )
{
bool bStatus;
byte_t val;
bStatus = se.write( m_controlDataLength, "FunctionBlockFeatureVolume controlDataLength" );
val = (byte_t)(m_volume >> 8);
bStatus &= se.write( val, "FunctionBlockFeatureVolume volume high" );
val = m_volume & 0xff;
bStatus &= se.write( val, "FunctionBlockFeatureVolume volume low" );
return bStatus;
}
bool
FunctionBlockFeatureVolume::deserialize( Util::IISDeserialize& de )
{
bool bStatus;
byte_t val;
bStatus = de.read( &m_controlDataLength );
bStatus &= de.read( &val );
m_volume = val << 8;
bStatus &= de.read( &val );
m_volume |= val;
return bStatus;
}
FunctionBlockFeatureVolume*
FunctionBlockFeatureVolume::clone() const
{
return new FunctionBlockFeatureVolume( *this );
}
/////////////////////////////////
FunctionBlockProcessingMixer::FunctionBlockProcessingMixer()
: IBusData()
, m_controlSelector( FunctionBlockProcessing::eCSE_Processing_Mixer )
{
}
FunctionBlockProcessingMixer::FunctionBlockProcessingMixer( const FunctionBlockProcessingMixer& rhs )
: m_controlSelector( rhs.m_controlSelector )
{
}
FunctionBlockProcessingMixer::~FunctionBlockProcessingMixer()
{
}
bool
FunctionBlockProcessingMixer::serialize( Util::IOSSerialize& se )
{
bool bStatus;
bStatus = se.write( m_controlSelector, "FunctionBlockProcessingMixer controlSelector" );
return bStatus;
}
bool
FunctionBlockProcessingMixer::deserialize( Util::IISDeserialize& de )
{
bool bStatus;
bStatus = de.read( &m_controlSelector );
return bStatus;
}
FunctionBlockProcessingMixer*
FunctionBlockProcessingMixer::clone() const
{
return new FunctionBlockProcessingMixer( *this );
}
/////////////////////////////////
FunctionBlockProcessingEnhancedMixer::FunctionBlockProcessingEnhancedMixer()
: IBusData()
, m_controlSelector( FunctionBlockProcessing::eCSE_Processing_EnhancedMixer )
, m_statusSelector( eSS_ProgramableState )
{
}
FunctionBlockProcessingEnhancedMixer::FunctionBlockProcessingEnhancedMixer(
const FunctionBlockProcessingEnhancedMixer& rhs )
: m_controlSelector( rhs.m_controlSelector )
, m_statusSelector( rhs.m_statusSelector )
{
}
FunctionBlockProcessingEnhancedMixer::~FunctionBlockProcessingEnhancedMixer()
{
}
bool
FunctionBlockProcessingEnhancedMixer::serialize( Util::IOSSerialize& se )
{
int todo,done;
bool bStatus;
byte_t data_length_hi, data_length_lo;
bStatus = se.write( m_controlSelector, "FunctionBlockProcessingEnhancedMixer controlSelector" );
bStatus &= se.write( m_statusSelector, "FunctionBlockProcessingEnhancedMixer statusSelector" );
switch (m_statusSelector) {
case eSS_ProgramableState:
m_controlDataLength=m_LevelData.size();
data_length_hi=(m_controlDataLength >> 8);
data_length_lo=(m_controlDataLength & 0xFF);
bStatus &= se.write( data_length_hi, "FunctionBlockProcessingEnhancedMixer controlDataLengthHi" );
bStatus &= se.write( data_length_lo, "FunctionBlockProcessingEnhancedMixer controlDataLengthLo" );
for (int i=0;i> 8);
data_length_lo=(m_controlDataLength & 0xFF);
bStatus &= se.write( data_length_hi, "FunctionBlockProcessingEnhancedMixer controlDataLengthHi" );
bStatus &= se.write( data_length_lo, "FunctionBlockProcessingEnhancedMixer controlDataLengthLo" );
for (int i=0;i> 8;
byte_t value_lo=value & 0xFF;
bStatus &= se.write( value_hi, "FunctionBlockProcessingEnhancedMixer data" );
bStatus &= se.write( value_lo, "FunctionBlockProcessingEnhancedMixer data" );
}
break;
}
return bStatus;
}
bool
FunctionBlockProcessingEnhancedMixer::deserialize( Util::IISDeserialize& de )
{
int todo;
bool bStatus=true;
bStatus = de.read( &m_controlSelector );
// NOTE: the returned value is currently bogus, so overwrite it
m_controlSelector=FunctionBlockProcessing::eCSE_Processing_EnhancedMixer;
bStatus &= de.read( &m_statusSelector );
byte_t data_length_hi;
byte_t data_length_lo;
bStatus &= de.read( &data_length_hi );
bStatus &= de.read( &data_length_lo );
m_controlDataLength = (data_length_hi << 8) + data_length_lo;
switch (m_statusSelector) {
case eSS_ProgramableState:
m_ProgramableStateData.clear();
for (int i=0;i=0;j--) {
byte_t bit_value;
bit_value=(((1<7-todo;j--) {
byte_t bit_value;
bit_value=(((1<serialize( se );
} else {
bStatus = false;
}
return bStatus;
}
bool
FunctionBlockFeature::deserialize( Util::IISDeserialize& de )
{
bool bStatus;
bStatus = de.read( &m_selectorLength );
bStatus &= de.read( &m_audioChannelNumber );
bStatus &= de.read( &m_controlSelector );
switch( m_controlSelector ) {
case eCSE_Feature_Volume:
bStatus &= m_pVolume->deserialize( de );
break;
case eCSE_Feature_Mute:
case eCSE_Feature_LRBalance:
case eCSE_Feature_FRBalance:
case eCSE_Feature_Bass:
case eCSE_Feature_Mid:
case eCSE_Feature_Treble:
case eCSE_Feature_GEQ:
case eCSE_Feature_AGC:
case eCSE_Feature_Delay:
case eCSE_Feature_BassBoost:
case eCSE_Feature_Loudness:
default:
bStatus = false;
}
return bStatus;
}
FunctionBlockFeature*
FunctionBlockFeature::clone() const
{
return new FunctionBlockFeature( *this );
}
/////////////////////////////////
FunctionBlockProcessing::FunctionBlockProcessing()
: IBusData()
, m_selectorLength( 0x04 )
, m_fbInputPlugNumber( 0x00 )
, m_inputAudioChannelNumber( 0x00 )
, m_outputAudioChannelNumber( 0x00 )
, m_pMixer( 0 )
, m_pEnhancedMixer( 0 )
{
}
FunctionBlockProcessing::FunctionBlockProcessing( const FunctionBlockProcessing& rhs )
: m_selectorLength( rhs.m_selectorLength )
, m_fbInputPlugNumber( rhs.m_fbInputPlugNumber )
, m_inputAudioChannelNumber( rhs.m_inputAudioChannelNumber )
, m_outputAudioChannelNumber( rhs.m_outputAudioChannelNumber )
{
if ( rhs.m_pMixer ) {
m_pMixer = new FunctionBlockProcessingMixer( *rhs.m_pMixer );
} else if ( rhs.m_pEnhancedMixer ) {
m_pEnhancedMixer = new FunctionBlockProcessingEnhancedMixer( *rhs.m_pEnhancedMixer );
}
}
FunctionBlockProcessing::~FunctionBlockProcessing()
{
delete m_pMixer;
m_pMixer = 0;
delete m_pEnhancedMixer;
m_pEnhancedMixer = 0;
}
bool
FunctionBlockProcessing::serialize( Util::IOSSerialize& se )
{
bool bStatus;
bStatus = se.write( m_selectorLength, "FunctionBlockProcessing selectorLength" );
bStatus &= se.write( m_fbInputPlugNumber, "FunctionBlockProcessing fbInputPlugNumber" );
bStatus &= se.write( m_inputAudioChannelNumber, "FunctionBlockProcessing inputAudioChannelNumber" );
bStatus &= se.write( m_outputAudioChannelNumber, "FunctionBlockProcessing outputAudioChannelNumber" );
if ( m_pMixer ) {
bStatus &= m_pMixer->serialize( se );
} else if ( m_pEnhancedMixer ) {
bStatus &= m_pEnhancedMixer->serialize( se );
} else {
bStatus = false;
}
return bStatus;
}
bool
FunctionBlockProcessing::deserialize( Util::IISDeserialize& de )
{
// NOTE: apparently the fbCmd of the STATUS type,
// with EnhancedMixer controlSelector returns with this
// controlSelector type changed to Mixer, making it
// impossible to choose the correct response handler
// based upon the response only.
// HACK: we assume that it is the same as the sent one
// we also look at our data structure to figure out what we sent
byte_t controlSelector=eCSE_Processing_Unknown;
if(m_pMixer) {
controlSelector=eCSE_Processing_Mixer;
} else if(m_pEnhancedMixer) {
controlSelector=eCSE_Processing_EnhancedMixer;
}
bool bStatus;
bStatus = de.read( &m_selectorLength );
bStatus &= de.read( &m_fbInputPlugNumber );
bStatus &= de.read( &m_inputAudioChannelNumber );
bStatus &= de.read( &m_outputAudioChannelNumber );
byte_t controlSelector_response;
bStatus &= de.peek( &controlSelector_response );
/* debugOutput(DEBUG_LEVEL_VERBOSE,"ctrlsel: orig = %02X, resp = %02X\n",
controlSelector, controlSelector_response);*/
switch( controlSelector ) {
case eCSE_Processing_Mixer:
if ( !m_pMixer ) {
m_pMixer = new FunctionBlockProcessingMixer;
}
bStatus &= m_pMixer->deserialize( de );
break;
case eCSE_Processing_EnhancedMixer:
if ( !m_pEnhancedMixer ) {
m_pEnhancedMixer = new FunctionBlockProcessingEnhancedMixer;
}
bStatus &= m_pEnhancedMixer->deserialize( de );
break;
case eCSE_Processing_Enable:
case eCSE_Processing_Mode:
default:
bStatus = false;
}
byte_t tmp;
if (de.peek(&tmp)) {
debugOutput(DEBUG_LEVEL_VERBOSE,"Unprocessed bytes:\n");
while (de.read(&tmp)) {
debugOutput(DEBUG_LEVEL_VERBOSE," %02X\n",tmp);
}
}
return bStatus;
}
FunctionBlockProcessing*
FunctionBlockProcessing::clone() const
{
return new FunctionBlockProcessing( *this );
}
/////////////////////////////////
FunctionBlockCodec::FunctionBlockCodec()
: IBusData()
{
}
FunctionBlockCodec::FunctionBlockCodec( const FunctionBlockCodec& rhs )
: IBusData()
{
}
FunctionBlockCodec::~FunctionBlockCodec()
{
}
bool
FunctionBlockCodec::serialize( Util::IOSSerialize& se )
{
return false;
}
bool
FunctionBlockCodec::deserialize( Util::IISDeserialize& de )
{
return false;
}
FunctionBlockCodec*
FunctionBlockCodec::clone() const
{
return new FunctionBlockCodec( *this );
}
/////////////////////////////////
/////////////////////////////////
FunctionBlockCmd::FunctionBlockCmd( Ieee1394Service& ieee1394service,
EFunctionBlockType eType,
function_block_id_t id,
EControlAttribute eCtrlAttrib )
: AVCCommand( ieee1394service, AVC1394_FUNCTION_BLOCK_CMD )
, m_functionBlockType( eType )
, m_functionBlockId( id )
, m_controlAttribute( eCtrlAttrib )
, m_pFBSelector( 0 )
, m_pFBFeature( 0 )
, m_pFBProcessing( 0 )
, m_pFBCodec( 0 )
{
setSubunitType( eST_Audio );
switch( m_functionBlockType ) {
case eFBT_Selector:
m_pFBSelector = new FunctionBlockSelector;
break;
case eFBT_Feature:
m_pFBFeature = new FunctionBlockFeature;
break;
case eFBT_Processing:
m_pFBProcessing = new FunctionBlockProcessing;
break;
case eFBT_Codec:
m_pFBCodec = new FunctionBlockCodec;
break;
}
}
FunctionBlockCmd::FunctionBlockCmd( const FunctionBlockCmd& rhs )
: AVCCommand( rhs )
, m_functionBlockType( rhs.m_functionBlockType )
, m_functionBlockId( rhs.m_functionBlockId )
, m_controlAttribute( rhs.m_controlAttribute )
, m_pFBSelector( new FunctionBlockSelector( *rhs.m_pFBSelector ) )
, m_pFBFeature( new FunctionBlockFeature( *rhs.m_pFBFeature ) )
, m_pFBProcessing( new FunctionBlockProcessing( *rhs.m_pFBProcessing ) )
, m_pFBCodec( new FunctionBlockCodec( *rhs.m_pFBCodec ) )
{
}
FunctionBlockCmd::~FunctionBlockCmd()
{
delete m_pFBSelector;
m_pFBSelector = 0;
delete m_pFBFeature;
m_pFBFeature = 0;
delete m_pFBProcessing;
m_pFBProcessing = 0;
delete m_pFBCodec;
m_pFBCodec = 0;
}
bool
FunctionBlockCmd::serialize( Util::IOSSerialize& se )
{
bool bStatus;
bStatus = AVCCommand::serialize( se );
bStatus &= se.write( m_functionBlockType, "FunctionBlockCmd functionBlockType" );
bStatus &= se.write( m_functionBlockId, "FunctionBlockCmd functionBlockId" );
bStatus &= se.write( m_controlAttribute, "FunctionBlockCmd controlAttribute" );
switch( m_functionBlockType ) {
case eFBT_Selector:
if ( m_pFBSelector ) {
bStatus &= m_pFBSelector->serialize( se );
} else {
bStatus = false;
}
break;
case eFBT_Feature:
if ( m_pFBFeature ) {
bStatus &= m_pFBFeature->serialize( se );
} else {
bStatus = false;
}
break;
case eFBT_Processing:
if ( m_pFBProcessing ) {
bStatus &= m_pFBProcessing->serialize( se );
} else {
bStatus = false;
}
break;
case eFBT_Codec:
if ( m_pFBCodec ) {
bStatus &= m_pFBCodec->serialize( se );
} else {
bStatus = false;
}
break;
default:
bStatus = false;
}
return bStatus;
}
bool
FunctionBlockCmd::deserialize( Util::IISDeserialize& de )
{
bool bStatus;
bStatus = AVCCommand::deserialize( de );
bStatus &= de.read( &m_functionBlockType );
bStatus &= de.read( &m_functionBlockId );
bStatus &= de.read( &m_controlAttribute );
switch( m_functionBlockType ) {
case eFBT_Selector:
if ( !m_pFBSelector ) {
m_pFBSelector = new FunctionBlockSelector;
}
bStatus &= m_pFBSelector->deserialize( de );
break;
case eFBT_Feature:
if ( !m_pFBFeature ) {
m_pFBFeature = new FunctionBlockFeature;
}
bStatus &= m_pFBFeature->deserialize( de );
break;
case eFBT_Processing:
if ( !m_pFBProcessing ) {
m_pFBProcessing = new FunctionBlockProcessing;
}
bStatus &= m_pFBProcessing->deserialize( de );
break;
case eFBT_Codec:
if ( !m_pFBCodec ) {
m_pFBCodec = new FunctionBlockCodec;
}
bStatus &= m_pFBCodec->deserialize( de );
break;
default:
bStatus = false;
}
return bStatus;
}
FunctionBlockCmd*
FunctionBlockCmd::clone() const
{
return new FunctionBlockCmd( *this );
}
}