User Manual, Developers Guide and API Documentation

How to implement a FunctionalUnit

Providing a custom PCI.

FunctionalUnits in the WNS are the componets of a FUN. Several functionalUnits arranged and connected together become the FUN (see also LayerPage). Usually a functionalUnit needs to send functionalUnit specific information like sequence numbers to its counterpart it is communicating with. This is performed by embedding information in the Command of the functionalUnit. Every FUN holds a CommandProxy, which is the common access point of a CommandPool, which is literally the PCI of the Layer. Every functionalUnit that is derived from the CommandTypeSpecifier may ask the CommandProxy to activate its Command entry in the CommandPool and access functionalUnit specific data in the Command.

To define a custom functionalUnit we declare our custom Command that we will use later for our functionalUnit.


class FunkyCommand :
    public Command
{
public:
    FunkyCommand()
    {
        local.somethingFunky = 23;
        local.destructorCalled = NULL;
    }

    ~FunkyCommand()
    {
        if(NULL != local.destructorCalled)
            *local.destructorCalled = true;
    }

    virtual Bit getSize() const
    {
        return FUNKY_LENGTH;
    }

    struct {
        long somethingFunky;
        long *destructorCalled;
    } local;
    struct {} peer;
    struct {} magic;
};

In this example the Command contains two members: somethingFunky and a pointer to a long, destructorCalled. Further a constructor, a destructor and the assignment operator are declared and defined. The getSize() method returns the size of the Command.

This FunkyCommand shall be the Command that is handled by the FunkyFunctionalUnit:

class FunkyFunctionalUnit :
    public virtual FunctionalUnit,
    public CommandTypeSpecifier<FunkyCommand>,
    public HasReceptor<>,
    public HasConnector<>,
    public HasDeliverer<>,
    public Cloneable<FunkyFunctionalUnit>
{
public:
    FunkyFunctionalUnit(fun::FUN* fuNet) :
            CommandTypeSpecifier<FunkyCommand>(fuNet),
            HasReceptor<>(),
            HasConnector<>(),
            HasDeliverer<>(),
            Cloneable<FunkyFunctionalUnit>(),

            destructorCalled(false)
    {}

    long foo(CommandPool* commandPool)
    {
        FunkyCommand* command = activateCommand(commandPool);

        command->local.destructorCalled = &destructorCalled;
        return command->local.somethingFunky;
    }

    long bar(CommandPool* commandPool)
    {
        FunkyCommand* command = getCommand(commandPool);

        command->local.destructorCalled = &destructorCalled;
        return command->local.somethingFunky;
    }

    long destructorCalled;

    void doOnData(const CompoundPtr&)
    {}

    void doSendData(const CompoundPtr&)
    {}

private:
    // CompoundHandlerInterface
    bool doIsAccepting(const CompoundPtr&) const
    {
        return true;
    }

    void doWakeup()
    {}
};

The FunkyFunctionalUnit is derived from the CommandTypeSpecifier and the functionalUnit has to handle FunkyCommands. Like almost all functionalUnits the FunkyFunctionalUnit has an upper and a lower interface. Incoming and outgoing Compounds are handled by the methods doOnData() and doSendData(), respectively. Here you have the possibility to alter the Compound and especially the previously defined FunkyCommand. This is the place to write or read custom data like sequence numbers. At the end of the doOnData() method the Compound is given to the next higher functionalUnit by calling its doOnData(). Resepctively downgoing packets are given to the next lower functionalUnit by calling doSendData() of the next lower functionalUnit. To learn more about interacting functionalUnits see LayerPage.

The wakeup() method is called by lower functionalUnits if they are able to receive new compounds from higher functionalUnits. This is only the case if the lower functionalUnit is able to block the packet flow. Finally the isAccepting() method is called immediately before a new PDU arrives at the doSendData() method. Here the functionalUnit is able to block the packet flow.

Choosing alternative interfaces.

In many cases functionalUnits have similar functions. Therefore a set of functionalUnits is already defined that provides a framework that limits your implementation to the essential operations of your functionalUnit. Before implementing a FunctionalUnit, you may choose from a set of interfaces that matches the behaviour of your FunctionalUnit best.

There are currently three different interfaces to choose from:

Use the Processor interface, whenever your FunctionalUnit has no internal storage for compounds, performs mutation only and forwards compounds without delay.

Use the Delayed interface, whenever your FunctionalUnit has internal storage, wants to inject new compounds into the FunctionalUnit stack or wants to drop compounds.

Note:
When starting to work with functional units, you usually will not need to implement the CompoundHandlerInterface directly. Internally, Processor and Delayed are only adaptors, that implement the CompoundHandlerInterface for you. Especially the burden of implementing intra-FUN flow control is relieved from you.
For a documentation of the methods to implement for each of the interfaces, have a look at PDU Handler.

Participating in size calculations.

Todo:
documentation on how to influence size calculation

Creating a reply.

Todo:
documentation on how to create replies

Generated on Wed Feb 8 03:32:25 2012 for openWNS by  doxygen 1.5.5