# Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description:
# Functions for generating CHCICommandBase derived classes.
# Attempts to fill in provided file templates with values deduced from the
# command name and command parameters.
# Template substitutions are:
# $CLASSNAME: CNameOfCommand, where NameOfCommand is given as parameter.
# $FILENAME: namofcommand, lower case version of NameOfCommand. Used when substituting filename.
# $HEADERGUARD: NAMEOFCOMMAND, upper case version of NameOfCommand. Used as header guard define.
# $PARAMETERS: Type1 aParam1, Type2 aParam2, etc. List of parameters. Used in NewL and constructor definitions and implementations.
# $MEMBERS: Type1 iParam1; Type2 iParam2; etc. Class member declarations.
# $NEWL_DEFINITIONS: static $CLASSNAME NewL(); and if parameter count > 0, static $CLASSNAME NewL($PARAMETERS);. NewL definitions.
# $NEWL_IMPLEMENTATIONS: Implementations of the NewLs.
# $CONSTRUCTOR_DEFINITION: Constructor definition. A class always has a default constructor.
# $CONSTRUCTOR_IMPLEMENTATION: Constructor implementation.
# $DESTRUCTOR_IMPLEMENTATION: Destructor implementation.
# $WRITE_FRAME: Code to write command data to a CHctlCommandFrame.
# $COMMANDFRAME: Comments out CHctlCommandFrame parameter of the WriteFrame method of commands that have no data. This to avoid compiler warnings.
# $MEMBER_ASSIGNMENT: iParam1 = aParam1; For Reset implementation.
# $ACCESSOR_DEFINITIONS: Type1 Param1(); Parameter getter method definition.
# $ACCESSOR_IMPLEMENTATION: Type1 $CLASSNAME::Param1() { return iParam1; }. Parameter getter method implementation.
# $EVENT_MATCH_DEFINITIONS: Definition of the event matching methods
# $EVENT_MATCH_IMPLEMENTATIONS: Implementations of the event matching methods
# $EVENT_MATCH_INCLUDES: System includes required by event matching methods
# $GENERATE_TIME_STAMP: timestamp showing when the generator produced the file
# $PRAGMA_HW_VOICE_SETTING_ADVICE: Write pragma lines for commands setupsynchronousconnection and writevoicesetting
#
#
import re
import string
from parameter import makeParameters, makeMembers
from time import strftime
from utils import doTimeStampCompareAndWrite
# makes the aParam part of constructor
def makeConstructorParameters(aParams):
ctor_str = ""
for p in aParams:
ctor_str += 'a' + p.getName() + ', '
return ctor_str[:-2]
# makes member initialization part of constructor
def makeMemberInitialization(aParams):
init_str = ", "
for p in aParams:
init_str += 'i' + p.getName() + '(a' + p.getName() + ')\n\t, '
return init_str[:-4]
# makes class NewL definition
def makeNewLDefinitions(aParams, aClass):
def_str = ''
if len(aParams) > 0:
def_str += 'IMPORT_C static C' + aClass + '* NewL(' + makeParameters(aParams) +');\n\t'
return def_str + 'IMPORT_C static C' + aClass +'* NewL();'
def makeNewLImp(aClass, aParamString, aConsParamString):
imp_str = ''
imp_str += 'EXPORT_C C' + aClass + '* C' + aClass + '::NewL(' + aParamString + ')\n\t{\n\t'
imp_str += 'C' + aClass + '* self = new (ELeave) C' + aClass + '(' + aConsParamString + ');\n\t'
imp_str += 'CleanupStack::PushL(self);\n\t'
imp_str += 'self->CHCICommandBase::BaseConstructL();\n\t'
imp_str += 'CleanupStack::Pop(self);\n\t'
imp_str += 'return self;\n\t}'
return imp_str
# makes class NewL implementation
def makeNewLImplementations(aParams, aClass):
imp_str = ''
if len(aParams) > 0:
imp_str += makeNewLImp(aClass, makeParameters(aParams), makeConstructorParameters(aParams))
imp_str += '\n\n'
imp_str += makeNewLImp(aClass, '', '')
return imp_str
# makes class constructor definition
def makeConstructorDefinitions(aParams, aClass):
def_str = ''
if len(aParams) > 0:
def_str += 'C' + aClass + '(' + makeParameters(aParams) + ');\n\t'
return def_str + 'C' + aClass + '();'
# makes class constructor implementation
def makeConstructorImplementations(aParams, aClass, aMatchParams):
imp_str = ''
CreditsConsumed = aMatchParams[0]
ExpCmdStatus = aMatchParams[1]
ExpCmdComplete = aMatchParams[2]
if len(aParams) > 0:
imp_str += 'C' + aClass + 'Command::C' + aClass + 'Command(' + makeParameters(aParams) + ')\n\t: CHCICommandBase(K' + aClass + 'Opcode)\n\t' + makeMemberInitialization(aParams) + '\n\t{\n\t'
if int(CreditsConsumed) != 1:
imp_str += 'SetCreditsConsumed(' + str(CreditsConsumed) + ');\n\t'
if ExpCmdStatus == 'False':
imp_str += 'SetExpectsCommandStatusEvent(EFalse);\n\t'
if ExpCmdComplete == 'False':
imp_str += 'SetExpectsCommandCompleteEvent(EFalse);\n\t'
imp_str += '}\n\n'
imp_str += 'C' + aClass + 'Command::C' + aClass + 'Command()\n\t: CHCICommandBase(K' + aClass + 'Opcode)\n\t{\n\t'
if int(CreditsConsumed) != 1:
imp_str += 'SetCreditsConsumed(' + str(CreditsConsumed) + ');\n\t'
if ExpCmdStatus == 'False':
imp_str += 'SetExpectsCommandStatusEvent(EFalse);\n\t'
if ExpCmdComplete == 'False':
imp_str += 'SetExpectsCommandCompleteEvent(EFalse);\n\t'
imp_str += '}'
return imp_str
def makeDestructorImplementation(aParams):
imp_str = ''
# We only need to close arrays
for p in aParams:
if p.iArray != '':
imp_str += 'i' + p.getName() + '.Close();\n\t'
return imp_str[0:-2]
# makes code that write command data to CHctlCommandFrame
def makeWriteFrame(aParams):
## (the parameter length is now output by the base class)
frame_str = ''
## Write the functions to set the data for the parameters
## If there are multiple array parameters then they are ordered like an
## array of structures, see BT Spec 2.0 Vol 2 Part E 5.2. The logic below allows
## for multiple such arrays of structures based on sets of consecutive parameters
## sharing the same array bound - however this is not really needed since no current
## event has more than one array.
firstOne = True
currentArray = None
for p in aParams:
if not p.iNotInFrame:
if not firstOne:
frame_str += '\n\t'
else:
firstOne = False
if p.iArray:
if currentArray != p.iArray:
if currentArray != None:
# end the previous array loop (actually, this is never needed)
frame_str += '\t}\n\t'
currentArray = None
# start the new array loop
currentArray = p.iArray # remember we're doing this array
frame_str += 'for(int i=0;i<i' + p.iArray + ';++i)\n\t\t{\n\t'
# continue generating the array
frame_str += '\taCommandFrame.' + p.iType.iSetter + '(' + p.setterParams('i') + ');'
else:
if currentArray != None:
# finish off the array we were doing (won't actually happen, arrays always come last really)
frame_str += '\t}\n\t'
frame_str += 'aCommandFrame.' + p.iType.iSetter + '(' + p.setterParams() + ');'
if currentArray != None:
frame_str += '\n\t\t}'
return frame_str
# if we do not have command data comment out parameter to avoid compiler warnings
def makeCommandFrame(aParams):
if len(aParams) > 0:
return 'CHctlCommandFrame& aCommandFrame'
else:
return 'CHctlCommandFrame& /*aCommandFrame*/'
# generates code block of form iParam = aParam;
def makeMemberAssignment(aParams):
ass_str = ''
for p in aParams:
ass_str += p.memberAssignment() + '\n\t'
return ass_str[:-2]
# make getter definition of form Param()
def makeAccessorDefinitions(aParams):
def_str = ''
for p in aParams:
def_str += p.accessorDef('Command') + '\n\t'
return def_str[:-2]
# make getter implementation
def makeAccessorImplementations(aParams, aClass):
imp_str = ''
for p in aParams:
imp_str += p.commandAccessorImpl(aClass)
return imp_str
def zsafe_codeEventMatch(aMatchParams, aFirstTime):
code_str = ''
code_str += '\n'
for p in aMatchParams[:]:
code_str += p + '\n'
return code_str
#make event match
def codeEventMatch(aMatchParams, aFirstTime):
code_str = ''
eventName = aMatchParams[0]
concludesCmd = aMatchParams[1]
continueMatching = aMatchParams[2]
if not aFirstTime:
code_str += 'else '
code_str += 'if (aEvent.EventCode() == ' 'E' + eventName +')\n\t\t'
code_str += '{\n\t\t'
if len(aMatchParams) > 3:
matchOperands = aMatchParams[3:]
if eventName == 'CommandCompleteEvent':
code_str += 'THCI' + eventName + '& event = THCI' + eventName + '::Cast(aEvent);\n\t\t'
else:
code_str += 'T' + eventName + '& event = T' + eventName + '::Cast(aEvent);\n\t\t'
if len(matchOperands) > 1:
code_str += 'if ('
else:
code_str += 'if '
i = 0
while i < len(matchOperands):
operands = string.split(matchOperands[i],'_')
if len(operands) == 1:
code_str += '(event.' + operands[0] + '() == ' + operands[0] + '())'
else:
code_str += '(event.' + operands[0] + '() == ' + operands[1]
if len(operands) > 2:
code_str += '()' # kludge: trailing _ means we need a function call syntax
code_str += ')'
i += 1
if i < len(matchOperands):
code_str += ' && '
if len(matchOperands) > 1:
code_str += ')\n\t\t\t'
else:
code_str += '\n\t\t\t'
code_str += '{\n\t\t\t'
code_str += 'aMatchesCmd = ETrue;\n\t\t\t'
code_str += 'aConcludesCmd = E' + concludesCmd + ';\n\t\t\t'
code_str += 'aContinueMatching = E' + continueMatching + ';\n\t\t\t'
code_str += '}\n\t\t'
else:
code_str += 'aMatchesCmd = ETrue;\n\t\t'
code_str += 'aConcludesCmd = E' + concludesCmd + ';\n\t\t'
code_str += 'aContinueMatching = E' + continueMatching + ';\n\t\t'
code_str += '}\n\t'
return code_str
#make event matching method definitions
def makeEventMatchDefinitions(aParams):
def_str = ''
Creditsconsumed = aParams[0]
ExpCmdStatus = aParams[1]
ExpCmdComplete = aParams[2]
if len(aParams) > 3 and 'Match' in aParams: # Always define a match function.
def_str += 'virtual void Match(const THCIEventBase& aEvent, TBool& aMatchesCmd, TBool& aConcludesCmd, TBool& aContinueMatching) const;\n\t'
return def_str
#make event matching method definitions
def makeEventMatchImplementations(aParams, aClass):
imp_str = ''
Creditsconsumed = aParams[0]
ExpCmdStatus = aParams[1]
ExpCmdComplete = aParams[2]
if len(aParams) > 3 and 'Match' in aParams:
imp_str += '/*virtual*/ void ' + 'C' + aClass + 'Command::Match(const THCIEventBase& aEvent, TBool& aMatchesCmd, TBool& aConcludesCmd, TBool& aContinueMatching) const\n\t'
imp_str += '{\n\t'
# Produce matching code specific to command
m = aParams.index('Match') + 1
firstTime = True
while ('Match' in aParams[m:]):
nm = m + aParams[m:].index('Match')
imp_str += codeEventMatch(aParams[m:nm], firstTime)
m = nm + 1
firstTime = False
else:
imp_str += codeEventMatch(aParams[m:], firstTime)
# Insert general matching code
imp_str += '// Command Status Event and default Command Complete Event matching\n\t'
imp_str += '// is implemented in the base class. If we haven\'t matched already\n\t'
imp_str += '// then we should try the default matching.\n\t'
imp_str += 'if (!aMatchesCmd)\n\t\t'
imp_str += '{\n\t\t'
imp_str += 'CHCICommandBase::Match(aEvent, aMatchesCmd, aConcludesCmd, aContinueMatching);\n\t\t'
imp_str += '}\n\t'
imp_str += '}\n\t'
return imp_str
#make event matching method definitions
def makeEventMatchIncludes(aParams):
inc_str = ''
remParams = aParams[:]
while ('Match' in remParams):
e = remParams.index('Match') + 1
eventName = remParams[e]
remParams = remParams[e:]
if eventName != 'CommandCompleteEvent':
inc_str += '#include <bluetooth/hci/' + string.lower(eventName) + '.h>\n'
return inc_str
# if command is setupsynchronousconnection or writevoicesetting write pragma lines
def makePragmaHwVoiceSettingAdvice(aCmd):
if aCmd == 'WriteVoiceSetting' or aCmd == 'SetupSynchronousConnection':
strPragma = '#pragma message("Value of iVoiceSetting member is closely related to hardware used. ")\n'
strPragma += '#pragma message("Bits: Input Coding, Input Data, Input Sample Size and Linear_PCM_Bit_pos, should be set...")\n'
strPragma += '#pragma message("...according to hardware capabilities, and OR-ed to create appropriate iVoiceSetting value.")'
return strPragma
return ''
def writeCommand(aCmd, aMatchData, aParams, aHeaderTemplate, aSourceTemplate, aHeaderPath, aSourcePath):
# separate by ,
matchParams = re.split(r'[^a-zA-Z_0-9\*]+', aMatchData);
# Make template values
c = {'COMMAND': aCmd, # plain command name
'CLASSNAME': 'C' + aCmd + 'Command', #CaCmd
'FILENAME': aCmd.lower() + 'command', # acmd
'HEADERGUARD': aCmd.upper() + 'COMMAND', # ACMD
'PARAMETERS': makeParameters(aParams), # aParam1, aParam2
'MEMBERS': makeMembers(aParams), # iParam1; iParam2
'NEWL_DEFINITIONS': makeNewLDefinitions(aParams, aCmd + 'Command'), # NewL($PARAMETERS)
'NEWL_IMPLEMENTATIONS': makeNewLImplementations(aParams, aCmd + 'Command'),
'CONSTRUCTOR_DEFINITIONS': makeConstructorDefinitions(aParams, aCmd + 'Command'),
'CONSTRUCTOR_IMPLEMENTATIONS': makeConstructorImplementations(aParams, aCmd, matchParams), # Don't add 'Command', aCmd is used to build K...Opcode
'DESTRUCTOR_IMPLEMENTATION': makeDestructorImplementation(aParams),
'WRITE_FRAME': makeWriteFrame(aParams),
'COMMANDFRAME': makeCommandFrame(aParams),
'MEMBER_ASSIGNMENT': makeMemberAssignment(aParams),
'ACCESSOR_DEFINITIONS': makeAccessorDefinitions(aParams),
'ACCESSOR_IMPLEMENTATIONS': makeAccessorImplementations(aParams, 'C' + aCmd + 'Command'),
'EVENT_MATCH_DEFINITIONS': makeEventMatchDefinitions(matchParams),
'EVENT_MATCH_IMPLEMENTATIONS': makeEventMatchImplementations(matchParams, aCmd),
'EVENT_MATCH_INCLUDES': makeEventMatchIncludes(matchParams),
'PRAGMA_HW_VOICE_SETTING_ADVICE': makePragmaHwVoiceSettingAdvice(aCmd),
'GENERATE_TIME_STAMP': strftime("%a, %d %b %Y %H:%M:%S") + ' (time stamp)'} # (time stamp) is needed for preventing unneccesary submissions.
# Fill in template
#file(aHeaderPath + '\\' + c['FILENAME'] + '.h', 'w+').write(aHeaderTemplate.substitute(c))
#file(aSourcePath + '\\' + c['FILENAME'] + '.cpp', 'w+').write(aSourceTemplate.substitute(c))
doTimeStampCompareAndWrite(aHeaderPath + '\\' + c['FILENAME'] + '.h', aHeaderTemplate.substitute(c))
doTimeStampCompareAndWrite(aSourcePath + '\\' + c['FILENAME'] + '.cpp', aSourceTemplate.substitute(c))