blob: 9a25c22e2734fedcc80ae49cb06d3cdf0f08c31f [file] [log] [blame]
// umlrtoutsignal.cc
#include "umlrtcommsport.hh"
#include "umlrtcommsportfarend.hh"
#include "umlrtcontroller.hh"
#include "umlrtoutsignal.hh"
#include "umlrtframeservice.hh"
#include "umlrtslot.hh"
#include "basefatal.hh"
#include "basedebugtype.hh"
#include "basedebug.hh"
/*******************************************************************************
* Copyright (c) 2015 Zeligsoft (2009) Limited and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
UMLRTOutSignal::UMLRTOutSignal()
{
}
UMLRTOutSignal::UMLRTOutSignal(const UMLRTOutSignal &signal)
{
}
UMLRTOutSignal& UMLRTOutSignal::operator=(const UMLRTOutSignal &signal)
{
UMLRTSignal::operator = (signal);
return *this;
}
UMLRTOutSignal::~UMLRTOutSignal()
{
}
// See documentation in UMLRTSignal.
void UMLRTOutSignal::encode( const void * data, const UMLRTObject_class * desc, int arraySize )
{
if (!element)
{
FATAL("encode attempted on invalid signal.");
}
element->encode(desc, data, arraySize);
}
// See documentation in UMLRTSignal.
void UMLRTOutSignal::encode( int ptrIndirection, void * data, const UMLRTObject_class * desc, int arraySize )
{
FATAL("encode ptr indirection not supported");
}
// Synchronous send out all port instances. Returns the number of replies (0 if fail).
int UMLRTOutSignal::invoke( UMLRTMessage * replyMsgs )
{
FATAL("invoke not implemented");
return 0;
}
// Synchronous send out a specific port instance. Returns the number of replies (0 or 1).
int UMLRTOutSignal::invokeAt( int index, UMLRTMessage * replyMsg )
{
FATAL("invokeAt not implemented");
return 0;
}
// Reply to a synchronous message. Return true if success.
bool UMLRTOutSignal::reply()
{
FATAL("reply not implemented");
return false;
}
bool UMLRTOutSignal::send( UMLRTSignalElement::Priority priority ) const
{
int ok = false;
if (!element)
{
BDEBUG(BD_SWERR, "WARNING: attempt to send an invalid signal. Capsule and port information are not known.\n");
}
else
{
const UMLRTCommsPort * srcPort = element->getSrcPort();
if (!srcPort)
{
FATAL("No srcPort when sending a signal. Should be the unbound port at least.");
}
else if (srcPort->unbound)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_UNBOUND);
}
else
{
// Set priority here.
if ((priority < UMLRTSignalElement::PRIORITY_BACKGROUND) || (priority > UMLRTSignalElement::PRIORITY_PANIC))
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_PRIORITY);
}
else
{
element->setPriority(priority);
// Attempt all sends regardless of errors - one successful send will mean overall success.
for (size_t i = 0; (i < srcPort->numFarEnd); ++i)
{
ok |= signalDeliver(srcPort, i);
}
if (ok)
{
// If one succeeds, we'll return success - and remove error code from controller.
srcPort->slot->controller->setError(UMLRTController::E_OK);
}
}
}
}
return ok;
}
// Send the signal to one far end port. See umlrtsignal.hh for documentation.
bool UMLRTOutSignal::sendAt( size_t portIndex, UMLRTSignalElement::Priority priority ) const
{
bool ok = false;
if (!element)
{
BDEBUG(BD_SEND, "WARNING: attempt to send an invalid signal. Capsule and port information are not known.\n");
}
else
{
const UMLRTCommsPort * srcPort = element->getSrcPort();
if (!srcPort)
{
FATAL("No srcPort when sending a signal. Should be the unbound port at least.");
}
else if (srcPort->unbound)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_UNBOUND);
}
else if ((priority < UMLRTSignalElement::PRIORITY_BACKGROUND) || (priority > UMLRTSignalElement::PRIORITY_PANIC))
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_PRIORITY);
}
else
{
// Set priority here.
element->setPriority(priority);
ok = signalDeliver(srcPort, portIndex);
}
}
return ok;
}
// Deliver the signal to a destination.
bool UMLRTOutSignal::signalDeliver( const UMLRTCommsPort * srcPort, size_t portIndex ) const
{
bool ok = false;
// Lock the RTS
UMLRTFrameService::rtsLock();
const UMLRTCommsPort * destPort;
if (srcPort->slot->condemned)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_FROM_DSTR);
}
else if (portIndex >= srcPort->numFarEnd)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_NO_PORT_INST);
}
else if ((destPort = srcPort->farEnds[portIndex].port) == NULL)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_PRT_NOT_CON);
}
else if (destPort->slot->condemned)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_TO_DSTR);
}
else if (destPort->slot->capsule == NULL)
{
srcPort->slot->controller->setError(UMLRTController::E_SEND_NO_CAP_INST);
}
else if (destPort->slot->controller == NULL)
{
FATAL("Destination slot %s has no controller when sending from capsule %s via port %s[%d].",
destPort->slot,
srcPort->slot->name,
srcPort->role()->name,
portIndex);
}
else
{
ok = destPort->slot->controller->deliver( destPort, *this, portIndex );
// Error code set by 'deliver' if an error occurred.
}
// Unlock the RTS
UMLRTFrameService::rtsUnlock();
return ok;
}