/* * 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 (common part). */ /*----------------------------------------------------------*/ #ifndef INDUSTRIAL_STACK_H #define INDUSTRIAL_STACK_H #include #include #include #include #include "SafeVector.h" #include "IndustrialStack_Types.h" #include "IndustrialStack_MNS.h" #include "Console.h" class CIndustrialStack : IISNetServiceWrapperCB { private: CISNetServiceWrapper *msnw; CSafeVector deviceQueues; CSafeVector intEventListeners; CISDeviceQueue *GetQueue(uint16_t deviceType); void HandleStateChange(ISReturn_t state, IISElement * element); public: CIndustrialStack(uint8_t deviceApi, int controlRxHandle, int controlTxHandle); virtual ~CIndustrialStack(); void ServiceStack(uint32_t time); void EnqueueElement(uint16_t nodeAddress, IISElement *element); bool ElementsPending(); bool ElementsPending(uint16_t ingoreNodeAddress); void ClearAllElements(); bool SendMostMessage(CISMostMsg *message); void Unsynchronize(); void AddInternalEventListener(CSInternalEvent* callback); /* Callback from IISNetServiceWrapperCB interface */ virtual void OnReceivedMostMessage(CISMostMsg *rcvMessage); virtual void OnSyncStateChanged(bool isSynced); virtual void OnControlReadEnd(); }; class CISWaitElement : public IISElement { protected: uint32_t startTime; uint32_t timeout; public: CISWaitElement() : IISElement(), startTime(0), timeout(2000) { ElementName = "Wait Element"; } void SetTimeout(uint32_t timeInMillis) { timeout = timeInMillis; } virtual ISReturn_t Service(CIndustrialStack *iStack, uint32_t time) { assert(NULL != iStack); if (0 == startTime) startTime = time; else if ( ( time - startTime >= timeout ) ) return ISReturn_Success; return ISReturn_NoChange; } virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *rcvMessage) { assert(NULL != iStack); return ISReturn_NoChange; } }; class CISWaitForPendingElements : public CISWaitElement { private: uint16_t ignoreNode; public: CISWaitForPendingElements(uint16_t ingoreNodeAddress) : CISWaitElement(), ignoreNode(ingoreNodeAddress) { } virtual ISReturn_t Service(CIndustrialStack *iStack, uint32_t time) { assert(NULL != iStack); if (!iStack->ElementsPending(ignoreNode)) return ISReturn_Success; return (CISWaitElement::Service(iStack, time) == ISReturn_NoChange) ? ISReturn_NoChange : ISReturn_Timeout; } }; class CISSendMostMsgElement : public CISWaitElement { private: uint8_t retryCount; public: CISMostMsg Request; CISMostMsg Response; bool WaitForResponse; CISOpType_t WaitForResponseOpType; CISSendMostMsgElement() : CISWaitElement(), retryCount(4), WaitForResponse(false), WaitForResponseOpType(CISOpType_INVALID) { timeout = 500; } virtual ISReturn_t Service(CIndustrialStack *iStack, uint32_t time) { assert(NULL != iStack); if (0 == startTime) { CISWaitElement::Service(iStack, time); if (Request.IsValid == false || Request.FBlock == 0xFFFFFFFF || Request.Func == 0xFFFFFFFF || Request.Inst == 0xFFFFFFFF || Request.OpType == CISOpType_INVALID) { ConsolePrintf(PRIO_ERROR, RED"CISSendMostMsgElement %s invalid MOST message to be"\ " sent"RESETCOLOR"\n", ElementName); return ISReturn_Failure; } bool success = iStack->SendMostMessage(&Request); if (success && !WaitForResponse) return ISReturn_Success; return success ? ISReturn_NoChange : ISReturn_Failure; } ISReturn_t waitState = CISWaitElement::Service(iStack, time); if (ISReturn_Success == waitState) { if (0 == --retryCount) { ConsolePrintf(PRIO_ERROR, RED"All High level retries failed for Request '%s',"\ " node 0x%X!"RESETCOLOR"\n", ElementName, Request.TargetAddress); return ISReturn_Timeout; } //Retry sending ConsolePrintf(PRIO_HIGH, YELLOW"High level retry after timeout for Request '%s',"\ " node 0x%X"RESETCOLOR"\n", ElementName, Request.TargetAddress); startTime = time; return (iStack->SendMostMessage(&Request)) ? ISReturn_NoChange : ISReturn_Failure; } return ISReturn_NoChange; } virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *rcvMessage) { if (!WaitForResponse) return ISReturn_NoChange; assert(NULL != iStack); assert(NULL != rcvMessage); assert(Request.IsValid); assert(rcvMessage->IsValid); uint32_t requestAddr = Request.TargetAddress; uint32_t responseAddr = rcvMessage->SourceAddress; if (requestAddr >= 0x400 && requestAddr <= 0x4FF ) requestAddr -= 0x300; if (responseAddr >= 0x400 && responseAddr <= 0x4FF ) responseAddr -= 0x300; if ( ( requestAddr < 0x300 || requestAddr > 0x3FF ) && ( responseAddr != requestAddr)) return ISReturn_NoChange; if ( rcvMessage->FBlock == Request.FBlock && rcvMessage->Func == Request.Func) { if (rcvMessage->OpType == WaitForResponseOpType) { Response.DeepCopy(rcvMessage); return ISReturn_Success; } else if(0 == --retryCount) { Response.DeepCopy(rcvMessage); return ISReturn_Failure; } //Retry sending ConsolePrintf(PRIO_HIGH, YELLOW"High level retry after wrong result for Request '%s',"\ " node 0x%X"RESETCOLOR"\n", ElementName, Request.TargetAddress); return (iStack->SendMostMessage(&Request)) ? ISReturn_NoChange : ISReturn_Failure; } return ISReturn_NoChange; } }; class CSInternalEvent : public IISElement { public: virtual ISReturn_t Service(CIndustrialStack *iStack, uint32_t time) { //Must not be called return ISReturn_Failure; } virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *r) { //Must not be called return ISReturn_Failure; } virtual void OnSyncStateChanged(CIndustrialStack *iStack, bool isSynced) {} virtual void OnControlReadEnd(CIndustrialStack *iStack) {} }; #endif //INDUSTRIAL_STACK_H