/* * 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 2 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); } }