📄 generaterpc.pl
字号:
#!/usr/bin/perl -w# "Copyright (c) 2000-2003 The Regents of the University of California. # All rights reserved.## Permission to use, copy, modify, and distribute this software and its# documentation for any purpose, without fee, and without written agreement# is hereby granted, provided that the above copyright notice, the following# two paragraphs and the author appear in all copies of this software.# # IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# # THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."## @author Kamin Whitehouse #use XML::Simple;use strict;use FindBin;use lib $FindBin::Bin;use AtTags;use NescParser;my $DestDir = "";my $useLeds = 0;#get rid of extraneous argumentsmy @args = @ARGV;@ARGV = ();while (@args){ my $arg = shift @args; if ($arg eq "-DRPC_LEDS"){ $useLeds = 1; } elsif ($arg eq "-d") { $DestDir = shift @args; $DestDir .= "/" unless $arg =~ m{/$}; } elsif ($arg !~ m/^-[^I]/) { push @ARGV, $arg; }}#}#add a few more directories that should always be on the search pathunshift ( @ARGV, "-I".$ENV{'TOSDIR'}."/types/" );unshift ( @ARGV, "-I".$ENV{'TOSDIR'}."/interfaces/" );unshift ( @ARGV, "-I".$ENV{'TOSDIR'}."/system/" );unshift ( @ARGV, "-I".$ENV{'PWD'}."/" );#make sure the user knows what's going on:my $s = "generateRpc.pl ";for my $arg (@ARGV) { $s = sprintf "%s %s", $s, $arg;}print $s, "\n";my $nescXml = pop(@ARGV);############################### look through the @rpc tags to find all unique rpc instances##############################my ($taggedInterfaces, $includes) = AtTags::getTaggedInterfaces(@ARGV, "rpc", ());my ($taggedFunctions, $includesB) = AtTags::getTaggedFunctions(@ARGV, "rpc", ());for my $include (keys %$includesB){ $includes->{$include} = 1;}############################### look through the code and get definitions of all interfaces##############################my $interfaces = NescParser::getInterfaces($nescXml);############################### load the struct definitions ###############################my $structs = NescParser::getStructs($nescXml);#print "there are %d structs\n\n",scalar keys %$structs;############################### go through all tagged interfaces and functions and come up with# complete list of rpc functions## The desired structure is the following, and will be used to create# rpc.schema ## %rpcFunctions--->fullName--->commandNumber# |->componentName# |->interfaceName# |->functionName# |->provided# |->functionType# |->returnType# |->%params## where "fullName" is either moduleM.interface.func or moduleM.func.## while creating this structure, we also check the validity criteria below:##############################my %rpcFunctions;my %requiredFunctions;my $fullName;my $shouldDie=0;# add each tagged functionfor my $taggedFunction (@$taggedFunctions){ $fullName = $taggedFunction->{'componentName'}.".".$taggedFunction->{'functionName'}; checkRpcFunction($taggedFunction, $fullName); $rpcFunctions{$fullName} = $taggedFunction;}# add each function in each tagged interfacefor my $taggedInterface (@$taggedInterfaces){ my $interface; my $functions; if ($interfaces->{$taggedInterface->{'interfaceType'}}){ $interface = $interfaces->{$taggedInterface->{'interfaceType'}}; $functions = $interface->{'functions'}; } else{ print "WARNING: rpc interface $taggedInterface->{'interfaceType'} not found."; } while (my ($functionName, $function) = each (%$functions) ){ my %rpc; $rpc{'componentName'} = $taggedInterface->{'componentName'}; $rpc{'interfaceType'} = $taggedInterface->{'interfaceType'}; $rpc{'interfaceName'} = $taggedInterface->{'interfaceName'}; $rpc{'functionName'} = $functionName; $rpc{'provided'} = $taggedInterface->{'provided'}; $rpc{'functionType'} = $function->{'functionType'}; $rpc{'returnType'} = $function->{'returnType'}; $rpc{'params'} = $function->{'params'}; if ($interface->{'abstract'}==1){ $rpc{'gparams'} = $taggedInterface->{'gparams'}; $rpc{'returnType'} = &substituteAbstractTypes($rpc{'returnType'}, $interface->{'gparams'}, $taggedInterface->{'gparams'}); $rpc{'params'} = &substituteAbstractParams($rpc{'params'}, $interface->{'gparams'}, $taggedInterface->{'gparams'}); } $rpc{'numParams'} = $function->{'numParams'}; $fullName = $rpc{'componentName'}.".".$rpc{'interfaceName'}.".".$rpc{'functionName'}; if (checkRpcFunction(\%rpc, $fullName)){ $requiredFunctions{$fullName} = \%rpc; } else{ $rpcFunctions{$fullName} = \%rpc; } }} #The following variable is set in the checkRpcFunction subroutine.#We wait until after all functions are checked before dieing so that#we can get all error messages at onceif ($shouldDie == 1) { die "Too many errors.";} ############################### Number the rpc functions alphabetically##############################my $count = 0;my $rpc;for $fullName (sort keys %rpcFunctions ) { $rpc = $rpcFunctions{$fullName}; $rpc->{'commandID'} = $count++;}############################### print out the parsed info for debugging/user knowledge.# Simultaneously, generate each rpc function signature.##############################my $params;my $bspace = sprintf "\b";if (keys %rpcFunctions){ $s = "Adding rpc functions:\n"; for $fullName (sort keys %rpcFunctions ) { $rpc = $rpcFunctions{$fullName}; my $signature = sprintf "%25s %s ( ", "$rpc->{'functionType'} $rpc->{'returnType'}->{'typeDecl'}", $fullName; my $sigLength = length($signature); $params = $rpc->{'params'}; for ($count=0; $count < $rpc->{'numParams'} ; $count++,) { if ($count>0){ $signature .= sprintf "\n%${sigLength}s%s,","", $params->{"param$count"}->{'type'}->{'typeDecl'}." ".$params->{"param$count"}->{'name'}; } else{ $signature .= sprintf "%s %s,", $params->{"param$count"}->{'type'}->{'typeDecl'}, $params->{"param$count"}->{'name'}; } } $signature .= sprintf "\b )\n"; $s .= $signature; $signature =~ s/\s+/ /g; $signature =~ s/.$bspace/ /g; $rpc->{'signature'} = $signature; } print "$s\n"; }else{ print "** Warning: no RPC functions found.\n\n"; } ############################### print out in XML format for the PC-side tools##############################my $xs1 = XML::Simple->new();my %xmlOutHash = ();$xmlOutHash{'rpcFunctions'} = \%rpcFunctions;my %tmpHash = ();#$tmpHash{'struct'} = $structs;#$xmlOutHash{'structs'} = \%tmpHash;my $str = $xs1->XMLout(\%xmlOutHash, RootName=>"rpcSchema", KeyAttr=>{'attribute'=>'name', 'event'=>'name', 'symbol'=>'name'}, XMLDecl=>1);SlurpFile::dump_file( "${DestDir}rpcSchema.xml", "$str" );############################### Create a warning at the top of each generated file##############################my $G_warning =<< 'EOF';// *** WARNING ****** WARNING ****** WARNING ****** WARNING ****** WARNING ***// *** ***// *** This file was automatically generated by generateRpc.pl. ***// *** Any and all changes made to this file WILL BE LOST! ***// *** ***// *** WARNING ****** WARNING ****** WARNING ****** WARNING ****** WARNING ***EOFmy $yellowToggle = "";my $greenToggle = "";my $redToggle = "";my $Leds = "";my $LedsC = "";my $ledsWiring = "";if ($useLeds) { $yellowToggle = "call Leds.yellowToggle();"; $greenToggle = "call Leds.greenToggle();"; $redToggle = "call Leds.redToggle();"; $Leds = "interface Leds;"; $LedsC = "LedsC,"; $ledsWiring = "RpcM.Leds -> LedsC;"}############################### Generate the RpcM.nc file##############################$includes->{'includes Drain;'}=1;$includes->{'includes Rpc;'}=1;$s = "";for my $include (keys %$includes){ $s .= "$include\n";}$s .= "module RpcM { provides { interface StdControl; /*** events that are rpc-able ***/";my $componentName="";my $interfaceName="";my $gparams = "";# generate the "provides" declarations of rpc-able eventsfor $fullName (sort keys %rpcFunctions ) { $rpc = $rpcFunctions{$fullName}; if ($rpc->{'provided'} == 1){ next; } if ($rpc->{'interfaceName'}){ if ( $componentName ne $rpc->{'componentName'} || $interfaceName ne $rpc->{'interfaceName'} ) { $componentName = $rpc->{'componentName'}; $interfaceName = $rpc->{'interfaceName'}; $gparams = ""; if ($rpc->{'gparams'}){ $gparams = "<"; for my $gparam (@{$rpc->{'gparams'}}) { $gparams .= $gparam; } $gparams .= ">"; } $s = sprintf "%s interface $rpc->{'interfaceType'}$gparams as $componentName\_$interfaceName;\n", $s; } } else{ print keys %$rpc; $params = $rpc->{'params'}; $s = sprintf "%s $rpc->{'functionType'} $rpc->{'returnType'}->{'typeDecl'} $rpc->{'componentName'}_$rpc->{'functionName'} ( ", $s; for ($count=0; $count < $rpc->{'numParams'} ; $count++) { $s = sprintf "%s %s %s,", $s, $params->{"param$count"}->{'type'}->{'typeDecl'}, $params->{"param$count"}->{'name'}; } $s = sprintf "%s\b );\n", $s; }}$s = sprintf "%s } uses { interface StdControl as SubControl; $Leds interface ReceiveMsg as CommandReceiveLocal; interface SendMsg as ResponseSendMsgDrain;// interface SendMsg as ErrorSendMsgDrain; interface Send as DrainSend; interface Receive as CommandReceiveDrip; interface Drip as CommandDrip; interface Dest; /*** commands that are rpc-able ***/", $s;# generate the "uses" declarations of rpc-able commandsfor $fullName (sort keys %rpcFunctions ) { $rpc = $rpcFunctions{$fullName}; if ($rpc->{'provided'} == 0){ next; } if ($rpc->{'interfaceName'}){ if ( $componentName ne $rpc->{'componentName'} || $interfaceName ne $rpc->{'interfaceName'} ) { $gparams = ""; if ($rpc->{'gparams'}){ $gparams = "<"; for my $gparam (@{$rpc->{'gparams'}}) { $gparams .= $gparam; } $gparams .= ">"; } $componentName = $rpc->{'componentName'}; $interfaceName = $rpc->{'interfaceName'}; $s = sprintf "%s interface $rpc->{'interfaceType'}$gparams as $componentName\_$interfaceName;\n", $s; } } else{ $params = $rpc->{'params'}; $s = sprintf "%s $rpc->{'functionType'} $rpc->{'returnType'}->{'typeDecl'} $rpc->{'componentName'}_$rpc->{'functionName'} ( ", $s; for ($count=0; $count < $rpc->{'numParams'} ; $count++) { $s = sprintf "%s %s %s,", $s, $params->{"param$count"}->{'type'}->{'typeDecl'}, $params->{"param$count"}->{'name'}; } $s = sprintf "%s\b );\n", $s; }}# build lists of the arguments and return sizesmy $num_rpcs = keys %rpcFunctions;my @rpc_args_sizes = ();my @rpc_return_sizes = ();for $fullName (sort keys %rpcFunctions) { $rpc = $rpcFunctions{$fullName}; my @as = (); for( my $n=0; $n < $rpc->{numParams} ; $n++ ) { my $p = $rpc->{params}{"param$n"}{type}{typeName}; push( @as, "sizeof($p)" ); } push( @rpc_args_sizes, join("+",@as) || "0" ); push( @rpc_return_sizes, "sizeof($rpc->{returnType}{typeName})" );}my $rpc_args_elems = " " . join( ",\n ", @rpc_args_sizes );my $rpc_return_elems = " " . join( ",\n ", @rpc_return_sizes );my $d = '%d';$s .=<<"EOF"; }}implementation { TOS_Msg dripStore; TOS_Msg cmdStore; TOS_Msg responseMsgBuf; TOS_MsgPtr responseMsgPtr; uint16_t dripStoreLength; uint16_t cmdStoreLength; uint16_t queryID; uint16_t returnAddress; bool processingCommand; bool sendingResponse; static const uint8_t args_sizes[$num_rpcs] = {$rpc_args_elems }; static const uint8_t return_sizes[$num_rpcs] = {$rpc_return_elems }; command result_t StdControl.init() { responseMsgPtr = &responseMsgBuf; processingCommand=FALSE; sendingResponse=FALSE; call SubControl.init(); return SUCCESS; } command result_t StdControl.start() { call SubControl.start(); call CommandDrip.init(); return SUCCESS; } command result_t StdControl.stop() { return SUCCESS; } task void processCommand(){ RpcCommandMsg* msg = (RpcCommandMsg*)cmdStore.data; uint8_t* byteSrc = msg->data; uint16_t maxLength; uint16_t id = msg->commandID; RpcResponseMsg *responseMsg = (RpcResponseMsg*)call DrainSend.getBuffer(responseMsgPtr, &maxLength); dbg(DBG_USR2, "processing command id %d, transaction %d\\n", msg->commandID, msg->transactionID);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -