/*
* Video On Demand Samples
*
* Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
*
* 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 .
*
* You may also obtain this software under a propriety license from Microchip.
* Please contact Microchip for further information.
*
*/
/*----------------------------------------------------------*/
/*! \file
* \brief This file contains the CIndustrialStack class.
*/
/*----------------------------------------------------------*/
//#define CON_TRACE
#define DISABLE_PARALLEL_MODE
#include
#include "IndustrialStack.h"
CIndustrialStack::CIndustrialStack(uint8_t deviceApi, int controlRxHandle, int controlTxHandle)
{
msnw = new CISNetServiceWrapper(deviceApi, controlRxHandle, controlTxHandle);
msnw->AddListener(this);
GetQueue(0x3C8); //Make sure that Broadcast queue is the first one
}
CIndustrialStack::~CIndustrialStack()
{
delete msnw;
deviceQueues.RemoveAll(true);
intEventListeners.RemoveAll(false);
}
void CIndustrialStack::EnqueueElement(uint16_t nodeAddress, IISElement *element)
{
CISDeviceQueue *dev = GetQueue(nodeAddress);
assert(NULL != dev);
element->AddReference();
dev->elements.PushBack(element);
}
void CIndustrialStack::ServiceStack(uint32_t time)
{
for (uint32_t i = 0; i < deviceQueues.Size(); i++)
{
assert(NULL != deviceQueues[i]);
if (deviceQueues[i]->elements.Size() == 0)
continue;
IISElement *element = deviceQueues[i]->elements[0];
assert(NULL != element);
ISReturn_t state = element->Service(this, time);
if (state == ISReturn_NoChange)
continue;
deviceQueues[i]->elements.PopFront();
HandleStateChange(state, element);
element->RemoveReference();
msnw->ServiceMns();
}
msnw->ServiceMns();
}
bool CIndustrialStack::ElementsPending()
{
for (uint32_t i = 0; i < deviceQueues.Size(); i++)
{
assert(NULL != deviceQueues[i]);
if (deviceQueues[i]->elements.Size() != 0)
return true;
}
return false;
}
bool CIndustrialStack::ElementsPending(uint16_t ingoreNodeAddress)
{
for (uint32_t i = 0; i < deviceQueues.Size(); i++)
{
CISDeviceQueue *q = deviceQueues[i];
assert(NULL != q);
if (q->GetNodeAddress() == ingoreNodeAddress)
continue;
if (q->elements.Size() != 0)
return true;
}
return false;
}
void CIndustrialStack::ClearAllElements()
{
for (uint32_t i = 0; i < deviceQueues.Size(); i++)
{
assert(NULL != deviceQueues[i]);
deviceQueues[i]->elements.RemoveAll(true);
}
}
bool CIndustrialStack::SendMostMessage(CISMostMsg *message)
{
assert(NULL != msnw);
assert(NULL != message);
if (NULL == message)
return false;
#ifdef CON_TRACE
ConsolePrintfStart(PRIO_HIGH, "IS TX, node:0x%X," \
" fblock:0x%X, func:0x%X, op:0x%X pl:0x[", message->TargetAddress,
message->FBlock, message->Func, message->OpType);
for (uint32_t i = 0; i < message->PayloadLen; i++)
ConsolePrintfContinue(" %02X", message->Payload[i]);
ConsolePrintfExit(" ]\n");
#endif
bool success = msnw->SendMostMessage(message);
for (uint32_t i = 0; success && i < intEventListeners.Size(); i++)
{
intEventListeners[i]->OnMostMessage(this, message);
}
return success;
}
void CIndustrialStack::Unsynchronize()
{
assert(NULL != msnw);
return msnw->Unsynchronize();
}
void CIndustrialStack::AddInternalEventListener(CSInternalEvent* callback)
{
intEventListeners.PushBack(callback);
}
/*--------------------------
* Callback from MSN Wrapper
*--------------------------
*/
void CIndustrialStack::OnReceivedMostMessage(CISMostMsg *rcvMessage)
{
assert(NULL != rcvMessage);
assert(rcvMessage->IsValid);
#ifdef CON_TRACE
ConsolePrintfStart(PRIO_HIGH, "IS RX, node:0x%X," \
" fblock:0x%X, func:0x%X, op:0x%X pl:0x[", rcvMessage->SourceAddress,
rcvMessage->FBlock, rcvMessage->Func, rcvMessage->OpType);
for (uint32_t i = 0; i < rcvMessage->PayloadLen; i++)
ConsolePrintfContinue(" %02X", rcvMessage->Payload[i]);
ConsolePrintfExit(" ]\n");
#endif
if (CISOpType_ERROR == rcvMessage->OpType
|| CISOpType_ERRORACK == rcvMessage->OpType)
{
//Ignore Destroy Resource Errors
if (rcvMessage->Func != 0x800)
{
ConsolePrintfStart(PRIO_ERROR, RED"Received error message, node:0x%X," \
" fblock:0x%X, func:0x%X, op:0x%X pl:0x[", rcvMessage->SourceAddress,
rcvMessage->FBlock, rcvMessage->Func, rcvMessage->OpType);
for (uint32_t i = 0; i < rcvMessage->PayloadLen; i++)
ConsolePrintfContinue(" %02X", rcvMessage->Payload[i]);
ConsolePrintfExit(" ]"RESETCOLOR"\n");
}
}
for (uint32_t i = 0; i < deviceQueues.Size(); i++)
{
assert(NULL != deviceQueues[i]);
IISElement *element = deviceQueues[i]->elements[0];
if (NULL == element)
continue;
ISReturn_t state = element->OnMostMessage(this, rcvMessage);
if (state == ISReturn_NoChange)
continue;
deviceQueues[i]->elements.PopFront();
HandleStateChange(state, element);
element->RemoveReference();
}
for (uint32_t i = 0; i < intEventListeners.Size(); i++)
{
intEventListeners[i]->OnMostMessage(this, rcvMessage);
}
}
void CIndustrialStack::OnSyncStateChanged(bool isSynced)
{
for (uint32_t i = 0; i < intEventListeners.Size(); i++)
{
assert(NULL != intEventListeners[i]);
intEventListeners[i]->OnSyncStateChanged(this, isSynced);
}
}
void CIndustrialStack::OnControlReadEnd()
{
for (uint32_t i = 0; i < intEventListeners.Size(); i++)
{
assert(NULL != intEventListeners[i]);
intEventListeners[i]->OnControlReadEnd(this);
}
}
/*--------------------------
* Private helper functions:
*--------------------------
*/
#ifdef DISABLE_PARALLEL_MODE
CISDeviceQueue *CIndustrialStack::GetQueue(uint16_t nodeAddress)
{
CISDeviceQueue *dev = deviceQueues[0];
if (NULL == dev)
{
ConsolePrintf(PRIO_HIGH, GREEN"Creating new Device Queue"RESETCOLOR"\n");
dev = new CISDeviceQueue(0);
deviceQueues.PushBack(dev);
}
return dev;
}
#else
CISDeviceQueue *CIndustrialStack::GetQueue(uint16_t nodeAddress)
{
CISDeviceQueue *dev = NULL;
if (nodeAddress >= 0x400 && nodeAddress <= 0x4FF)
nodeAddress -= 0x300;
for (uint32_t i = 0; i < deviceQueues.Size(); i++)
{
if (deviceQueues[i]->GetNodeAddress() == nodeAddress)
{
dev = deviceQueues[i];
break;
}
}
if (NULL == dev)
{
ConsolePrintf(PRIO_HIGH, GREEN"Creating new Device Queue for"\
" node address:0x%02X"RESETCOLOR"\n", nodeAddress);
dev = new CISDeviceQueue(nodeAddress);
deviceQueues.PushBack(dev);
}
return dev;
}
#endif
void CIndustrialStack::HandleStateChange(ISReturn_t state, IISElement * element)
{
assert(NULL != element);
switch (state)
{
case ISReturn_Failure:
case ISReturn_Timeout:
ConsolePrintf(PRIO_ERROR, RED"Job '%s' %s"RESETCOLOR"\n",
element->ElementName, state == ISReturn_Failure ? "failed" : "timed out");
case ISReturn_Success:
if (NULL != element->Callback)
element->Callback->ElementProcessed(this, state, element);
break;
case ISReturn_NoChange:
//Nothing to do
break;
default:
assert(false);
}
}