diff options
Diffstat (limited to 'Src/Network/IndustrialStack.cpp')
-rw-r--r-- | Src/Network/IndustrialStack.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/Src/Network/IndustrialStack.cpp b/Src/Network/IndustrialStack.cpp new file mode 100644 index 0000000..e84ab22 --- /dev/null +++ b/Src/Network/IndustrialStack.cpp @@ -0,0 +1,275 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * 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 <assert.h> +#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); + } +} |