diff options
Diffstat (limited to 'Src/Network')
32 files changed, 12420 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); + } +} diff --git a/Src/Network/IndustrialStack.h b/Src/Network/IndustrialStack.h new file mode 100644 index 0000000..fc42f66 --- /dev/null +++ b/Src/Network/IndustrialStack.h @@ -0,0 +1,238 @@ +/* + * 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 (common part). + */ +/*----------------------------------------------------------*/ + +#ifndef INDUSTRIAL_STACK_H +#define INDUSTRIAL_STACK_H + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <string.h> +#include "SafeVector.h" +#include "IndustrialStack_Types.h" +#include "IndustrialStack_MNS.h" +#include "Console.h" + +class CIndustrialStack : IISNetServiceWrapperCB +{ +private: + CISNetServiceWrapper *msnw; + CSafeVector<CISDeviceQueue *> deviceQueues; + CSafeVector<CSInternalEvent *> 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 diff --git a/Src/Network/IndustrialStack_ApiGeneric.h b/Src/Network/IndustrialStack_ApiGeneric.h new file mode 100644 index 0000000..730f157 --- /dev/null +++ b/Src/Network/IndustrialStack_ApiGeneric.h @@ -0,0 +1,125 @@ +/* + * 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 (Generic commands). + */ +/*----------------------------------------------------------*/ + +#ifndef INDUSTRIAL_STACK_API_GENERIC_H +#define INDUSTRIAL_STACK_API_GENERIC_H + +#include "IndustrialStack.h" +#include "Network.h" +#include "Types.h" + +class CGeneric_SendConfigOk : public CISSendMostMsgElement +{ +public: + CGeneric_SendConfigOk(bool isOkay) + { + ElementName = "CGeneric_SendConfigOk"; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = 0x3C8; + Request.FBlock = 0x2; + Request.Func = 0xA00; + Request.Inst = 0x00; + Request.OpType = CISOpType_STATUS; + Request.PayloadLen = 1; + Request.Payload[0] = isOkay; + } +}; + +class CGeneric_GetMacAddress : public CISSendMostMsgElement +{ +public: + CGeneric_GetMacAddress(uint16_t nodeAddress) + { + ElementName = "CGeneric_GetMacAddress"; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x1; + Request.Func = 0x013; + Request.Inst = 0x00; + Request.OpType = CISOpType_GET; + Request.PayloadLen = 0; + } +}; + +class CGeneric_GetGroupAddress : public CISSendMostMsgElement +{ +public: + CGeneric_GetGroupAddress(uint16_t nodeAddress) + { + ElementName = "CGeneric_GetGroupAddress"; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x1; + Request.Func = 0x004; + Request.Inst = 0x00; + Request.OpType = CISOpType_GET; + Request.PayloadLen = 0; + } +}; + +class CGeneric_SendMostMessage : public CISSendMostMsgElement +{ +public: + CGeneric_SendMostMessage(const uint8_t *pPayload, uint32_t payloadLength, + uint16_t nodeAddress, uint8_t fblockId, uint8_t instanceId, + uint16_t functionId, uint8_t opTypeRequest, uint8_t opTypeResponse) + { + if (payloadLength > sizeof(Request.Payload)) + { + ConsolePrintf(PRIO_ERROR, RED"CGeneric_SendMostMessage was called"\ + " with to big payload size"RESETCOLOR"\n"); + payloadLength = sizeof(Request.Payload); + } + ElementName = "CGeneric_SendMostMessage"; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = fblockId; + Request.Func = functionId; + Request.Inst = instanceId; + Request.OpType = (CISOpType_t)opTypeRequest; + Request.PayloadLen = payloadLength; + if (0 != payloadLength) + memcpy(Request.Payload, pPayload, payloadLength); + if( 0xFF != opTypeResponse ) + { + WaitForResponse = true; + WaitForResponseOpType = (CISOpType_t)opTypeResponse; + } + } +}; + +#endif //INDUSTRIAL_STACK_API_GENERIC_H diff --git a/Src/Network/IndustrialStack_ApiV1.h b/Src/Network/IndustrialStack_ApiV1.h new file mode 100644 index 0000000..1c7f45a --- /dev/null +++ b/Src/Network/IndustrialStack_ApiV1.h @@ -0,0 +1,712 @@ +/* + * 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 (API V1 commands). + */ +/*----------------------------------------------------------*/ + +#ifndef INDUSTRIAL_STACK_API_V1_H +#define INDUSTRIAL_STACK_API_V1_H + +#define ISO_PACKET_SIZE 188 + +#include "IndustrialStack.h" +#include "Network.h" +#include "Types.h" + +class CV1_OnMostRx : public CSInternalEvent +{ +private: + CNetworkDevice *device; +public: + CV1_OnMostRx(CNetworkDevice *d) : device(d) + { + } + + virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *r) + { + assert(NULL != device); + assert(r->IsValid); + if (0x0 == r->FBlock) //INIC Block + { + switch (r->Func) + { + case 0x30E: //Change EUI48 + if (CISOpType_STATUS == r->OpType && r->PayloadLen >= 6) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, true, + r->SourceAddress, r->Payload[0], r->Payload[1], + r->Payload[2], r->Payload[3], r->Payload[4], r->Payload[5]); + } + else if (CISOpType_ERROR == r->OpType) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, false, + r->SourceAddress, 0,0,0,0,0,0); + } + break; + } + } + return ISReturn_NoChange; + } + + virtual void OnControlReadEnd(CIndustrialStack *iStack) + { + assert(NULL != device); + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnControlChannelReadEnd(device); + } +}; + +class CV1_ChangeEUI48 : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; +public: + CV1_ChangeEUI48(CNetworkDevice *d, uint16_t nodeAddress, + uint8_t macAddress1, uint8_t macAddress2, uint8_t macAddress3, + uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6, + bool persistent) : device(d) + { + ElementName = "CV1_ChangeEUI48"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x30E; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = macAddress1; + Request.Payload[1] = macAddress2; + Request.Payload[2] = macAddress3; + Request.Payload[3] = macAddress4; + Request.Payload[4] = macAddress5; + Request.Payload[5] = macAddress6; + Request.Payload[6] = persistent; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + assert(this == element); + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 6; + if (success) + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, true, + Request.TargetAddress, Response.Payload[0],Response.Payload[1], + Response.Payload[2], Response.Payload[3], Response.Payload[4], + Response.Payload[5]); + else + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, false, + Request.TargetAddress, 0, 0, 0, 0, 0, 0); + } +}; + +class CV1_NetworkStartup : public CISWaitElement +{ +private: + CNetworkDevice *device; +public: + CV1_NetworkStartup(CNetworkDevice *d, bool isTimingMaster, uint16_t packetBW) : device(d) + { + ElementName = "CV1_NetworkStartup is not implemented!"; + timeout = 1; + } +}; + +class CV1_NetworkShutdown : public CISWaitElement +{ +private: + CNetworkDevice *device; +public: + CV1_NetworkShutdown(CNetworkDevice *d) : device(d) + { + ElementName = "CV1_NetworkShutdown is not implemented!"; + timeout = 1; + } +}; + +class CV1_TsiPortCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; +public: + CV1_TsiPortCreate(CNetworkDevice *d, uint16_t nodeAddress, V1TsiPortInstance_t tsiPort, V1TsiPortMode tsiMode) : device(d) + { + ElementName = "CV2_TsiPortCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x400; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 2; + Request.Payload[0] = tsiPort; + Request.Payload[1] = tsiMode; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnOpenTsiV1(device, (ISReturn_Success == result), Request.TargetAddress); + } +}; + +class CV1_TsiSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + V1TsiPortInstance_t tsiPort; + EPDataType_t epType; + EPDirection_t epDir; + uint16_t blockWidthTsi; + uint32_t tag; +public: + CV1_TsiSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, V1TsiPortInstance_t tp, + EPDataType_t ept, EPDirection_t epd, uint16_t bw, uint32_t t) : + device(d), tsiPort(tp), epType(ept), epDir(epd), blockWidthTsi(bw), tag(t) + { + if ( EP_Isochron != epType ) + { + ConsolePrintf( PRIO_ERROR, RED"CV1_TsiSocketCreate: Unsupported Data type"RESETCOLOR"\n" ); + return; + } + ElementName = "CV1_TsiSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x403; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = tsiPort; + Request.Payload[1] = epDir; + Request.Payload[2] = epType; + Request.Payload[3] = blockWidthTsi / 256; + Request.Payload[4] = blockWidthTsi % 256; + Request.Payload[5] = ISO_PACKET_SIZE / 256; + Request.Payload[6] = ISO_PACKET_SIZE % 256; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t tsiPortHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + tsiPortHandle = Response.Payload[0]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateTsiSocketV1(device, success, Request.TargetAddress, tsiPort, + epType, epDir, blockWidthTsi, tsiPortHandle, tag); + } +}; + +class CV1_MlbPortCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; +public: + CV1_MlbPortCreate(CNetworkDevice *d, uint16_t nodeAddress, MlbPortSpeed_t mlbSpeed) : device(d) + { + ElementName = "CV2_MlbPortCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x400; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 4; + Request.Payload[0] = 0x00; //SCM_PORT_ID_MEDIALB; + Request.Payload[1] = 0xFF; + Request.Payload[2] = 0x00; //SCM_PORT_CFG_MLB_MODE_CTL; + Request.Payload[3] = mlbSpeed; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnOpenMlbV1(device, (ISReturn_Success == result), Request.TargetAddress); + } +}; + +class CV1_MlbSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDataType_t epType; + EPDirection_t epDir; + uint16_t mlbChannelAddress; + uint16_t blockWidthMlb; + uint32_t tag; +public: + CV1_MlbSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDataType_t ept, EPDirection_t epd, + uint16_t mlb, uint16_t bw, uint32_t t) : device(d), epType(ept), epDir(epd), + mlbChannelAddress(mlb), blockWidthMlb(bw), tag(t) + { + ElementName = "CV1_MlbSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x403; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = 0x00; //SCM_PORT_ID_MEDIALB + Request.Payload[1] = epDir; + Request.Payload[2] = epType; + Request.Payload[3] = blockWidthMlb / 256; + Request.Payload[4] = blockWidthMlb % 256; + Request.Payload[5] = mlbChannelAddress / 256; + Request.Payload[6] = mlbChannelAddress % 256; + if ( EP_Isochron == epType ) + { + Request.PayloadLen = 10; + Request.Payload[7] = ISO_PACKET_SIZE / 256; + Request.Payload[8] = ISO_PACKET_SIZE % 256; + Request.Payload[9] = 0x1; //SCM_FLOW_CONTROL_ON + } + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t mlbPortHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + mlbPortHandle = Response.Payload[0]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateMlbSocketV1(device, success, Request.TargetAddress, epType, + epDir, blockWidthMlb, mlbChannelAddress, mlbPortHandle, tag); + } +}; + +class CV1_SplittedMlbSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDataType_t epType; + EPDirection_t epDir; + uint16_t mlbChannelAddress; + uint16_t blockWidthMlb; + uint16_t splittedOffset; + uint16_t blockWidthCombined; + uint32_t tag; +public: + CV1_SplittedMlbSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, + EPDataType_t ept, EPDirection_t epd, uint16_t mlb, uint16_t bw, + uint16_t so, uint16_t bwc, uint32_t t) + : device(d), epType(ept), epDir(epd), mlbChannelAddress(mlb), + blockWidthMlb(bw), splittedOffset(so), blockWidthCombined(bwc), tag(t) + { + ElementName = "CV1_SplittedMlbSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x403; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 9; + Request.Payload[0] = 0x00; //SCM_PORT_ID_MEDIALB + Request.Payload[1] = epDir; + Request.Payload[2] = epType; + Request.Payload[3] = blockWidthMlb / 256; + Request.Payload[4] = blockWidthMlb % 256; + Request.Payload[5] = mlbChannelAddress / 256; + Request.Payload[6] = mlbChannelAddress % 256; + Request.Payload[7] = ( uint8_t )( splittedOffset & 0xFF ); + Request.Payload[8] = ( uint8_t )( blockWidthCombined & 0xFF ); + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t mlbPortHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + mlbPortHandle = Response.Payload[0]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateMlbSocketV1(device, success, Request.TargetAddress, epType, + epDir, blockWidthMlb, mlbChannelAddress, mlbPortHandle, tag); + } +}; + +class CV1_MostSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDataType_t epType; + EPDirection_t epDir; + uint16_t connectionLabel; + uint16_t blockWidthMost; + uint32_t tag; +public: + CV1_MostSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDataType_t ept, EPDirection_t epd, + uint16_t cl, uint16_t bw, uint32_t t) : device(d), epType(ept), epDir(epd), + connectionLabel(cl), blockWidthMost(bw), tag(t) + { + ElementName = "CV1_MostSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x403; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.Payload[0] = 0x02; //SCM_PORT_ID_MOST + Request.Payload[1] = epDir; + Request.Payload[2] = epType; + Request.Payload[3] = blockWidthMost / 256; + Request.Payload[4] = blockWidthMost % 256; + switch( epType ) + { + case EP_Isochron: + Request.Payload[5] = ISO_PACKET_SIZE / 256; + Request.Payload[6] = ISO_PACKET_SIZE % 256; + if( SCM_IN == epDir ) + { + Request.PayloadLen = 10; + Request.Payload[7] = 0x1; //SCM_PA_CL + Request.Payload[8] = connectionLabel / 256; + Request.Payload[9] = connectionLabel % 256; + } + else + { + Request.PayloadLen = 8; + Request.Payload[7] = 0x0; //SCM_NOT_PA + } + break; + case EP_Synchron: + if( SCM_IN == epDir ) + { + Request.PayloadLen = 8; + Request.Payload[5] = 0x1; //SCM_PA_CL + Request.Payload[6] = connectionLabel / 256; + Request.Payload[7] = connectionLabel % 256; + } + else + { + Request.PayloadLen = 6; + Request.Payload[5] = 0x0; //SCM_NOT_PA + } + break; + default: + timeout = 1; + ConsolePrintf( PRIO_ERROR, RED"CreateMostSocket: Unsupported Data type"RESETCOLOR"\n" ); + return; + } + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t usbSocketHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + usbSocketHandle = Response.Payload[0]; + if( success && SCM_OUT == epDir && Response.PayloadLen >= 4) + connectionLabel = ( Response.Payload[2] << 8) | Response.Payload[3]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateMostSocketV1(device, success, Request.TargetAddress, epType, + epDir, blockWidthMost, connectionLabel, usbSocketHandle, tag); + } +}; + +class CV1_ConnectSockets : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t nodeAddress; + EPDataType_t epType; + uint16_t inHandle; + uint16_t outHandle; + uint32_t tag; +public: + CV1_ConnectSockets(CNetworkDevice *d, uint16_t nodeAddress, uint16_t iH, + uint16_t oH, uint32_t t) : device(d), inHandle(iH), outHandle(oH), tag(t) + { + ElementName = "CV1_ConnectSockets"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x405; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 2; + Request.Payload[0] = inHandle; + Request.Payload[1] = outHandle; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t conHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + conHandle = Response.Payload[0]; + + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnConnectSocketsV1(device, success, + Request.TargetAddress, inHandle, outHandle, conHandle, tag); + } +}; + +class CV1_DestroySocket : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint8_t handle; + uint32_t tag; +public: + CV1_DestroySocket(CNetworkDevice *d, int16_t nodeAddress, uint8_t h, + uint32_t t) : device(d), handle(h), tag(t) + { + ElementName = "CV1_DestroySocket"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x404; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 1; + Request.Payload[0] = handle; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnDestroySocketV1(device, (ISReturn_Success == result), + Request.TargetAddress, handle, tag); + } +}; + +class CV1_DisconnectSockets : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint8_t handle; + uint32_t tag; +public: + CV1_DisconnectSockets(CNetworkDevice *d, int16_t nodeAddress, uint8_t h, + uint32_t t) : device(d), handle(h), tag(t) + { + ElementName = "CV1_DisconnectSockets"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x406; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 1; + Request.Payload[0] = handle; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnDisconnectSocketsV1(device, (ISReturn_Success == result), + Request.TargetAddress, handle, tag); + } +}; + +class CV1_StreamPortOpen : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + V1I2SPortClkDriveMode_t portMode; + V1I2SStreamingPortMode_t streamPortMode; + V1I2SStreamingDataFormat_t format; + uint32_t tag; +public: + CV1_StreamPortOpen(CNetworkDevice *d, int16_t nodeAddress, + V1I2SPortClkDriveMode_t pm, V1I2SStreamingPortMode_t spm, + V1I2SStreamingDataFormat_t f, uint32_t t) : device(d), portMode(pm), + streamPortMode(spm), format(f), tag(t) + { + ElementName = "CV1_StreamPortOpen"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x400; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 4; + Request.Payload[0] = 0x03; //Streaming Port + Request.Payload[1] = portMode; + Request.Payload[2] = streamPortMode; + Request.Payload[3] = format; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnOpenI2SPortV1(device, (ISReturn_Success == result), + Request.TargetAddress, portMode, format, tag); + } +}; + +class CV1_StreamSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDirection_t epDir; + uint16_t blockWidthI2S; + V1I2SPin_t pin; + uint32_t tag; +public: + CV1_StreamSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDirection_t epd, + uint16_t bw, V1I2SPin_t p, uint32_t t) : device(d), epDir(epd), + blockWidthI2S(bw), pin(p), tag(t) + { + ElementName = "CV1_StreamSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x403; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 6; + Request.Payload[0] = 0x03; //Streaming Port + Request.Payload[1] = epDir; + Request.Payload[2] = 0x0; //SyncData + Request.Payload[3] = blockWidthI2S / 256; + Request.Payload[4] = blockWidthI2S % 256; + Request.Payload[5] = (uint8_t)pin; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t i2sSocketHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + i2sSocketHandle = Response.Payload[0]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateI2SSocketV1(device, success, + Request.TargetAddress, epDir, blockWidthI2S, pin, i2sSocketHandle, tag); + } +}; + +class CV1_SplittedStreamSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDirection_t epDir; + uint16_t blockWidthI2S; + V1I2SPin_t pin; + uint32_t tag; +public: + CV1_SplittedStreamSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDirection_t epd, + uint16_t bw, uint16_t splittedOffset, uint16_t blockWidthCombined, V1I2SPin_t p, + uint32_t t) : device(d), epDir(epd), blockWidthI2S(bw), pin(p), tag(t) + { + ElementName = "CV1_SplittedStreamSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x403; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = 0x03; //Streaming Port + Request.Payload[1] = epDir; + Request.Payload[2] = 0x0; //SyncData + Request.Payload[3] = blockWidthI2S / 256; + Request.Payload[4] = blockWidthI2S % 256; + Request.Payload[5] = (uint8_t)pin; + Request.Payload[6] = ( uint8_t )( splittedOffset & 0xFF ); + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint8_t i2sSocketHandle = 0xFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 1; + if (success) + i2sSocketHandle = Response.Payload[0]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateI2SSocketV1(device, success, + Request.TargetAddress, epDir, blockWidthI2S, pin, i2sSocketHandle, tag); + } +}; + +#endif //INDUSTRIAL_STACK_API_V1_H
\ No newline at end of file diff --git a/Src/Network/IndustrialStack_ApiV3.h b/Src/Network/IndustrialStack_ApiV3.h new file mode 100644 index 0000000..7e37789 --- /dev/null +++ b/Src/Network/IndustrialStack_ApiV3.h @@ -0,0 +1,1123 @@ +/* + * 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 (API V3 commands). + */ +/*----------------------------------------------------------*/ + +#ifndef INDUSTRIAL_STACK_API_V3_H +#define INDUSTRIAL_STACK_API_V3_H + +#include "IndustrialStack.h" +#include "Network.h" +#include "Types.h" + +class CV3_OnMostRx : public CSInternalEvent +{ +private: + CNetworkDevice *device; +public: + CV3_OnMostRx(CNetworkDevice *d) : device(d) + { + } + + virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *r) + { + assert(NULL != device); + assert(r->IsValid); + if (0x0 == r->FBlock) //INIC Block + { + switch (r->Func) + { + case 0x520: //MOST Network Status + if (CISOpType_STATUS == r->OpType && r->PayloadLen == 11) + { + bool mpValChanged = ( 0 != ( r->Payload[1] & 0x1 ) ); //This is a 16 Bit value!! + bool systemNotOk = false; //Not transmitted any longer + bool mostAvailable = ( 0 != ( r->Payload[2] & 0x1 ) ); + uint8_t availableSubState = r->Payload[3]; + uint8_t availableTransition = r->Payload[4]; + uint16_t nodeAddress = r->Payload[5] << 8 + | r->Payload[6]; + uint8_t nodePos = ( r->Payload[7] & 0x3F ); + uint8_t maxPos = ( r->Payload[8] ); + uint16_t packetBW = r->Payload[9] << 8 + | r->Payload[10]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnNetworkState(device, + mpValChanged, systemNotOk, mostAvailable, availableSubState, + availableTransition, nodeAddress, nodePos, maxPos, packetBW); + } + break; + case 0x524: //MOST Network Startup + if (CISOpType_STATUS == r->OpType) + { + if (r->Payload[0] == 0x20 && r->Payload[1] == 0x04 && r->Payload[2] == 0x40) + return ISReturn_NoChange; //Startup was called, but we already have locked network, so ignore this error + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnNetworkStartupV3(device, (CISOpType_STATUS == r->OpType)); + } + break; + case 0x527: //RBD Result + if (CISOpType_STATUS == r->OpType && r->PayloadLen == 5) + { + uint8_t result = r->Payload[0]; + uint8_t position = r->Payload[1]; + uint8_t status = r->Payload[2]; + uint16_t id = r->Payload[3] << 8 + | r->Payload[4]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnRbdResultV3(device, r->SourceAddress, + result, position, status, id); + } + break; + } + } + else if (0x1 == r->FBlock) //NetBlock FBlock + { + switch (r->Func) + { + case 0x004: //GroupAddress Changed + if (CISOpType_STATUS == r->OpType && r->PayloadLen >= 2) + { + uint16_t groupAddress = r->Payload[0] << 8 + | r->Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostDeviceType(device, true, r->SourceAddress, groupAddress ); + } + else if (CISOpType_ERROR == r->OpType) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostDeviceType(device, false, r->SourceAddress, 0xFFFF ); + } + break; + case 0x013: //NetBlock EUI48 + if (CISOpType_STATUS == r->OpType && r->PayloadLen >= 6) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, true, + r->SourceAddress, r->Payload[0], r->Payload[1], + r->Payload[2], r->Payload[3], r->Payload[4], r->Payload[5]); + } + else if (CISOpType_ERROR == r->OpType) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, false, + r->SourceAddress, 0,0,0,0,0,0); + } + break; + } + } + return ISReturn_NoChange; + } + + virtual void OnSyncStateChanged(CIndustrialStack *iStack, bool isSynced) + { + assert(NULL != device); + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnSync(device, isSynced ); + } +}; + +class CV3_NetworkStartup : public CISSendMostMsgElement +{ +private: + CNetworkDevice *device; +public: + CV3_NetworkStartup(CNetworkDevice *d, uint16_t autoForcedNotAvailable, uint16_t packetBW) : device(d) + { + ElementName = "CV3_NetworkStartup"; + WaitForResponseOpType = CISOpType_RESULT; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = 0x1; + Request.FBlock = 0x0; + Request.Func = 0x524; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 4; + Request.Payload[0] = autoForcedNotAvailable / 256; + Request.Payload[1] = autoForcedNotAvailable % 256; + Request.Payload[2] = packetBW / 256; + Request.Payload[3] = packetBW % 256; + } +}; + +class CV3_MostNetworkConfiguration : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; +public: + CV3_MostNetworkConfiguration(CNetworkDevice *d, uint16_t nodeAddress, + uint8_t macAddress1, uint8_t macAddress2, uint8_t macAddress3, + uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6, + bool promiscuous) : device(d) + { + ElementName = "CV3_MostNetworkConfiguration"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_STATUS; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x521; + Request.Inst = 0x00; + Request.OpType = CISOpType_SETGET; + Request.PayloadLen = 24; + Request.Payload[0] = 0; // HB: MASK + Request.Payload[1] = + ( 1 << 3 ) // LB: MASK: Packet Filter Mode is considered + | ( 1 << 5 ); // LB: MASK: PacketEUI is considered + Request.Payload[2] = 0x00; // HB: Node Address (ignored) + Request.Payload[3] = 0x08; // LB: Node Address (ignored) + Request.Payload[4] = 0x00; // HB: Group Address (ignored) + Request.Payload[5] = 0x00; // LB: Group Address (ignored) + Request.Payload[6] = 0x00; // Control LLR Block Count (ignored) + Request.Payload[7] = 0x00; // HB: FilterMode (reserved) + Request.Payload[8] = promiscuous ? 0x0A : 0x08; // LB: FilterMode (Allow all Multicast) + Request.Payload[9] = 0x00; // HB: PacketHash_63to48 (ignored) + Request.Payload[10] = 0x00; // LB: PacketHash_63to48 (ignored) + Request.Payload[11] = 0x00; // HB: PacketHash_47to32 (ignored) + Request.Payload[12] = 0x00; // LB: PacketHash_47to32 (ignored) + Request.Payload[13] = 0x00; // HB: PacketHash_31to16 (ignored) + Request.Payload[14] = 0x00; // LB: PacketHash_31to16 (ignored) + Request.Payload[15] = 0x00; // HB: PacketHash_15to0 (ignored) + Request.Payload[16] = 0x00; // LB: PacketHash_15to0 (ignored) + Request.Payload[17] = macAddress1; // HB: PacketEUI48_47to32 + Request.Payload[18] = macAddress2; // LB: PacketEUI48_47to32 + Request.Payload[19] = macAddress3; // HB: PacketEUI48_31to16 + Request.Payload[20] = macAddress4; // LB: PacketEUI48_31to16 + Request.Payload[21] = macAddress5; // HB: PacketEUI48_15to0 + Request.Payload[22] = macAddress6; // LB: PacketEUI48_15to0 + Request.Payload[23] = 0x00; // PacketLLRTime (ignored) + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + assert(this == element); + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 18; + if (success) + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, true, + Request.TargetAddress, Response.Payload[15],Response.Payload[16], + Response.Payload[17], Response.Payload[18], Response.Payload[19], + Response.Payload[20]); + else + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnMostMacAddress(device, false, + Request.TargetAddress, 0, 0, 0, 0, 0, 0); + } +}; + +class CV3_DeviceAttach : public CISSendMostMsgElement +{ +public: + CV3_DeviceAttach() + { + ElementName = "CV3_DeviceAttach"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = 0x1; + Request.FBlock = 0x0; + Request.Func = 0x223; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + } +}; + +class CV3_Unsynchronize : public IISElement +{ +public: + CV3_Unsynchronize() + { + ElementName = "CV3_Unsynchronize"; + } + + virtual ISReturn_t Service(CIndustrialStack *iStack, uint32_t time) + { + assert(NULL != iStack); + iStack->Unsynchronize(); + return ISReturn_Success; + } + + virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *r) + { + return ISReturn_NoChange; + } +}; + +class CV3_DeviceSync : public CISSendMostMsgElement +{ +public: + CV3_DeviceSync(uint16_t nodeAddress, bool sync) + { + if (0x1 == nodeAddress) + { + ConsolePrintf(PRIO_ERROR, RED"CV3_DeviceSync was called with local" \ + " node address, this will fail!"RESETCOLOR"\n"); + } + ElementName = "CV3_DeviceSync"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x224; + Request.Inst = 0x01; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 1; + Request.Payload[0] = sync; + } +}; + +class CV3_NetworkShutdown : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; +public: + CV3_NetworkShutdown(CNetworkDevice *d) : device(d) + { + ElementName = "CV3_NetworkShutdown"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = 0x1; + Request.FBlock = 0x0; + Request.Func = 0x525; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 0; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnNetworkShutdownV3(device, (ISReturn_Success == result)); + } +}; + +class CV3_MlbPortCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; +public: + CV3_MlbPortCreate(CNetworkDevice *d, uint16_t nodeAddress, MlbPortSpeed_t mlbSpeed) : device(d) + { + ElementName = "CV3_MlbPortCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x621; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 2; + Request.Payload[0] = 0x00; //Index + Request.Payload[1] = mlbSpeed; //ClockConfig + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint16_t mlbPortHandle = 0xFFFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (success) + mlbPortHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnOpenMlbV3(device, success, Request.TargetAddress, mlbPortHandle); + } +}; + +class CV3_UsbSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDataType_t epType; + EPDirection_t epDir; + uint8_t endPointAddress; + uint16_t packetsPerFrame; + uint32_t tag; +public: + CV3_UsbSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDataType_t ept, + EPDirection_t epd, uint8_t epa, uint16_t p, uint32_t t) : device(d), epType(ept), + epDir(epd), endPointAddress(epa), packetsPerFrame(p), tag(t) + { + ElementName = "CV3_UsbSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x671; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = 0x12; // HB: UsbPortHandle + Request.Payload[1] = 0x00; // LB: UsbPortHandle + Request.Payload[2] = epDir; // Direction + Request.Payload[3] = epType; // DataType + Request.Payload[4] = endPointAddress; // EndpointAddress + Request.Payload[5] = packetsPerFrame / 256; // HB: Packets per USB frame + Request.Payload[6] = packetsPerFrame % 256; // LB: Packets per USB frame + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint16_t usbHandle = 0xFFFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (success) + usbHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateUsbSocketV3(device, success, + Request.TargetAddress, epType, epDir, endPointAddress, usbHandle, tag); + } +}; + +class CV3_SplittedUsbSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + EPDataType_t epType; + EPDirection_t epDir; + uint8_t endPointAddress; + uint16_t packetsPerUsbFrame; + uint16_t bytesPerPacket; + uint32_t tag; + uint16_t usbHandle; +public: + CV3_SplittedUsbSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDataType_t ept, + EPDirection_t epd, uint8_t epa, uint16_t p, uint16_t bp, uint32_t t) : device(d), epType(ept), + epDir(epd), endPointAddress(epa), packetsPerUsbFrame(p), bytesPerPacket(bp), tag(t), + usbHandle(0xFFFF) + { + ElementName = "CV3_SplittedUsbSocketCreate-USB"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x671; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = 0x12; // HB: UsbPortHandle + Request.Payload[1] = 0x00; // LB: UsbPortHandle + Request.Payload[2] = epDir; // Direction + Request.Payload[3] = epType; // DataType + Request.Payload[4] = endPointAddress; // EndpointAddress + Request.Payload[5] = packetsPerUsbFrame / 256; // HB: Packets per USB frame + Request.Payload[6] = packetsPerUsbFrame % 256; // LB: Packets per USB frame + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (!success) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateSplittedUsbSocketV3(device, false, + Request.TargetAddress, epType, epDir, endPointAddress, 0xFFFF, 0xFFFF, tag); + return; + } + if (0x671 == Response.Func) + { + usbHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + CreateSplitter(iStack); + } + else + { + uint16_t splitterHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateSplittedUsbSocketV3(device, success, + Request.TargetAddress, epType, epDir, endPointAddress, usbHandle, splitterHandle, tag); + } + } +private: + void CreateSplitter(CIndustrialStack *iStack) + { + assert(usbHandle != 0xFFFF); + ElementName = "CV3_SplittedUsbSocketCreate-Splitter"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + startTime = 0; + Request.FBlock = 0x0; + if( EPDIR_IN == epDir ) + Request.Func = 0x911; //SplitterCreate + else + Request.Func = 0x901; //CombinerCreate + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 6; + Request.Payload[0] = usbHandle / 256; // HB: SocketHandle IN/OUT + Request.Payload[1] = usbHandle % 256; // LB: SocketHandle IN/OUT + Request.Payload[2] = 0x0D; // HB: MOSTPortHandle + Request.Payload[3] = 0x00; // LB: MOSTPortHandle + Request.Payload[4] = bytesPerPacket / 256; // HB: BytesPerFrame + Request.Payload[5] = bytesPerPacket % 256; // LB: BytesPerFrame + iStack->EnqueueElement(Request.TargetAddress, this); + } +}; + +class CV3_MlbSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t mlbPortHandle; + EPDataType_t epType; + EPDirection_t epDir; + uint8_t mlbChannelAddress; + uint16_t blockWidthMlb; + uint32_t tag; +public: + CV3_MlbSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, uint16_t mlb, EPDataType_t ept, + EPDirection_t epd, uint8_t eca, uint16_t bw, uint32_t t) : device(d), mlbPortHandle(mlb), + epType(ept), epDir(epd), mlbChannelAddress(eca), blockWidthMlb(bw), tag(t) + { + ElementName = "CV3_MlbSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x631; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 8; + Request.Payload[0] = mlbPortHandle / 256; + Request.Payload[1] = mlbPortHandle % 256; + Request.Payload[2] = epDir; + Request.Payload[3] = epType; + Request.Payload[4] = blockWidthMlb / 256; + Request.Payload[5] = blockWidthMlb % 256; + Request.Payload[6] = mlbChannelAddress / 256; + Request.Payload[7] = mlbChannelAddress % 256; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint16_t mlbHandle = 0xFFFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (success) + mlbHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateMlbSocketV3(device, success, + Request.TargetAddress, epType, epDir, blockWidthMlb, mlbChannelAddress, mlbHandle, tag); + } +}; + +class CV3_SplittedMlbSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t mlbPortHandle; + EPDataType_t epType; + EPDirection_t epDir; + uint8_t mlbChannelAddress; + uint16_t blockWidthMlb; + uint16_t bytesPerPacket; + uint16_t mlbHandle; + uint32_t tag; +public: + CV3_SplittedMlbSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, uint16_t mlb, EPDataType_t ept, + EPDirection_t epd, uint8_t eca, uint16_t bw, uint16_t bp, uint32_t t) : device(d), mlbPortHandle(mlb), + epType(ept), epDir(epd), mlbChannelAddress(eca), blockWidthMlb(bw), bytesPerPacket(bp), tag(t) + { + ElementName = "CV3_SplittedMlbSocketCreate-MLB"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x631; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 8; + Request.Payload[0] = mlbPortHandle / 256; + Request.Payload[1] = mlbPortHandle % 256; + Request.Payload[2] = epDir; + Request.Payload[3] = epType; + Request.Payload[4] = blockWidthMlb / 256; + Request.Payload[5] = blockWidthMlb % 256; + Request.Payload[6] = mlbChannelAddress / 256; + Request.Payload[7] = mlbChannelAddress % 256; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (!success) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateSplittedMlbSocketV3(device, false, + Request.TargetAddress, epType, epDir, blockWidthMlb, mlbChannelAddress, + 0xFFFF, 0xFFFF, tag); + return; + } + if (0x631 == Response.Func) + { + mlbHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + CreateSplitter(iStack); + } + else + { + uint16_t splitterHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateSplittedMlbSocketV3(device, success, + Request.TargetAddress, epType, epDir, blockWidthMlb, mlbChannelAddress, + mlbHandle, splitterHandle, tag); + } + } +private: + void CreateSplitter(CIndustrialStack *iStack) + { + assert(mlbHandle != 0xFFFF); + ElementName = "CV3_SplittedMlbSocketCreate-Splitter"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + startTime = 0; + Request.FBlock = 0x0; + if( EPDIR_IN == epDir ) + Request.Func = 0x911; //SplitterCreate + else + Request.Func = 0x901; //CombinerCreate + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 6; + Request.Payload[0] = mlbHandle / 256; // HB: SocketHandle IN/OUT + Request.Payload[1] = mlbHandle % 256; // LB: SocketHandle IN/OUT + Request.Payload[2] = 0x0D; // HB: MOSTPortHandle + Request.Payload[3] = 0x00; // LB: MOSTPortHandle + Request.Payload[4] = bytesPerPacket / 256; // HB: BytesPerFrame + Request.Payload[5] = bytesPerPacket % 256; // LB: BytesPerFrame + iStack->EnqueueElement(Request.TargetAddress, this); + } +}; + +class CV3_MostSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t nodeAddress; + EPDataType_t epType; + EPDirection_t epDir; + uint16_t connectionLabel; + uint16_t blockwidthMost; + uint32_t tag; +public: + CV3_MostSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, EPDataType_t ep, EPDirection_t epd, + uint16_t cl, uint16_t bw, uint32_t t) : device(d), epType(ep), + epDir(epd), connectionLabel(cl), blockwidthMost(bw), tag(t) + { + ElementName = "CV3_MostSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x611; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 8; + Request.Payload[0] = 0x0D; // HB: MostPortHandle + Request.Payload[1] = 0x00; // LB: MostPortHandle + Request.Payload[2] = epDir; // Dir + Request.Payload[3] = epType; // DataType + Request.Payload[4] = blockwidthMost / 256; // HB: bandwidth + Request.Payload[5] = blockwidthMost % 256; // LB: bandwidth + Request.Payload[6] = connectionLabel / 256; // HB: ConnectionLabel + Request.Payload[7] = connectionLabel % 256; // LB: ConnectionLabel + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint16_t conHandle = 0xFFFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 4; + if (success) + conHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + + if (success && SCM_OUT == epDir && Response.PayloadLen >= 4) + connectionLabel = ( Response.Payload[2] << 8 ) | Response.Payload[3]; + + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateMostSocketV3(device, success, + Request.TargetAddress, epType, epDir, blockwidthMost, connectionLabel, conHandle, tag); + } +}; + +class CV3_ConnectSockets : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t nodeAddress; + EPDataType_t epType; + uint16_t inHandle; + uint16_t outHandle; + uint16_t offset; + uint32_t tag; +public: + CV3_ConnectSockets(CNetworkDevice *d, uint16_t nodeAddress, EPDataType_t ep, uint16_t iH, + uint16_t oH, uint16_t o, uint32_t t) : device(d), epType(ep), inHandle(iH), + outHandle(oH), offset(o), tag(t) + { + ElementName = "CV3_ConnectSockets"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + + switch( epType ) + { + case EP_Isochron: + Request.Func = 0x861; //AVPCreate + Request.PayloadLen = 6; + Request.Payload[0] = inHandle / 256; // HB: in handle (will be filled by decomposerHandleIn) + Request.Payload[1] = inHandle % 256; // LB: in handle (will be filled by decomposerHandleIn) + Request.Payload[2] = outHandle / 256; // HB: out handle (will be filled by decomposerHandleOut) + Request.Payload[3] = outHandle % 256; // LB: out handle (will be filled by decomposerHandleOut) + Request.Payload[4] = 0x00; // HB: IsoPacketSize + Request.Payload[5] = 188; // LB: IsoPacketSize + break; + case EP_Synchron: + Request.Func = 0x871; // SyncCreate + Request.PayloadLen = 8; + Request.Payload[0] = inHandle / 256; // HB: in handle (will be filled by decomposerHandleIn) + Request.Payload[1] = inHandle % 256; // LB: in handle (will be filled by decomposerHandleIn) + Request.Payload[2] = outHandle / 256; // HB: out handle (will be filled by decomposerHandleOut) + Request.Payload[3] = outHandle % 256; // LB: out handle (will be filled by decomposerHandleOut) + Request.Payload[4] = 0x00; // 0: not muted by default; 1: muted by default + Request.Payload[5] = 0x00; // 0: NoMuting, 1:MuteSignal, 2:AutoMute + Request.Payload[6] = offset / 256; // HB: Offset + Request.Payload[7] = offset % 256; // LB: Offset + break; + default: + WaitForResponse = false; + ConsolePrintf( PRIO_ERROR, RED"CV3_ConnectSockets: Unsupported Data type"RESETCOLOR"\n" ); + return; + } + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + assert(this == element); + uint16_t conHandle = 0xFFFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (success) + conHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnConnectSocketsV3(device, success, + Request.TargetAddress, epType, inHandle, outHandle, conHandle, tag); + } +}; + +class CV3_ResourceDestroy : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t nodeAddress; + uint8_t amountOfHandles; + uint32_t tag; +public: + CV3_ResourceDestroy(CNetworkDevice *d, int16_t nodeAddress, + uint8_t amount, const uint16_t *pHandle, uint32_t t) : device(d), + amountOfHandles(amount), tag(t) + { + ElementName = "CV3_ResourceDestroy"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x800; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + + uint8_t index = 0; + Request.Payload[index++] = 0x00; // HB: SenderHandle + Request.Payload[index++] = 0x00; // LB: SenderHandle + for( uint8_t i = 0; i < amountOfHandles; i++ ) + { + Request.Payload[index++] = pHandle[i] / 256; // HB: handle + Request.Payload[index++] = pHandle[i] % 256; // LB: handle + } + Request.PayloadLen = index; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnResourceDestroyV3(device, true, + Request.TargetAddress, amountOfHandles, ( uint16_t * )&Request.Payload[2], tag); + } +}; + +class CV3_StreamPortConfig : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint8_t portInstance; + V3I2SPortOption_t option; + V3I2SClockMode_t mode; + V3I2SDelayMode_t delay; + uint32_t tag; +public: + CV3_StreamPortConfig(CNetworkDevice *d, uint16_t nodeAddress, uint8_t port, + V3I2SPortOption_t opt, V3I2SClockMode_t md, V3I2SDelayMode_t del, uint32_t t) + : device(d), portInstance(port), option(opt), mode(md), delay(del), tag(t) + { + ElementName = "CV3_StreamPortConfig"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x680; + Request.Inst = 0x00; + Request.OpType = CISOpType_SETGET; + Request.PayloadLen = 5; + Request.Payload[0] = portInstance; + Request.Payload[1] = 0x00; //Fixed operation mode 0 = Generic + Request.Payload[2] = option; + Request.Payload[3] = mode; + Request.Payload[4] = delay; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnConfigureI2SPortV3(device, (ISReturn_Success == result), + Request.TargetAddress, portInstance, option, mode, delay, tag); + } +}; + +class CV3_StreamPortCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint8_t portInstance; + V3I2SPortSpeed_t clock; + V3I2SAlignment_t align; + uint32_t tag; +public: + CV3_StreamPortCreate(CNetworkDevice *d, uint16_t nodeAddress, uint8_t port, + V3I2SPortSpeed_t cl, V3I2SAlignment_t al, uint32_t t) + : device(d), portInstance(port), clock(cl), align(al), tag(t) + { + ElementName = "CV3_StreamPortCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x681; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 3; + Request.Payload[0] = portInstance; + Request.Payload[1] = clock; + Request.Payload[2] = align; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateI2SPortV3(device, (ISReturn_Success == result), + Request.TargetAddress, portInstance, clock, align, tag); + } +}; + +class CV3_StreamSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint8_t portInstance; + EPDirection_t epDir; + uint16_t blockWidthI2S; + V3I2SPin_t pin; + uint32_t tag; +public: + CV3_StreamSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, uint8_t pi, EPDirection_t epd, + uint16_t bw, V3I2SPin_t p, uint32_t t) : device(d), portInstance(pi), + epDir(epd), blockWidthI2S(bw), pin(p), tag(t) + { + ElementName = "CV3_StreamSocketCreate"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x691; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = 0x16; //Fixed port handle for I2S + Request.Payload[1] = portInstance; //dynamic port handle for I2S (Port A or B) + Request.Payload[2] = epDir; + Request.Payload[3] = 0x00; //Data type (fixed 0 for sync) + Request.Payload[4] = blockWidthI2S / 256; + Request.Payload[5] = blockWidthI2S % 256; + Request.Payload[6] = pin; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + uint16_t i2sHandle = 0xFFFF; + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (success) + i2sHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateI2SSocketV3(device, success, + Request.TargetAddress, portInstance, epDir, blockWidthI2S, pin, i2sHandle, tag); + } +}; + +class CV3_SplittedStreamSocketCreate : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint8_t portInstance; + EPDirection_t epDir; + uint16_t blockWidthI2S; + V3I2SPin_t pin; + uint16_t bytesPerPacket; + uint32_t tag; + uint16_t i2sHandle; +public: + CV3_SplittedStreamSocketCreate(CNetworkDevice *d, uint16_t nodeAddress, uint8_t pi, + EPDirection_t epd, uint16_t bw, V3I2SPin_t p, uint16_t bp, uint32_t t) : device(d), + portInstance(pi), epDir(epd), blockWidthI2S(bw), pin(p), bytesPerPacket(bp), tag(t), + i2sHandle(0xFFFF) + { + ElementName = "CV3_SplittedStreamSocketCreate-Stream"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x691; + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 7; + Request.Payload[0] = 0x16; //Fixed port handle for I2S + Request.Payload[1] = portInstance; //dynamic port handle for I2S (Port A or B) + Request.Payload[2] = epDir; + Request.Payload[3] = 0x00; //Data type (fixed 0 for sync) + Request.Payload[4] = blockWidthI2S / 256; + Request.Payload[5] = blockWidthI2S % 256; + Request.Payload[6] = pin; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 2; + if (!success) + { + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateSplittedI2SSocketV3(device, false, + Request.TargetAddress, portInstance, epDir, blockWidthI2S, pin, + 0xFFFF, 0xFFFF, tag); + return; + } + if (0x691 == Response.Func) + { + i2sHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + CreateSplitter(iStack); + } + else + { + uint16_t splitterHandle = ( Response.Payload[0] << 8 ) | Response.Payload[1]; + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnCreateSplittedI2SSocketV3(device, success, + Request.TargetAddress, portInstance, epDir, blockWidthI2S, pin, + i2sHandle, splitterHandle, tag); + } + } +private: + void CreateSplitter(CIndustrialStack *iStack) + { + assert(i2sHandle != 0xFFFF); + ElementName = "CV3_SplittedStreamSocketCreate-Splitter"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_RESULT; + Callback = this; + startTime = 0; + Request.FBlock = 0x0; + if( EPDIR_IN == epDir ) + Request.Func = 0x911; //SplitterCreate + else + Request.Func = 0x901; //CombinerCreate + Request.Inst = 0x00; + Request.OpType = CISOpType_STARTRESULT; + Request.PayloadLen = 6; + Request.Payload[0] = i2sHandle / 256; // HB: SocketHandle IN/OUT + Request.Payload[1] = i2sHandle % 256; // LB: SocketHandle IN/OUT + Request.Payload[2] = 0x0D; // HB: MOSTPortHandle + Request.Payload[3] = 0x00; // LB: MOSTPortHandle + Request.Payload[4] = bytesPerPacket / 256; // HB: BytesPerFrame + Request.Payload[5] = bytesPerPacket % 256; // LB: BytesPerFrame + iStack->EnqueueElement(Request.TargetAddress, this); + } +}; + +class CV3_GetRbdResult : public CISSendMostMsgElement +{ +public: + CV3_GetRbdResult(uint16_t nodeAddress) + { + ElementName = "CV3_GetRbdResult"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_STATUS; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Func = 0x527; + Request.Inst = 0x00; + Request.OpType = CISOpType_GET; + Request.PayloadLen = 0; + } +}; + +class CV3_DeviceVersion : public CISSendMostMsgElement, public IISElementCallback +{ +private: + CNetworkDevice *device; + uint16_t nodeAddress; + EPDataType_t epType; + uint16_t inHandle; + uint16_t outHandle; + uint16_t offset; + uint32_t tag; +public: + CV3_DeviceVersion(CNetworkDevice *d, uint16_t nodeAddress, uint32_t t) : device(d), tag(t) + { + ElementName = "CV3_DeviceVersion"; + WaitForResponse = true; + WaitForResponseOpType = CISOpType_STATUS; + Callback = this; + + Request.IsValid = true; + Request.SourceAddress = 0x2; + Request.TargetAddress = nodeAddress; + Request.FBlock = 0x0; + Request.Inst = 0x00; + Request.Func = 0x221; + Request.OpType = CISOpType_GET; + Request.PayloadLen = 0; + } + + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) + { + assert(this == element); + bool success = (ISReturn_Success == result) && Response.PayloadLen >= 13; + + uint32_t productId = 0xFFFFFFFF; + uint32_t fwVersion = 0xFFFFFFFF; + uint32_t buildVersion = 0xFFFFFFFF; + uint8_t hwVersion = 0xFF; + uint16_t diagnosisId = 0xFFFF; + + if (success) + { + productId = ( Response.Payload[0] << 24 ) + | ( Response.Payload[1] << 16 ) + | ( Response.Payload[2] << 8 ) + | Response.Payload[3]; + + fwVersion = ( Response.Payload[4] << 24 ) + | ( Response.Payload[5] << 16 ) + | ( Response.Payload[6] << 8 ); + + buildVersion = ( Response.Payload[7] << 24 ) + | ( Response.Payload[8] << 16 ) + | ( Response.Payload[9] << 8 ) + | Response.Payload[10]; + + hwVersion = Response.Payload[10]; + + diagnosisId = ( Response.Payload[11] << 8 ) + | Response.Payload[12]; + } + + for( uint32_t i = 0; NULL != device && i < device->GetAmountOfListners(); i++ ) + device->GetListener( i )->OnDeviceVersion(device, success, Response.SourceAddress, + productId, fwVersion, buildVersion, hwVersion, diagnosisId, tag); + } +}; + +#endif //INDUSTRIAL_STACK_API_V3_H
\ No newline at end of file diff --git a/Src/Network/IndustrialStack_LLD.cpp b/Src/Network/IndustrialStack_LLD.cpp new file mode 100644 index 0000000..f025dec --- /dev/null +++ b/Src/Network/IndustrialStack_LLD.cpp @@ -0,0 +1,278 @@ +/* + * 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. + * + */ + +//#define LLD_TRACE + +/*----------------------------------------------------------*/ +/*! \file */ +/*! \brief Base Board initialisation */ +/*----------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <pthread.h> +#include <assert.h> + +#include "Console.h" +#include "Board.h" +#include "DriverConfiguration.h" +#include "IndustrialStack_LLD.h" + +/*----------------------------------------------------------*/ +/* Static C helper functions */ +/*----------------------------------------------------------*/ + +static void Queue_Init( Queue_t *queue ) +{ + assert(NULL != queue); + queue->testPattern = QUEUE_TESTPATTERN; + queue->rxPos = 0; + queue->txPos = 0; + queue->pRx = queue->dataQueue; + queue->pTx = queue->dataQueue; +} + +static QueueEntry_t *Queue_GetRxPtr( Queue_t *queue ) +{ + assert(NULL != queue && QUEUE_TESTPATTERN == queue->testPattern); + QueueEntry_t *pEntry = NULL; + if( queue->txPos - queue->rxPos > 0 ) + { + pEntry = queue->pRx; + } + return pEntry; +} + +static void Queue_PopRx( Queue_t *queue ) +{ + assert(NULL != queue && QUEUE_TESTPATTERN == queue->testPattern); + if( ++queue->pRx >= queue->dataQueue + BOARD_PMS_RX_QUEUE ) + queue->pRx = queue->dataQueue; + ++queue->rxPos; +} + +static QueueEntry_t *Queue_GetTxPtr( Queue_t *queue ) +{ + assert(NULL != queue && QUEUE_TESTPATTERN == queue->testPattern); + QueueEntry_t *pEntry = NULL; + if( ( uint32_t )BOARD_PMS_RX_QUEUE + queue->rxPos - queue->txPos > 0 ) + { + pEntry = queue->pTx; + } + return pEntry; +} + +static void Queue_PopTx( Queue_t *queue ) +{ + assert(NULL != queue && QUEUE_TESTPATTERN == queue->testPattern); + if( ++queue->pTx >= queue->dataQueue + BOARD_PMS_RX_QUEUE ) + queue->pTx = queue->dataQueue; + ++queue->txPos; +} + +static void *ReceiveThread( void *tag ) +{ + assert(NULL != tag); + CIndustrialStackLld *var = ( CIndustrialStackLld * )tag; + while( var->allowThreadRun ) + { + if( -1 == var->hControlRx ) + { + ConsolePrintf( PRIO_ERROR, RED"File handle for Control-RX is invalid, stopping reader thread."RESETCOLOR"\n" ); + if (NULL != var->listener) + var->listener->OnReadThreadEnd(var); + pthread_exit( NULL ); + } + QueueEntry_t *pEntry = Queue_GetTxPtr(&var->rxQueue); + if( NULL != pEntry ) + { + int16_t payloadLen = 0; + payloadLen = read( var->hControlRx, pEntry->buffer, sizeof( pEntry->buffer ) ); + if( payloadLen < 0 ) + { + if( var->allowThreadRun ) + { + ConsolePrintf( PRIO_ERROR, RED"Stopping reader thread, because of error: '%s'"RESETCOLOR"\n", + GetErrnoString() ); + if (NULL != var->listener) + var->listener->OnReadThreadEnd(var); + } + pthread_exit( NULL ); + } + else if( payloadLen != 0 ) + { + pEntry->payloadLen = payloadLen; + Queue_PopTx(&var->rxQueue); +#ifdef LLD_TRACE + { + ConsolePrintfStart( PRIO_HIGH, BLUE"%04d: MSG_RX: ", GetTickCountWord()); + for ( int16_t i = 0; i < pEntry->payloadLen; i++ ) + { + ConsolePrintfContinue( "%02X ", pEntry->buffer[i] ); + } + ConsolePrintfExit(RESETCOLOR"\n"); + } +#endif + } + } + else + { + ConsolePrintf( PRIO_ERROR, RED"WARNING, RX QUEUE FULL !!\nPlease increase BOARD_PMS_RX_QUEUE value, or increase polling speed\n"RESETCOLOR"\n" ); + usleep( 10000 ); + } + } + ConsolePrintf( PRIO_LOW, "Control Receive Thread ends\n" ); + if( var->allowThreadRun && NULL != var->listener) + var->listener->OnReadThreadEnd(var); + pthread_exit( NULL ); +} + +static void *SendThread( void *tag ) +{ + assert(NULL != tag); + CIndustrialStackLld *var = ( CIndustrialStackLld * )tag; + while( var->allowThreadRun ) + { + sem_wait( &var->txSem ); + if (!var->allowThreadRun) + pthread_exit( NULL ); + QueueEntry_t *pEntry = Queue_GetRxPtr( &var->txQueue ); + assert(NULL != pEntry); + if( -1 == var->hControlTx ) + { + ConsolePrintf( PRIO_ERROR, RED"File handle for Control-TX is invalid, stopping send thread."RESETCOLOR"\n" ); + pthread_exit( NULL ); + } +#ifdef LLD_TRACE + { + uint32_t i; + ConsolePrintfStart( PRIO_MEDIUM, YELLOW"%04d: MSG_TX: ", GetTickCountWord()); + for ( i = 0; i < pEntry->payloadLen; i++ ) + { + ConsolePrintfContinue( "%02X ", pEntry->buffer[i] ); + } + ConsolePrintfExit(RESETCOLOR"\n"); + } +#endif + if( write( var->hControlTx, pEntry->buffer, pEntry->payloadLen ) != pEntry->payloadLen ) + { + ConsolePrintf( PRIO_ERROR, RED"Failed to send %d bytes to the MOST control channel"RESETCOLOR"\n", pEntry->payloadLen ); + usleep(1000); + } + else + { + Queue_PopRx(&var->txQueue); + } + + } + pthread_exit( NULL ); +} + +/*----------------------------------------------------------*/ +/* Public method implementations */ +/*----------------------------------------------------------*/ + +CIndustrialStackLld::CIndustrialStackLld( int controlRxHandle, int controlTxHandle ) + : hControlRx(controlRxHandle), hControlTx(controlTxHandle), allowThreadRun(true), listener(NULL) +{ + Queue_Init(&rxQueue); + Queue_Init(&txQueue); + + if (sem_init(&txSem, 0, 0) == -1) + { + ConsolePrintf(PRIO_ERROR, RED"CIndustrialStackLld constructor: sem_init failed"RESETCOLOR"\n"); + return; + } + + pthread_create( &rxThread, NULL, ReceiveThread, this ); + pthread_create( &txThread, NULL, SendThread, this ); +} + +CIndustrialStackLld::~CIndustrialStackLld() +{ + void *dummy; + allowThreadRun = false; + sem_post( &txSem ); + + pthread_join( txThread, &dummy ); + pthread_join( rxThread, &dummy ); + + sem_destroy( &txSem ); +} + +void CIndustrialStackLld::ClearQueues() +{ + ConsolePrintf( PRIO_LOW, "Clearing INIC queues\n" ); + QueueEntry_t *pEntry; + while( NULL != ( pEntry = Queue_GetRxPtr(&rxQueue) ) ) + Queue_PopRx(&rxQueue); + while( NULL != ( pEntry = Queue_GetRxPtr(&txQueue) ) ) + Queue_PopRx(&txQueue); +} + +uint16_t CIndustrialStackLld::DataAvailable() +{ + uint16_t readLen = 0; + QueueEntry_t *pEntry = Queue_GetRxPtr(&rxQueue); + if( NULL != pEntry ) + readLen = pEntry->payloadLen; + return readLen; +} + +uint16_t CIndustrialStackLld::Read( uint8_t *pData, uint32_t bufferLen ) +{ + uint16_t readLen = 0; + QueueEntry_t *pEntry = Queue_GetRxPtr(&rxQueue); + if( NULL != pData && NULL != pEntry ) + { + readLen = pEntry->payloadLen; + if (readLen > bufferLen) + { + ConsolePrintf(PRIO_ERROR, RED"CIndustrialStackLld::Read buffer"\ + " length is too small"RESETCOLOR"\n"); + readLen = bufferLen; + } + memcpy( pData, pEntry->buffer, readLen ); + Queue_PopRx(&rxQueue); + } + return readLen; +} + +bool CIndustrialStackLld::Write( uint16_t wLen, uint8_t *pData ) +{ + if( -1 == hControlTx ) + return false; + QueueEntry_t *pEntry = Queue_GetTxPtr( &txQueue ); + if( NULL != pData && NULL != pEntry ) + { + memcpy( pEntry->buffer, pData, wLen ); + pEntry->payloadLen = wLen; + Queue_PopTx( &txQueue ); + sem_post( &txSem ); + return true; + } + return false; +} diff --git a/Src/Network/IndustrialStack_LLD.h b/Src/Network/IndustrialStack_LLD.h new file mode 100644 index 0000000..8ae9738 --- /dev/null +++ b/Src/Network/IndustrialStack_LLD.h @@ -0,0 +1,148 @@ +/* + * 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 component implements the MOST low level driver. + */ +/*----------------------------------------------------------*/ +#ifndef INDUSTRIAL_STACK_LLD_H +#define INDUSTRIAL_STACK_LLD_H + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> +#include "IndustrialStack_Types.h" + +#define BOARD_PMS_RX_QUEUE 256 +#define BOARD_PMS_RX_SIZE 64 +#define BOARD_PMS_TX_SIZE 64 + +typedef struct +{ + int16_t payloadLen; + uint8_t buffer[BOARD_PMS_RX_SIZE]; +} QueueEntry_t; + +#define QUEUE_TESTPATTERN (0x34547382) +typedef struct +{ + uint32_t testPattern; + QueueEntry_t dataQueue[BOARD_PMS_RX_QUEUE]; + QueueEntry_t *pRx; + QueueEntry_t *pTx; + volatile uint32_t rxPos; + volatile uint32_t txPos; +} Queue_t; + +class CIndustrialStackLld +{ +private: + pthread_t txThread; + pthread_t rxThread; +public: + ///Do not use directly! (Called internally from thread context) + Queue_t txQueue; + ///Do not use directly! (Called internally from thread context) + Queue_t rxQueue; + ///Do not use directly! (Called internally from thread context) + int hControlRx; + ///Do not use directly! (Called internally from thread context) + int hControlTx; + ///Do not use directly! (Called internally from thread context) + bool allowThreadRun; + ///Do not use directly! (Called internally from thread context) + sem_t txSem; + + CIndustrialStackLldCB *listener; + + /*----------------------------------------------------------*/ + /*! \brief initializes LLD + * + * \param controlRxHandle File handle for the RX character device + * \param controlRxHandle File handle for the TX character device + * \return nothing. + */ + /*----------------------------------------------------------*/ + CIndustrialStackLld( int controlRxHandle, int controlTxHandle ); + + + + /*----------------------------------------------------------*/ + /*! \brief deinitializes LLD + */ + /*----------------------------------------------------------*/ + ~CIndustrialStackLld(); + + + /*----------------------------------------------------------*/ + /*! \brief determins if INIC has something to read + * + * \return The amount of data, which will be delivered by the next call of Read + */ + /*----------------------------------------------------------*/ + uint16_t DataAvailable(); + + + /*----------------------------------------------------------*/ + /*! \brief receive a control message via USB. + * + * \param pData - message data + * + * \return The amount of bytes read. + */ + /*----------------------------------------------------------*/ + uint16_t Read( uint8_t *pData, uint32_t bufferLen ); + + + + /*----------------------------------------------------------*/ + /*! \brief Clearing RX and TX queues. + * + * \return nothing + */ + /*----------------------------------------------------------*/ + void ClearQueues(); + + + + /*----------------------------------------------------------*/ + /*! \brief send a control message via USB. + * + * \param wLen - length of message in bytes + * \param pData - message data + * + * \return True if no error. + */ + /*----------------------------------------------------------*/ + bool Write( uint16_t wLen, uint8_t *pData ); + +}; + +class CIndustrialStackLldCB +{ +public: + virtual void OnReadThreadEnd(CIndustrialStackLld *lld) = 0; +}; + +#endif // INDUSTRIAL_STACK_LLD_H diff --git a/Src/Network/IndustrialStack_MNS.cpp b/Src/Network/IndustrialStack_MNS.cpp new file mode 100644 index 0000000..257db40 --- /dev/null +++ b/Src/Network/IndustrialStack_MNS.cpp @@ -0,0 +1,414 @@ +/* + * 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 (NetService part). + */ +/*----------------------------------------------------------*/ + +#define ENABLE_INIC_WATCHDOG true + +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "IndustrialStack_MNS.h" +#include "IndustrialStack_Types.h" +#include "Board.h" +#include "Console.h" + +static bool CheckMnswPointer(void *inst_ptr, const char *functionName); +static void Lld_CtrlStartC( Mns_Lld_Api_t *callbacks_ptr, void *ns_ptr, void *inst_ptr ); +static void Lld_CtrlStopC( void *inst_ptr ); +static void Lld_CtrlTxTransmitC( Mns_Lld_TxMsg_t *msg_ptr, void *inst_ptr ); +static void Lld_CtrlRxMsgAvailableC( void *inst_ptr ); +static uint16_t GetTickCountWordC(); +static void OnMnslEventC( Mnsl_Event_t event_code, void *inst_ptr ); +static void OnMnslServiceC( void *inst_ptr ); +static void *OnMnslAmsAllocMemC( void *inst_ptr, uint16_t mem_size, Mns_Ams_MemUsage_t type, void** custom_info_pptr ); +static void OnMnslAmsFreeMemC( void *inst_ptr, void *mem_ptr, Mns_Ams_MemUsage_t type, void* custom_info_ptr ); +static void OnIcmRx( void *inst_ptr, Msg_MostTel_t *pRx ); +static void OnRcmRx( void *inst_ptr, Msg_MostTel_t *pRx ); +static void OnMcmRx( void *inst_ptr, Msg_MostTel_t *pRx ); +static void OnTransmissionStatus(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status); + +CISNetServiceWrapper::CISNetServiceWrapper(uint8_t deviceApi, int controlRxHandle, int controlTxHandle) + : testPattern(MNSW_TESTPATTERN), inicWriteError( false ), pMnsInterface(NULL), pMnsInst(NULL) + , isSynced(false), wrapperCB(NULL) +{ + if( 2 != deviceApi && 3 != deviceApi ) + { + ConsolePrintf( PRIO_ERROR, RED"CISNetServiceWrapper was called with deviceApi set"\ + " to %d. This is not supported by this branch of NetworkManager"\ + RESETCOLOR"\n", deviceApi ); + } + + lld = new CIndustrialStackLld(controlRxHandle, controlTxHandle); + lld->listener = this; + + memset(&pLldCb, 0, sizeof(pLldCb)); + pLldCb.start_fptr = &Lld_CtrlStartC; + pLldCb.stop_fptr = &Lld_CtrlStopC; + pLldCb.rx_available_fptr = &Lld_CtrlRxMsgAvailableC; + pLldCb.tx_transmit_fptr = &Lld_CtrlTxTransmitC; + + Mnsl_InitData_t initData; + Mnsl_SetDefaultConfig(&initData, ENABLE_INIC_WATCHDOG); + initData.lld.start_fptr = &Lld_CtrlStartC; + initData.lld.stop_fptr = &Lld_CtrlStopC; + initData.lld.rx_available_fptr = &Lld_CtrlRxMsgAvailableC; + initData.lld.tx_transmit_fptr = &Lld_CtrlTxTransmitC; + + initData.general.get_tickcount_fptr = &GetTickCountWordC; + initData.general.event_fptr = &OnMnslEventC; + initData.general.request_service_fptr = &OnMnslServiceC; + + initData.pms.active_fifos = MNSL_FIFOS_MCM_ICM_RCM; + initData.pms.compressed = (2 == deviceApi); + + initData.ams.rx_alloc_mem_fptr = &OnMnslAmsAllocMemC; + initData.ams.rx_free_mem_fptr = &OnMnslAmsFreeMemC; + + Mnsl_Init( &mnsl, &initData, this ); + + icm_inst_ptr = Mnsl_GetIcmTransceiver( &mnsl ); // Retrieve ICM instance + rcm_inst_ptr = Mnsl_GetRcmTransceiver( &mnsl ); // Retrieve RCM instance + mcm_inst_ptr = Mnsl_GetMcmTransceiver( &mnsl ); // Retrieve MCM instance + + Trcv_RxAssignReceiver( icm_inst_ptr, &OnIcmRx, this ); // Assign ICM Receiver Callback + Trcv_RxAssignReceiver( rcm_inst_ptr, &OnRcmRx, this ); // Assign ICM Receiver Callback + Trcv_RxAssignReceiver( mcm_inst_ptr, &OnMcmRx, this ); // Assign ICM Receiver Callback + + Mnsl_Synchronize( &mnsl ); +} + +CISNetServiceWrapper::~CISNetServiceWrapper() +{ + if (NULL != lld) + { + delete lld; + lld = NULL; + } +} + +void CISNetServiceWrapper::ServiceMns() +{ + assert(NULL != lld); + uint16_t wLen; + while( 0 != ( wLen = lld->DataAvailable() ) ) + { + if (NULL != pMnsInterface) + { + Mns_Lld_RxMsg_t *pRxMsg = pMnsInterface->rx_allocate_fptr( pMnsInst, wLen ); + if( pRxMsg ) + { + if (wLen != lld->Read( pRxMsg->data_ptr, wLen )) + ConsolePrintf( PRIO_ERROR, RED"! LLD read error"RESETCOLOR"\n" ); //Must not happen + pRxMsg->data_size = wLen; + pMnsInterface->rx_receive_fptr( pMnsInst, pRxMsg ); + Mnsl_Service( &mnsl ); + } + else + ConsolePrintf( PRIO_ERROR, RED"! out of message memory"RESETCOLOR"\n" ); + } + } + Mnsl_Service( &mnsl ); +} + +void CISNetServiceWrapper::AddListener(IISNetServiceWrapperCB *rcvListener) +{ + wrapperCB = rcvListener; +} + +bool CISNetServiceWrapper::SendMostMessage(CISMostMsg *msg) +{ + assert(NULL != msg); + assert(msg->IsValid); + + CTransceiver *tr = NULL; + + if (0x1 == msg->TargetAddress || 0x100 == msg->TargetAddress) + tr = icm_inst_ptr; + else if (0x0 == msg->FBlock || 0x1 == msg->FBlock) + tr = rcm_inst_ptr; + else + tr = mcm_inst_ptr; + + Msg_MostTel_t *tel = Trcv_TxAllocateMsg( tr, msg->PayloadLen ); + if( NULL == tel ) + { + ConsolePrintf( PRIO_ERROR, RED"Trcv_TxAllocateMsg failed. Len:"\ + " %u, Message-Type=%s"RESETCOLOR"\n", msg->PayloadLen, + (tr == icm_inst_ptr ? "ICM" : tr == rcm_inst_ptr ? "RCM" : "MCM")); + return false; + } + tel->source_addr = msg->SourceAddress; + tel->destination_addr = msg->TargetAddress; + tel->id.fblock_id = msg->FBlock; + tel->id.function_id = msg->Func; + tel->id.instance_id = msg->Inst; + tel->id.op_type = (Mns_OpType_t)msg->OpType; + tel->tel.tel_len = msg->PayloadLen; + tel->tel.tel_id = 0; + if (0 != msg->PayloadLen) + { + if (NULL != tel->tel.tel_data_ptr) + { + memcpy(tel->tel.tel_data_ptr, msg->Payload, msg->PayloadLen); + } else { + ConsolePrintf(PRIO_ERROR, RED"CISNetServiceWrapper::SendMostMessage,"\ + " packet has NULL pointer payload"RESETCOLOR"\n"); + Trcv_TxReleaseMsg(tel); + return false; + } + } + Trcv_TxSendMsgExt( tr, tel, OnTransmissionStatus, NULL ); + return true; +} + +void CISNetServiceWrapper::Unsynchronize() +{ + Mnsl_Unsynchronize( &mnsl, true ); +} + +void CISNetServiceWrapper::OnReadThreadEnd(CIndustrialStackLld *lld) +{ + if (NULL != wrapperCB) + wrapperCB->OnControlReadEnd(); +} + +void CISNetServiceWrapper::OnCtrlTxTransmit( Mns_Lld_TxMsg_t *msg_ptr) +{ + assert(NULL != msg_ptr); + assert(NULL != pMnsInterface); + if( msg_ptr && pMnsInterface ) + { + assert(NULL != lld); + Mns_Mem_Buffer_t *pMemBuf; +#define MAX_DATA_LEN 72 + uint8_t data[MAX_DATA_LEN]; + uint8_t *pW = data; + for( pMemBuf = msg_ptr->memory_ptr; pMemBuf != NULL; + pMemBuf = pMemBuf->next_buffer_ptr ) + { + if( pW + pMemBuf->data_size >= data + MAX_DATA_LEN ) + { + ConsolePrintf( PRIO_ERROR, RED"invalid size"RESETCOLOR"\n" ); + return; + } + memcpy( pW, pMemBuf->data_ptr, pMemBuf->data_size ); + pW += pMemBuf->data_size; + } + + if( !lld->Write( pW - data, data ) ) + { + if (!inicWriteError) + { + inicWriteError = true; + ConsolePrintf( PRIO_ERROR, RED"! Unable to write to INIC!"RESETCOLOR"\n" ); + } + } + else inicWriteError = false; + + pMnsInterface->tx_release_fptr( pMnsInst, msg_ptr ); + } +} + +void CISNetServiceWrapper::OnMnslEvent( Mnsl_Event_t event_code ) +{ + bool oldSyncState = isSynced; + switch( event_code ) + { + case MNSL_EVENT_SYNC_COMPLETE: + isSynced = true; + ConsolePrintf( PRIO_MEDIUM, "MNSL Event Callback notifies: MNSL_EVENT_SYNC_COMPLETE\n" ); + break; + case MNSL_EVENT_SYNC_FAILED: + isSynced = false; + ConsolePrintf( PRIO_ERROR, YELLOW"MNSL Event Callback notifies: MNSL_EVENT_SYNC_FAILED" \ + ", retrying..\nMake sure that local INIC runs Firmware V2.3.0 or later!"RESETCOLOR"\n" ); + Mnsl_Synchronize( &mnsl ); + return; /* Do not report the event */ + case MNSL_EVENT_SYNC_LOST: + isSynced = false; + ConsolePrintf( PRIO_ERROR, "MNSL Event Callback notifies: MNSL_EVENT_SYNC_LOST\n" ); + break; + case MNSL_EVENT_UNSYNC_COMPLETE: + isSynced = false; + ConsolePrintf( PRIO_MEDIUM, YELLOW"MNSL Event Callback notifies: MNSL_EVENT_UNSYNC_COMPLETE, syncing again.."RESETCOLOR"\n" ); + Mnsl_Synchronize( &mnsl ); + return; /* Do not report the event */ + case MNSL_EVENT_UNSYNC_FAILED: + isSynced = false; + ConsolePrintf( PRIO_ERROR, RED"MNSL Event Callback notifies: MNSL_EVENT_UNSYNC_FAILED"RESETCOLOR"\n" ); + Mnsl_Synchronize( &mnsl ); + break; + default: + ConsolePrintf( PRIO_ERROR, "MNSL Event Callback notifies: UNKNOWN CODE\n" ); + break; + } + if (NULL != wrapperCB && oldSyncState != isSynced) + { + wrapperCB->OnSyncStateChanged(isSynced); + } +} + +void CISNetServiceWrapper::OnMessage( Msg_MostTel_t *pRx, CTransceiver *pTr ) +{ + assert(NULL != pRx); + assert(pRx->tel.tel_len <= MAX_PAYLOAD_SIZE); + if (NULL == wrapperCB) + return; + CISMostMsg msg; + msg.IsValid = true; + msg.SourceAddress = pRx->source_addr; + msg.TargetAddress = pRx->destination_addr; + msg.FBlock = pRx->id.fblock_id; + msg.Func = pRx->id.function_id; + msg.Inst = pRx->id.instance_id; + msg.OpType = (CISOpType_t) pRx->id.op_type; + msg.PayloadLen = pRx->tel.tel_len; + memcpy(msg.Payload, pRx->tel.tel_data_ptr, msg.PayloadLen); + Trcv_RxReleaseMsg(pTr, pRx); + wrapperCB->OnReceivedMostMessage(&msg); +} + +/*---------------------------------------- + * Private helper functions and C wrapper: + *---------------------------------------- + */ +static bool CheckMnswPointer(void *inst_ptr, const char *functionName) +{ + if( NULL == inst_ptr || MNSW_TESTPATTERN != ( ( CISNetServiceWrapper * )inst_ptr )->testPattern ) + { + ConsolePrintf( PRIO_ERROR, RED"Parameter bug in %s"RESETCOLOR"\n", functionName ); + assert(false); + return true; + } + return false; +} +static void Lld_CtrlStartC( Mns_Lld_Api_t *callbacks_ptr, void *ns_ptr, void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "Lld_CtrlStart")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->pMnsInterface = callbacks_ptr; + mnsw->pMnsInst = ns_ptr; +} +static void Lld_CtrlStopC( void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "Lld_CtrlStop")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->pMnsInterface = 0; + mnsw->pMnsInst = 0; +} +static void Lld_CtrlTxTransmitC( Mns_Lld_TxMsg_t *msg_ptr, void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "Lld_CtrlTxTransmit")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnCtrlTxTransmit(msg_ptr); +} +static void Lld_CtrlRxMsgAvailableC( void *inst_ptr ) +{ + //Unused +} +static uint16_t GetTickCountWordC() +{ + return GetTickCountWord(); +} +static void OnMnslEventC( Mnsl_Event_t event_code, void *inst_ptr ) +{ + if (CheckMnswPointer(inst_ptr, "OnMnslEvent")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMnslEvent(event_code); +} +static void OnMnslServiceC( void *inst_ptr ) +{ + //Unused +} +static void *OnMnslAmsAllocMemC( void *inst_ptr, uint16_t mem_size, Mns_Ams_MemUsage_t type, void** custom_info_pptr ) +{ + if( 0 == mem_size ) + return NULL; + return calloc( mem_size, 1 ); +} +static void OnMnslAmsFreeMemC( void *inst_ptr, void *mem_ptr, Mns_Ams_MemUsage_t type, void* custom_info_ptr ) +{ + if( NULL != mem_ptr ) + free( mem_ptr ); +} +static void OnIcmRx( void *inst_ptr, Msg_MostTel_t *pRx ) +{ + if (CheckMnswPointer(inst_ptr, "OnIcmRx")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMessage(pRx, mnsw->icm_inst_ptr); +} +static void OnRcmRx( void *inst_ptr, Msg_MostTel_t *pRx ) +{ + if (CheckMnswPointer(inst_ptr, "OnRcmRx")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMessage(pRx, mnsw->rcm_inst_ptr); +} +static void OnMcmRx( void *inst_ptr, Msg_MostTel_t *pRx ) +{ + if (CheckMnswPointer(inst_ptr, "OnMcmRx")) return; + CISNetServiceWrapper *mnsw = ( CISNetServiceWrapper * )inst_ptr; + mnsw->OnMessage(pRx, mnsw->mcm_inst_ptr); +} + +static void OnTransmissionStatus(void *self, Msg_MostTel_t *tel_ptr, Mns_MsgTxStatus_t status) +{ + if (MNS_MSG_STAT_OK != status) + { + ConsolePrintf(PRIO_ERROR, RED"Transmission failed for addr=0x%X FBlock=0x%X " \ + "Function=0x%X, error-code=0x%X"RESETCOLOR"\n", tel_ptr->destination_addr, + tel_ptr->id.fblock_id, tel_ptr->id.function_id, status); + } + Trcv_TxReleaseMsg(tel_ptr); +} + +#define TRACE_BUFFER_SZ 200 +#include <stdarg.h> +#include <stdio.h> +void My_TraceInfo(uint8_t mns_inst_id, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...) +{ + char_t outbuf[TRACE_BUFFER_SZ]; + va_list argptr; + uint16_t timestamp = GetTickCountWord(); + va_start(argptr, vargs_cnt); + vsprintf(outbuf, entry_str, argptr); + va_end(argptr); + ConsolePrintf(PRIO_HIGH, YELLOW"[%u] | %u | Info | %s | %s"RESETCOLOR"\n", mns_inst_id, timestamp, module_str, outbuf); +} + +void My_TraceError(uint8_t mns_inst_id, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...) +{ + char_t outbuf[TRACE_BUFFER_SZ]; + va_list argptr; + uint16_t timestamp = GetTickCountWord(); + va_start(argptr, vargs_cnt); + vsprintf(outbuf, entry_str, argptr); + va_end(argptr); + ConsolePrintf(PRIO_ERROR, RED"[%u] | %u | Error | %s | %s"RESETCOLOR"\n", mns_inst_id, timestamp, module_str, outbuf); +} diff --git a/Src/Network/IndustrialStack_MNS.h b/Src/Network/IndustrialStack_MNS.h new file mode 100644 index 0000000..7cb28ee --- /dev/null +++ b/Src/Network/IndustrialStack_MNS.h @@ -0,0 +1,84 @@ +/* + * 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 (NetService part). + */ +/*----------------------------------------------------------*/ + +#ifndef INDUSTRIAL_STACK_MNS_H +#define INDUSTRIAL_STACK_MNS_H + +#include <assert.h> +#include "IndustrialStack_Types.h" +#include "IndustrialStack_LLD.h" +#include "mns_types_cfg.h" +#include "mnsl.h" + +#define MNSW_TESTPATTERN ((uint32_t)0xA1B2C3D4) + +class IISNetServiceWrapperCB +{ +public: + virtual void OnReceivedMostMessage(CISMostMsg *rcvMessage) = 0; + virtual void OnSyncStateChanged(bool isSynced) = 0; + virtual void OnControlReadEnd() = 0; +}; + +class CISNetServiceWrapper : public CIndustrialStackLldCB +{ +public: + const uint32_t testPattern; + bool inicWriteError; + Mns_Lld_Api_t *pMnsInterface; + void *pMnsInst; + CTransceiver *icm_inst_ptr; + CTransceiver *rcm_inst_ptr; + CTransceiver *mcm_inst_ptr; +private: + CMnsl mnsl; + Mns_Lld_Callbacks_t pLldCb; + bool isSynced; + IISNetServiceWrapperCB *wrapperCB; + CIndustrialStackLld *lld; + +public: + CISNetServiceWrapper(uint8_t deviceApi, int controlRxHandle, int controlTxHandle); + virtual ~CISNetServiceWrapper(); + void ServiceMns(); + void AddListener(IISNetServiceWrapperCB *rcvListener); + + bool SendMostMessage(CISMostMsg *sndMessage); + void Unsynchronize(); + +public: + //Will be called from LLD, do not call directly + virtual void OnReadThreadEnd(CIndustrialStackLld *lld); + //All this functions will be called by the C wrappers, do not call them directly + void OnCtrlTxTransmit( Mns_Lld_TxMsg_t *msg_ptr); + void OnMnslEvent( Mnsl_Event_t event_code ); + void OnMessage( Msg_MostTel_t *pRx, CTransceiver *pTr ); +}; + +#endif //INDUSTRIAL_STACK_MNS_H diff --git a/Src/Network/IndustrialStack_Types.h b/Src/Network/IndustrialStack_Types.h new file mode 100644 index 0000000..21bba51 --- /dev/null +++ b/Src/Network/IndustrialStack_Types.h @@ -0,0 +1,159 @@ +/* + * 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 (type defnitions and common classes). + */ +/*----------------------------------------------------------*/ + +#ifndef INDUSTRIAL_STACK_TYPES_H +#define INDUSTRIAL_STACK_TYPES_H + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include "SafeVector.h" +typedef enum +{ + ISReturn_NoChange, + ISReturn_Success, + ISReturn_Failure, + ISReturn_Timeout +} ISReturn_t; + +typedef enum +{ + CISOpType_INVALID = 0xFF, + CISOpType_SET = 0x0, + CISOpType_GET = 0x1, + CISOpType_SETGET = 0x2, + CISOpType_INC = 0x3, + CISOpType_DEC = 0x4, + CISOpType_GETINTERFACE = 0x5, + CISOpType_STATUS = 0xC, + CISOpType_INTERFACE = 0xE, + CISOpType_ERROR = 0xF, + CISOpType_START = 0x0, + CISOpType_ABORT = 0x1, + CISOpType_STARTRESULT = 0x2, + CISOpType_STARTRESULTACK = 0x6, + CISOpType_ABORTACK = 0x7, + CISOpType_STARTACK = 0x8, + CISOpType_ERRORACK = 0x9, + CISOpType_PROCESSINGACK = 0xA, + CISOpType_PROCESSING = 0xB, + CISOpType_RESULT = 0xC, + CISOpType_RESULTACK = 0xD, + CISOpType_REPORTS = 0x9 +} CISOpType_t; + +class CIndustrialStack; +class IISElement; +class IISElementCallback; +class CISWaitElement; +class CISMostMsg; +class CSInternalEvent; +class CISSendMostMsgElement; +class CISDeviceQueue; +class CIndustrialStackLldCB; +class CV1_OnMostRx; +class CV2_OnMostRx; +class CV3_OnMostRx; + +class IISElement +{ +private: + int32_t refCount; +public: + const char *ElementName; + IISElementCallback *Callback; + IISElement() : refCount(1), ElementName("Not set"), Callback(NULL) { } + virtual ~IISElement() {} + + virtual ISReturn_t Service(CIndustrialStack *iStack, uint32_t time) = 0; + virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *rcvMessage) = 0; + + void AddReference() + { + ++refCount; + } + + void RemoveReference() + { + if( 0 == --refCount ) + delete this; + } +}; + +class CISMostMsg +{ +#define MAX_PAYLOAD_SIZE 45 +public: + bool IsValid; + uint32_t SourceAddress; + uint32_t TargetAddress; + uint32_t FBlock; + uint32_t Func; + uint32_t Inst; + CISOpType_t OpType; + uint32_t PayloadLen; + uint8_t Payload[MAX_PAYLOAD_SIZE]; + + CISMostMsg() : IsValid(false), SourceAddress(0xFFFFFFFF), TargetAddress(0xFFFFFFFF), + FBlock(0xFFFFFFFF), Func(0xFFFFFFFF), Inst(0xFFFFFFFF), + OpType(CISOpType_INVALID), PayloadLen(0) + { } + + void DeepCopy(CISMostMsg *msg) + { + IsValid = msg->IsValid; + SourceAddress = msg->SourceAddress; + TargetAddress = msg->TargetAddress; + FBlock = msg->FBlock; + Func = msg->Func; + Inst = msg->Inst; + OpType = msg->OpType; + PayloadLen = msg->PayloadLen; + memcpy(Payload, msg->Payload, PayloadLen); + } +}; + +class IISElementCallback +{ +public: + virtual void ElementProcessed(CIndustrialStack *iStack, ISReturn_t result, IISElement *element) = 0; +}; + +class CISDeviceQueue +{ +private: + uint16_t nodeAddress; +public: + CSafeVector<IISElement *> elements; + + CISDeviceQueue(uint16_t address) : nodeAddress(address) { } + uint16_t GetNodeAddress() { return nodeAddress; } +}; + +#endif //INDUSTRIAL_STACK_TYPES_H
\ No newline at end of file diff --git a/Src/Network/Network.cpp b/Src/Network/Network.cpp new file mode 100644 index 0000000..0c4b10d --- /dev/null +++ b/Src/Network/Network.cpp @@ -0,0 +1,433 @@ +/* + * 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. + * + */ + +#include <stdint.h> +#include <stddef.h> +#include "SafeVector.h" +#include "Network.h" +#include "NetworkDevice.h" +#include "DriverConfiguration.h" +#include "MacAddr.h" +#include "Board.h" +#include "Console.h" +#include "NodeDatabase.h" + +using namespace std; + +static CNetwork *staticInstance = NULL; +CSafeVector<CNetworkDevice *> CNetwork::allNetworkDevices; + +CNetwork::CNetwork() : CThread( "CNetwork", false ), allowNetworkRun( false ), + vodXml( NULL ), connectionBitMask( 0 ), promiscuous( false ), retryCounter( 0 ), + retryExecTime( 0 ) +{ + searchPath[0] = 0; + sem_init( &vodXmlMutex, 0, 1 ); //Mutex, initialized to 1 => sem_wait will block at 2nd call + Start(); +} + +CNetwork::~CNetwork() +{ + ConsolePrintf( PRIO_LOW, "Destructor of network called\r\n" ); + Stop(); + allowNetworkRun = false; + CloseAllNetworkDevices(); + sem_wait( &vodXmlMutex ); + if( NULL != vodXml ) + { + delete vodXml; + vodXml = NULL; + } + sem_post( &vodXmlMutex ); + staticInstance = NULL; + ConsolePrintf( PRIO_LOW, "end network\r\n" ); +} + +CNetwork *CNetwork::GetInstance( void ) +{ + if( NULL == staticInstance ) + { + staticInstance = new CNetwork(); + } + return staticInstance; +} + +void CNetwork::AddListener( CNetworkListner *listener ) +{ + allListeners.PushBack( listener ); +} + +void CNetwork::RemoveListener( CNetworkListner *listener ) +{ + allListeners.Remove(listener); +} + +void CNetwork::SetPromiscuousMode( bool enabled ) +{ + promiscuous = enabled; +} + +bool CNetwork::LoadConfig( char *szConfigXml ) +{ + uint32_t len = strlen(szConfigXml); + if( NULL == szConfigXml || 0 == len) + { + ConsolePrintf( PRIO_ERROR, RED"Path to config file was NULL"RESETCOLOR"\n" ); + return false; + } + if ('/' == szConfigXml[0]) + { + char path[300]; + uint32_t i; + uint32_t lastSlash = 0; + for (i = len - 1; i > 0; i--) + { + if ('/' == szConfigXml[i]) + { + lastSlash = i; + break; + } + } + memcpy(path, szConfigXml, lastSlash); + path[lastSlash] = '\0'; + memcpy(szConfigXml, &szConfigXml[lastSlash + 1], (len - lastSlash - 1) ); + szConfigXml[len - lastSlash - 1] = '\0'; + return LoadConfig(szConfigXml, path); + } + else + { + return LoadConfig(szConfigXml, NULL); + } +} + +bool CNetwork::LoadConfig( const char *szConfigXml, const char *szSearchPath ) +{ + char configPath[300]; + if( NULL == szConfigXml || 0 == strlen(szConfigXml)) + { + ConsolePrintf( PRIO_ERROR, RED"Path to config file was NULL"RESETCOLOR"\n" ); + return false; + } + if (NULL != szSearchPath) + strncpy( searchPath, szSearchPath, sizeof( searchPath ) ); + if( NULL != searchPath && '/' != szConfigXml[0]) + snprintf( configPath, sizeof( configPath ), "%s/%s", searchPath, szConfigXml ); + else + strncpy( configPath, szConfigXml, sizeof( configPath ) ); + + allowNetworkRun = true; + + sem_wait( &vodXmlMutex ); + bool success; + if( NULL != vodXml ) + { + delete vodXml; + } + vodXml = new CVodXml( configPath ); + success = ( NULL != vodXml ); + sem_post( &vodXmlMutex ); + + if ( allNetworkDevices.Size() != 0 ) + { + bool tm; + uint32_t bw; + if (vodXml->GetMostParameters( &tm, &bw ) ) + { + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + allNetworkDevices[i]->SetAsyncBandwidth(bw); + allNetworkDevices[i]->SetTimingMaster(tm); + ShutdownMost(allNetworkDevices[i]); + } + } + } + + if( success ) + FindNewNetworkDevices(); + + retryCounter = 0; + return success; +} + +bool CNetwork::ActionsPending() +{ + bool isPending = false; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( allNetworkDevices[i]->ActionsPending() ) + { + isPending = true; + break; + } + } + return isPending; +} + +bool CNetwork::ConnectSourceToSink( CMacAddr *SourceMacAddr, TChannelId SourceChannelId, CMacAddr *SinkMacAddr, + TChannelId SinkChannelId ) +{ + CNodeEntry *inNode = CNodeEntry::GetNodeEntry( SourceMacAddr ); + CNodeEntry *outNode = CNodeEntry::GetNodeEntry( SinkMacAddr ); + return ConnectSourceToSink( inNode, outNode, SourceChannelId, SinkChannelId ); +} + +uint8_t CNetwork::GetAmountOfLocalNodes() +{ + return allNetworkDevices.Size(); +} + +bool CNetwork::SendMostControlMessage( TMostInstace mostInstance, uint32_t targetAddr, uint32_t nFBlock, + uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ) +{ + bool success = false; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance ) + { + if (targetAddr < 0x300 || targetAddr > 0x3FF || targetAddr == 0x3C8) + { + success = allNetworkDevices[i]->SendMostControlMessage( mostInstance, targetAddr, nFBlock, nInst, nFunc, + nOpType, nPayloadLen, Payload ); + } + else + { + success = true; + for (uint16_t j = 0; j < CNodeEntry::GetAmountOfNodeEntries(); j++) + { + CNodeEntry *node = CNodeEntry::GetNodeEntry(j); + if (NULL != node && node->deviceInstance == mostInstance && + node->deviceType == targetAddr) + { + success &= allNetworkDevices[i]->SendMostControlMessage( mostInstance, node->nodeAddress, nFBlock, nInst, nFunc, + nOpType, nPayloadLen, Payload ); + } + } + } + break; + } + } + return success; +} + +bool CNetwork::SendMostControlMessage( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst, + uint32_t nFBlock, uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ) +{ + bool success = false; + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( mostInstance, deviceId, devInst ); + if( NULL == entry ) + return success; + + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance ) + { + success = allNetworkDevices[i]->SendMostControlMessage( mostInstance, entry->nodeAddress, nFBlock, nInst, + nFunc, nOpType, nPayloadLen, Payload ); + break; + } + } + return success; +} + +bool CNetwork::ExecuteXmlScriptFromFile( TMostInstace mostInstance, uint32_t targetAddr, const char *szFile ) +{ + if (NULL == szFile) + return false; + bool success = false; + char scriptPath[300]; + const char *pPath = szFile; + if( NULL != searchPath && '/' != szFile[0]) + { + snprintf( scriptPath, sizeof( scriptPath ), "%s/%s", searchPath, szFile ); + pPath = scriptPath; + } + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance ) + { + allNetworkDevices[i]->ExecuteMcmScript( targetAddr, pPath ); + success = true; + break; + } + } + return success; +} + +bool CNetwork::ExecuteXmlScriptFromFile( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst, + const char *szFile ) +{ + CNodeEntry *entry = CNodeEntry::GetNodeEntry( mostInstance, deviceId, devInst ); + if( NULL == entry ) + return false; + + return ExecuteXmlScriptFromFile( mostInstance, entry->nodeAddress, szFile ); +} + +bool CNetwork::ExecuteXmlScriptFromMemory( TMostInstace mostInstance, uint32_t targetAddr, const char *szBuffer, + uint32_t nBufferLen ) +{ + bool success = false; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance ) + { + allNetworkDevices[i]->ExecuteMcmScript( targetAddr, szBuffer, nBufferLen ); + success = true; + break; + } + } + return success; +} + +bool CNetwork::ExecuteXmlScriptFromMemory( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst, + const char *szBuffer, uint32_t nBufferLen ) +{ + CNodeEntry *entry = CNodeEntry::GetNodeEntry( mostInstance, deviceId, devInst ); + if( NULL == entry ) + return false; + + return ExecuteXmlScriptFromMemory( mostInstance, entry->nodeAddress, szBuffer, nBufferLen ); +} + +uint32_t CNetwork::GetCounterPartOfRoute( const Route_t *pInRoute, Route_t **pOutRouteArray ) +{ + if( ( NULL == pInRoute ) || ( NULL == pOutRouteArray ) ) + { + ConsolePrintf( PRIO_ERROR, RED"GetCounterPartOfRoute was called with wrong parameters"RESETCOLOR"\n" ); + return 0; + } + *pOutRouteArray = NULL; + CSafeVector<CRouteTerminal *> connectedTerminals; + CRouteTerminal terminal; + terminal.deviceType = pInRoute->deviceType; + terminal.instance = pInRoute->instance; + terminal.channelId = pInRoute->channelId; + + sem_wait( &vodXmlMutex ); + bool found = vodXml->GetRouteTerminals( &terminal, connectedTerminals ); + sem_post( &vodXmlMutex ); + if( !found ) + return 0; + uint32_t arrayLen = connectedTerminals.Size(); + *pOutRouteArray = ( Route_t * )calloc( arrayLen, sizeof( Route_t ) ); + if( NULL == *pOutRouteArray ) + { + ConsolePrintf( PRIO_ERROR, RED"GetCounterPartOfRoute failed to allocate memory"RESETCOLOR"\n" ); + return 0; + } + for( uint32_t i = 0; i < arrayLen; i++ ) + { + ( *pOutRouteArray )[i].deviceType = connectedTerminals[i]->deviceType; + ( *pOutRouteArray )[i].instance = connectedTerminals[i]->instance; + ( *pOutRouteArray )[i].channelId = connectedTerminals[i]->channelId; + } + return arrayLen; +} + +bool CNetwork::GetRingBreakDiagnosisResult( TMostInstace mostInstance, uint32_t targetAddr ) +{ + bool success = false; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( allNetworkDevices[i]->GetDeviceIndex() == mostInstance ) + { + allNetworkDevices[i]->GetRingBreakResultV3( 1, 0 ); + success = true; + break; + } + } + return success; +} + +void CNetwork::EnableMost(bool enabled) +{ + allowNetworkRun = enabled; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + CNetworkDevice *device = allNetworkDevices[i]; + if (enabled) + { + if (NetworkState_Available == device->GetNetState()) + { + ConsolePrintf(PRIO_ERROR, RED"MOST is already in NET ON state"RESETCOLOR"\n"); + return; + } + device->SetNetstate( NetworkState_Unknown ); + bool isTimingMaster = device->IsTimingMaster(); + uint32_t asyncBandwidth = device->GetAsyncBandwidth(); + if( isTimingMaster ) + device->MostNetworkStartupV3( 0xFFFF, asyncBandwidth ); + } + else + { + device->SetNetstate( NetworkState_ShutdownInProgress ); + device->ClearAllPendingActions(); + device->MostNetworkShutdownV3(); + } + } +} + +void CNetwork::Run() +{ + sleep( 5 ); + if (retryCounter > 0 && (GetTickCount() - retryExecTime >= 60000)) + retryCounter = 0; + if( allowNetworkRun ) + FindNewNetworkDevices(); +} + +/*---------------------------------------------*/ +/* Empty implementation of CNetworkListner */ +/*---------------------------------------------*/ + +void CNetworkListner::OnNetworkState( uint8_t mostInstance, bool available, uint8_t maxPos, uint16_t packetBW ) +{ + ConsolePrintf( PRIO_LOW, "CNetwork::OnNetworkState\n" ); +} + +void CNetworkListner::OnChannelAvailable( CMacAddr *macAddr, TDeviceId deviceId, uint8_t devInst, TChannelId channelId, + TMostInstace mostInstance, EPDataType_t dataType, TBlockwidth reservedBandwidth, bool isSourceDevice, + bool inSocketCreated, bool outSocketCreated, bool socketsConnected, int32_t bufferSize, + uint32_t mostConnectionLabel, int16_t splittedOffset, int16_t splittedMaxBandwidth, uint16_t packetsPerXact, + const char *deviceName ) +{ + ConsolePrintf( PRIO_LOW, "CNetwork::OnCharacterDeviceAvailable(%s)\n", deviceName ); +} + +void CNetworkListner::OnChannelUnavailable( CMacAddr *macAddr, TChannelId channelId, uint8_t mostInstance ) +{ + ConsolePrintf( PRIO_LOW, "CNetwork::OnChannelUnavailable\n" ); +} + +void CNetworkListner::OnMostControlMessage( uint8_t devInst, uint32_t sourceAddr, uint32_t targetAddr, + uint32_t nFBlock, uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ) +{ + ConsolePrintf( PRIO_LOW, "CNetwork::OnMostControlMessage\n" ); +} + +void CNetworkListner::OnRingBreakDiagnosisResultV3( uint8_t devInst, uint16_t nodeAddress, uint8_t result, + uint8_t position, uint8_t status, uint16_t id ) +{ + ConsolePrintf( PRIO_LOW, "CNetwork::OnRingBreakDiagnosisResultV2\n" ); +} diff --git a/Src/Network/Network.h b/Src/Network/Network.h new file mode 100644 index 0000000..749e903 --- /dev/null +++ b/Src/Network/Network.h @@ -0,0 +1,498 @@ +/* + * 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 CNetworkListner class. + */ +/*----------------------------------------------------------*/ +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include "SafeVector.h" +#include "Types.h" +#include "Thread.h" +#include "MacAddr.h" +#include "NetworkDevice.h" +#include "NetworkDeviceListener.h" +#include "VodXml.h" + +/*----------------------------------------------------------*/ +/*! \brief CNetworkListner class shall be derived from classes, which want them self to be registered as callback to the CNetwork class. + */ +/*----------------------------------------------------------*/ +class CNetworkListner +{ +public: + /*----------------------------------------------------------*/ + /*! \brief This callback method is called whenever there is a new channel information available. + * \note In order to be informed about this event, derive this class, implement this method and register the class with AddListener method of CNetwork class. + * \param mostInstance - The instance number of the MOST bus. If the server device has more then one physical MOST devices, each ring + * is identified by a unique id starting with 0 for the first MOST instance. + * \param available - true, if the network is fully usable. false, otherwise. + * \param maxPos - The amount of devices found in the network (inclusive master) + * \param packetBW - Amount of bytes reserved for Ethernet data (multiple with 48000 to get Byte/s) + */ + /*----------------------------------------------------------*/ + virtual void OnNetworkState( uint8_t mostInstance, bool available, uint8_t maxPos, uint16_t packetBW ); + + /*----------------------------------------------------------*/ + /*! \brief This callback method is called whenever there is a new channel information available. + * \note In order to be informed about this event, derive this class, implement this method and register the class with AddListener method of CNetwork class. + * \param macAddr - The MAC address identifying the device unique. + * \param deviceId - The device identifier (group address) as specified in the XML file. + * \param devInst - The instance number of the device. Starting with 0 for the first device with deviceId. + * \param channelId - The channel identifier as specified in the XML file, given by "LoadConfig"-method of CNetwork class. + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring. + * \param dataType - The MOST data used by this channel. + * \param reservedBandwidth - The reserved MOST bandwidth in bytes for this channel. + * is identified by a unique id starting with 0 for the first MOST instance. + * \param isSourceDevice - true, if this device acts as source. false, if this device acts as sink. + * \param inSocketCreated - true, if the in-socket of the connection was created. false, there is no in-socket available at the moment. + * \param outSocketCreated - true, if the out-socket of the connection was created. false, there is no out-socket available at the moment. + * \param socketsConnected - true, if the in- and the out-socket are connected. + * \param splittedOffset - If this socket is a splitted / combined socket, this value holds the offset in byte. -1 if this is a normal socket. + * \param splittedMaxBandwidth - If this socket is a splitted / combined socket, this value holds the maximum bandwidth of all splitted sockets in byte. -1 if this is a normal socket. + * \param bufferSize - The amount of bytes reserved for this channel in Driver. If no buffers were allocated, this value is -1. + * \param packetsPerXactconst, This is USB specific. It describes how many sub-frames are concatenated into a single USB microframe. + * \param deviceName - The name of the Linux character device. May be NULL if the device is a remote device. + */ + /*----------------------------------------------------------*/ + virtual void OnChannelAvailable( CMacAddr *macAddr, TDeviceId deviceId, uint8_t devInst, TChannelId channelId, + TMostInstace mostInstance, EPDataType_t dataType, TBlockwidth reservedBandwidth, bool isSourceDevice, + bool inSocketCreated, bool outSocketCreated, bool socketsConnected, int32_t bufferSize, + uint32_t mostConnectionLabel, int16_t splittedOffset, int16_t splittedMaxBandwidth, + uint16_t packetsPerXact, const char *deviceName ); + + + /*----------------------------------------------------------*/ + /*! \brief This callback method is called whenever a channel has become unavailable. + * \note In order to be informed about this event, derive this class, implement this method and register the class with AddListener method of CNetwork class. + * \param macAddr - The MAC address identifying the device unique. + * \param channelId - The channel identifier as specified in the XML file, given by "LoadConfig"-method of CNetwork class. + * \param mostInstance - The instance number of the MOST bus. If the server device has more then one physical MOST devices, each ring + * is identified by a unique id starting with 0 for the first MOST instance. + */ + /*----------------------------------------------------------*/ + virtual void OnChannelUnavailable( CMacAddr *macAddr, TChannelId channelId, uint8_t mostInstance ); + + + /*----------------------------------------------------------*/ + /*! \brief This callback method is called whenever a MOST control message was sent or received. + * \note In order to be informed about this event, derive this class, implement this method and register the class with AddListener method of CNetwork class. + * \note The user may interpret the data and sent a corresponding MOST control message via CNetwork::SendMostControlMessage. + * \param devInst - The MOST ring instance, starting with 0 for the first MOST ring. + * \param sourceAddr - The MOST source address (may be not accurate) + * \param targetAddr - The MOST target address + * \param nFBlock - The MOST Function Block Identifier + * \param nInst - The MOST Function Block Instance Identifier + * \param nFunc - The MOST Function Block Function Identifier + * \param nPayloadLen - The amount of bytes stored in Payload + * \param Payload - The pointer to the payload byte array. + */ + /*----------------------------------------------------------*/ + virtual void OnMostControlMessage( uint8_t devInst, uint32_t sourceAddr, uint32_t targetAddr, uint32_t nFBlock, + uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ); + + /*----------------------------------------------------------*/ + /*! \brief Callback, when a Ring Break Diagnosis Result was received. + * \param devInst - The MOST ring instance, starting with 0 for the first MOST ring. + * \param nodeAddr - The device with this MOST node address raised this event. + * \praram result - The ring break diagnosis result + * \param position - Relative position to the ring break. + * \param status - Gives information about the activity state. + * \param id - The RBD identifier as configured in config string. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnRingBreakDiagnosisResultV3( uint8_t devInst, uint16_t nodeAddress, uint8_t result, + uint8_t position, uint8_t status, uint16_t id ); +}; + +/*----------------------------------------------------------*/ +/*! \brief CNetwork represents the main controlling class, which opens and setup MOST connections. +*/ +/*----------------------------------------------------------*/ +class CNetwork : public CNetworkDeviceListener, public CThread +{ + +private: + bool allowNetworkRun; + char searchPath[256]; + CSafeVector<CNetworkListner *> allListeners; + static CSafeVector<CNetworkDevice *> allNetworkDevices; + CVodXml *vodXml; + sem_t vodXmlMutex; + uint32_t connectionBitMask; + bool promiscuous; + uint32_t retryCounter; + uint32_t retryExecTime; + + CNetwork(); + + void DestroyAllResources( CNetworkDevice *device, uint16_t nodeAddress ); + + void CloseAllNetworkDevices(); + + void DestroyAllResources(); + + void FindNewNetworkDevices(); + + void TryToCreateRoute( uint32_t devInstance, bool mostIsTx, void *entry, void *terminal ); + + void TryToConnectSockets( uint32_t devInstance, uint16_t nodeAddr, uint32_t channelId ); + + void TryToCloseExistingMostConnection( void *inNode, uint32_t channelId, void *outNode, uint32_t outChannelId ); + + void RaiseAvailable( void *connection ); + + void RaiseUnavailable( void *connection ); + + CNetworkDevice *GetNetworkDevice( uint32_t devInstance ); + + CMacAddr *SetMacAddress( CNetworkDevice *device, uint32_t devInstance, uint16_t nodeAddress, + uint8_t inicApiVersion ); + + bool ConnectSourceToSink( void *mostTxNode, void *mostRxNode, uint32_t sourceChannelId, uint32_t sinkChannelId ); + + void RaiseUknownConnection( uint32_t devInstance, uint16_t nodeAddress, EPDataType_t dType ); + + void ShutdownMost( CNetworkDevice *device ); + + void ShutdownMostBecauseOfErrors( CNetworkDevice *device ); + + virtual void OnSync( void *source, bool isSynced ); + + virtual void OnNetworkState( void *source, bool mpValChanged, bool systemNotOk, + bool mostAvailable, uint8_t availableSubState, uint8_t availableTransition, uint16_t nodeAddress, + uint8_t nodePos, uint8_t maxPos, uint16_t packetBW ); + + virtual void OnNetworkStartupV3( void *source, bool success ); + + virtual void OnNetworkShutdownV3( void *source, bool success ); + + virtual void OnMostDeviceType( void *source, bool success, uint16_t nodeAddress, uint16_t deviceType ); + + virtual void OnCreateTsiSocketV1( void *source, bool success, uint16_t nodeAddr, V1TsiPortInstance_t tsiPortInst, + EPDataType_t epType, EPDirection_t epDir, uint16_t blockWidthTsi, uint16_t socketHandle, uint32_t tag ); + + virtual void OnCreateMlbSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ); + + virtual void OnCreateMostSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ); + + virtual void OnConnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t inSocketHandle, + uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ); + + virtual void OnDestroySocketV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, uint32_t tag ); + + virtual void OnDisconnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, uint32_t tag ); + + virtual void OnCreateI2SSocketV1( void *source, bool success, uint16_t nodeAddr, EPDirection_t epDir, + uint16_t blockWidthI2S, V1I2SPin_t pin, uint16_t socketHandle, uint32_t tag ); + + virtual void OnCreateUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t socketHandle, uint32_t tag ); + + virtual void OnCreateSplittedUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t usbHandle, uint16_t splitterHandle, uint32_t tag ); + + virtual void OnCreateMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ); + + virtual void OnCreateSplittedMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t mlbSocketHandle, + uint16_t splitterHandle, uint32_t tag ); + + virtual void OnCreateI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t socketHandle, uint32_t tag ); + + virtual void OnCreateSplittedI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t i2sSocketHandle, uint16_t splitterHandle, + uint32_t tag ); + + virtual void OnCreateMostSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ); + + virtual void OnConnectSocketsV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + uint16_t inSocketHandle, uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ); + + virtual void OnControlChannelReadEnd( void *source ); + + virtual void OnMostControlMessage( void *source, uint32_t sourceAddr, uint32_t targetAddr, uint32_t nFBlock, + uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ); + + virtual void OnRbdResultV3( void *source, uint16_t nodeAddress, uint8_t result, uint8_t position, + uint8_t status, uint16_t id ); + + virtual void OnMostMacAddress( void *source, bool success, uint16_t nodeAddress, uint8_t macAddress1, + uint8_t macAddress2, uint8_t macAddress3, uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6 ); + + virtual void OnConfigureI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortOption_t option, V3I2SClockMode_t mode, V3I2SDelayMode_t delay, uint32_t tag ); + + virtual void OnCreateI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortSpeed_t clock, V3I2SAlignment_t align, uint32_t tag ); + + virtual void OnDeviceVersion( void *source, bool success, uint32_t sourceAddr, + uint32_t productId, uint32_t fwVersion, uint32_t buildVersion, + uint8_t hwVersion, uint16_t diagnosisId, uint32_t tag ); +public: + /*----------------------------------------------------------*/ + /*! \brief Destructor of CNetwork. + */ + /*----------------------------------------------------------*/ + virtual ~CNetwork(); + + + + //Singleton pattern, there can only be one manager + /*----------------------------------------------------------*/ + /*! \brief Gets the singleton instance of CNetwork (Only one object). + * \return Pointer to the singleton object. + */ + /*----------------------------------------------------------*/ + static CNetwork *GetInstance( void ); + + + + /*----------------------------------------------------------*/ + /*! \brief Registers the given CNetworkListener to this component. + * If there are events, all registered listeners will be called back. + * \note Multiple listerners are supported. + * \param listener- Class derivating CNetworkListener base class. This class will be called back on events. + */ + /*----------------------------------------------------------*/ + void AddListener( CNetworkListner *listener ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Deregisters the given CNetworkListener from this component. + * The given object will no longer be called back. + * \param listener- Class derivating CNetworkListener base class. This class will not be called after this method call. + */ + /*----------------------------------------------------------*/ + void RemoveListener( CNetworkListner *listener ); + + + /*----------------------------------------------------------*/ + /*! \brief Enables or Disables the promiscuous mode on MEP channel. If enabled, tools like Wireshark will capture every packet. + * \param enabled - true, promiscuous mode. false, perfect match filter with multicast and broadcast enabled. + */ + /*----------------------------------------------------------*/ + void SetPromiscuousMode( bool enabled ); + + + /*----------------------------------------------------------*/ + /*! \brief Loads a XML file holding information about connections and devices. + * \param szConfigXml - string holding only the filename to the XML file. + * \note This method tries to extract the search path from the given string. Therefor it must start with '/'. + * \note The given string will be modified by this method. Don't use it anymore after wise! + * \return true, if successful, false otherwise + */ + /*----------------------------------------------------------*/ + bool LoadConfig( char *szConfigXml ); + + + + /*----------------------------------------------------------*/ + /*! \brief Loads a XML file holding information about connections and devices. + * \param szConfigXml - string holding only the filename to the XML file. + * \param szSearchPath - string holding the path to all the XML files. + * \return true, if successful, false otherwise + */ + /*----------------------------------------------------------*/ + bool LoadConfig( const char *szConfigXml, const char *szSearchPath ); + + + + /*----------------------------------------------------------*/ + /*! \brief Checks if there are pending actions enqueued. + * \note This method blocks, until the result (true / false is reported by the subprocess). + * \return true, when there are pending actions in the queue. false, otherwise + */ + /*----------------------------------------------------------*/ + bool ActionsPending(); + + + + + /*----------------------------------------------------------*/ + /*! \brief Connects a source to sink according to the configuration of the XML file, provided by LoadConfig method. + * \param SourceMacAddr - The MAC address of the source device, reported by the OnChannelAvailable callback method. + * \param SourceChannelId - The channel identifier of the source as specified in the XML file and reported by + * the OnChannelAvailable callback method. + * \param SinkMacAddr - The MAC address of the sink device, reported by the OnChannelAvailable callback method. + * \param SourceChannelId - The channel identifier of the sink as specified in the XML file and reported by + * the OnChannelAvailable callback method. + * \return true, if succesful. false, otherwise + */ + /*----------------------------------------------------------*/ + bool ConnectSourceToSink( CMacAddr *SourceMacAddr, TChannelId SourceChannelId, CMacAddr *SinkMacAddr, + TChannelId SinkChannelId ); + + + + /*----------------------------------------------------------*/ + /*! \brief Retrieves the amount of connected INIC nodes. + * \return The amount of local connected INIC nodes. + */ + /*----------------------------------------------------------*/ + uint8_t GetAmountOfLocalNodes(); + + + /*----------------------------------------------------------*/ + /*! \brief Sends the given Control Message out to the given MOST ring + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param targetAddr - The MOST target address (0x100, 0x401, etc..) + * \param nFBlock - The MOST Function Block Identifier + * \param nInst - The MOST Function Block Instance Identifier + * \param nFunc - The MOST Function Block Function Identifier + * \param nPayloadLen - The amount of bytes stored in Payload + * \param Payload - The pointer to the payload byte array. + */ + /*----------------------------------------------------------*/ + bool SendMostControlMessage( TMostInstace mostInstance, uint32_t targetAddr, uint32_t nFBlock, uint32_t nInst, + uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ); + + + /*----------------------------------------------------------*/ + /*! \brief Sends the given Control Message out to the given MOST ring + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param deviceId - The device identifier (group address) as specified in the XML file + * \param devInst - The instance number of the device. Starting with 0 for the first device with deviceId + * \param nFBlock - The MOST Function Block Identifier + * \param nInst - The MOST Function Block Instance Identifier + * \param nFunc - The MOST Function Block Function Identifier + * \param nPayloadLen - The amount of bytes stored in Payload + * \param Payload - The pointer to the payload byte array. + */ + /*----------------------------------------------------------*/ + bool SendMostControlMessage( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst, uint32_t nFBlock, + uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ); + + + /*----------------------------------------------------------*/ + /*! \brief Executes a given XML script by it's filename and MOST target address + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param targetAddr - The MOST target address (0x100, 0x401, etc..) + * \param szFile - Path to the XML file (zero terminated string) + */ + /*----------------------------------------------------------*/ + bool ExecuteXmlScriptFromFile( TMostInstace mostInstance, uint32_t targetAddr, const char *szFile ); + + + /*----------------------------------------------------------*/ + /*! \brief Executes a given XML script by it's filename, device identifier and device instance + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param deviceId - The device identifier (group address) as specified in the XML file + * \param devInst - The instance number of the device. Starting with 0 for the first device with deviceId + * \param szFile - Path to the XML file (zero terminated string) + */ + /*----------------------------------------------------------*/ + bool ExecuteXmlScriptFromFile( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst, + const char *szFile ); + + + /*----------------------------------------------------------*/ + /*! \brief Executes a given XML script directly by it's content stored in the memory and MOST target address + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param targetAddr - The MOST target address (0x100, 0x401, etc..) + * \param szBuffer - The Buffer containing the XML script + * \param nBufferLen - The length of the XML script stored in szBuffer + */ + /*----------------------------------------------------------*/ + bool ExecuteXmlScriptFromMemory( TMostInstace mostInstance, uint32_t targetAddr, const char *szBuffer, + uint32_t nBufferLen ); + + + /*----------------------------------------------------------*/ + /*! \brief Executes a given XML script by it's filename, device identifier and device instance + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param targetAddr - The MOST target address (0x100, 0x401, etc..) + * \param szBuffer - The Buffer containing the XML script + * \param nBufferLen - The length of the XML script stored in szBuffer + */ + /*----------------------------------------------------------*/ + bool ExecuteXmlScriptFromMemory( TMostInstace mostInstance, TDeviceId deviceId, uint8_t devInst, + const char *szBuffer, uint32_t nBufferLen ); + + /*! + * \brief Storage class for channel related informations. This class will be returned by + * the CVodXml class. + */ + typedef struct + { + /// Determines the device type as specified in the configuration XML file and found in the group address configuration. + uint32_t deviceType; + + /// instance number of the device found in the network + uint32_t instance; + + /// Determines the used channel id, as specified in the configuration XML file. + uint32_t channelId; + } Route_t; + + /*----------------------------------------------------------*/ + /*! \brief Sends the given Control Message out to the given MOST ring. + * \param pInRoute - Pointer to the route to search the counter part of. + * \param pOutRouteArray - Pointer to pointer, which then the result array will be stored, maybe NULL! + * \return The array length of pOutRouteArray, maybe 0! + * \note The pOutRouteArray must be freed by the user after usage! + */ + /*----------------------------------------------------------*/ + uint32_t GetCounterPartOfRoute( const Route_t *pInRoute, Route_t **pOutRouteArray ); + + + /*----------------------------------------------------------*/ + /*! \brief Retrieves the stored result of the Ring Break Diagnosis + * \param mostInstance - The MOST ring instance, starting with 0 for the first MOST ring + * \param targetAddr - The MOST target address (0x100, 0x401, etc..) + * \return true, if successful, false otherwise + */ + /*----------------------------------------------------------*/ + bool GetRingBreakDiagnosisResult( TMostInstace mostInstance, uint32_t targetAddr ); + + + /*----------------------------------------------------------*/ + /*! \brief Enables or disables all MOST rings. + * \note This is thought for debug reasons only. Normally this method must not be called. + * \param enabled - TRUE, all MOST rings will start up. FALSE, all MOST rings will shutdown. + */ + /*----------------------------------------------------------*/ + void EnableMost(bool enabled); + + /*----------------------------------------------------------*/ + /*! \brief Function of background thread. + * \note Never call this method. It is used by internal threads. + */ + /*----------------------------------------------------------*/ + void Run(); + +}; + + +#endif diff --git a/Src/Network/NetworkDevice.cpp b/Src/Network/NetworkDevice.cpp new file mode 100644 index 0000000..5308215 --- /dev/null +++ b/Src/Network/NetworkDevice.cpp @@ -0,0 +1,903 @@ +/* + * 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. + * + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include "NetworkDevice.h" +#include "DriverConfiguration.h" +#include "Board.h" +#include "ScriptXml.h" +#include "IndustrialStack_ApiV1.h" +#include "IndustrialStack_ApiV3.h" +#include "IndustrialStack_ApiGeneric.h" + +CNetworkDevice::CNetworkDevice( uint8_t index, uint8_t api, bool master, uint32_t asyncBW, bool promiscuousMode ) : +CThread( "CNetworkDevice", false ), promiscuous( promiscuousMode ), netState( NetworkState_Unknown ), + pInic( NULL ), pScriptMemoryArea( NULL ), isRunning( false ), + isActionPending( false ), deviceIndex( index ), deviceApi( api ), + isTimingMaster( master ), asyncBandwidth( asyncBW ), + controlEndpointRxHandle( -1 ), controlEndpointTxHandle( -1 ), + startV3autoForced( 0xFFFF ), startV3packetBW( 0xFFFF ) +{ + responseToWaitFor[0] = '\0'; + deviceNameControlRx[0] = '\0'; + deviceNameControlTx[0] = '\0'; + + sem_init( &methodMutex, 0, 0 ); //Mutex, initialized to 0 => sem_wait will block +} + +CNetworkDevice::~CNetworkDevice() +{ + Stop(); + CloseMostControlChannel(); + if (NULL != iStack) + { + delete iStack; + iStack = NULL; + } + if (NULL != v1Events) + { + delete v1Events; + v1Events = NULL; + } + if (NULL != v3Events) + { + delete v3Events; + v3Events = NULL; + } +} + +bool CNetworkDevice::OpenDevice( const char *systemNameControlRx, const char *systemNameControlTx, + const char *linkNameControlRx, const char *linkNameControlTx ) +{ + ConsolePrintf( PRIO_LOW, "SYS RX:%s\nSYS TX:%s\nLINK RX:%s\nLINK TX:%s\n", systemNameControlRx, + systemNameControlTx, linkNameControlRx, linkNameControlTx ); + + CloseMostChannel( systemNameControlRx ); + CloseMostChannel( systemNameControlTx ); + + bool success = ConfigureMostChannel( systemNameControlRx, EP_Control, EPDIR_OUT, 32, 128 ); + + if( success ) + { + success = ConfigureMostChannel( systemNameControlTx, EP_Control, EPDIR_IN, 32, 128 ); + } + + if( success ) + { + success = LinkToCharacterDevice( linkNameControlRx, deviceNameControlRx ); + } + + if( success ) + { + success = LinkToCharacterDevice( linkNameControlTx, deviceNameControlTx ); + } + + if( success ) + { + if( OpenMostControlChannel() ) + { + isRunning = true; + Start(); + } + else + { + ConsolePrintf( PRIO_ERROR, RED"MOST control channel startup failed"RESETCOLOR"\n" ); + } + + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"NetworkDevice: Open device aborted, because of channel configuration issues"RESETCOLOR"\n" ); + } + return success; +} + +bool CNetworkDevice::OpenUsb( uint8_t controlRxEndpointAddress, uint8_t controlTxEndpointAddress ) +{ + char systemNameControlRx[64]; + char systemNameControlTx[64]; + char linkNameControlRx[64]; + char linkNameControlTx[64]; + bool success = GetUsbDeviceNames( deviceIndex, controlRxEndpointAddress, + deviceNameControlRx, sizeof( deviceNameControlRx ), systemNameControlRx, sizeof( systemNameControlRx ), + linkNameControlRx, sizeof( linkNameControlRx ) ); + + if( success ) + success = GetUsbDeviceNames( deviceIndex, controlTxEndpointAddress, + deviceNameControlTx, sizeof( deviceNameControlTx ), systemNameControlTx, sizeof( systemNameControlTx ), + linkNameControlTx, sizeof( linkNameControlTx ) ); + + if( success ) + success = OpenDevice( systemNameControlRx, systemNameControlTx, linkNameControlRx, linkNameControlTx ); + + if( ! success ) + ConsolePrintf( PRIO_ERROR, RED"NetworkDevice: Failed to open USB device"RESETCOLOR"\n" ); + + return success; +} + +bool CNetworkDevice::OpenMlb( uint8_t controlRxChannelAddress, uint8_t controlTxChannelAddress ) +{ + char systemNameControlRx[64]; + char systemNameControlTx[64]; + char linkNameControlRx[64]; + char linkNameControlTx[64]; + bool success = GetMlbDeviceNames( deviceIndex, controlRxChannelAddress, + deviceNameControlRx, sizeof( deviceNameControlRx ), systemNameControlRx, sizeof( systemNameControlRx ), + linkNameControlRx, sizeof( linkNameControlRx ) ); + + if( success ) + success = GetMlbDeviceNames( deviceIndex, controlTxChannelAddress, + deviceNameControlTx, sizeof( deviceNameControlTx ), systemNameControlTx, sizeof( systemNameControlTx ), + linkNameControlTx, sizeof( linkNameControlTx ) ); + + if( success ) + success = OpenDevice( systemNameControlRx, systemNameControlTx, linkNameControlRx, linkNameControlTx ); + + if( ! success ) + ConsolePrintf( PRIO_ERROR, RED"NetworkDevice: Failed to open MLB device"RESETCOLOR"\n" ); + + return success; +} + +bool CNetworkDevice::OpenI2C() +{ + char systemNameControlRx[64]; + char systemNameControlTx[64]; + char linkNameControlRx[64]; + char linkNameControlTx[64]; + bool success = GetI2CDeviceNames( deviceIndex, false, deviceNameControlRx, sizeof( deviceNameControlRx ), + systemNameControlRx, sizeof( systemNameControlRx ), linkNameControlRx, sizeof( linkNameControlRx ) ); + + if( success ) + success = GetI2CDeviceNames( deviceIndex, true, deviceNameControlTx, sizeof( deviceNameControlTx ), + systemNameControlTx, sizeof( systemNameControlTx ), linkNameControlTx, sizeof( linkNameControlTx ) ); + + if( success ) + success = OpenDevice( systemNameControlRx, systemNameControlTx, linkNameControlRx, linkNameControlTx ); + + if( ! success ) + ConsolePrintf( PRIO_ERROR, RED"NetworkDevice: Failed to open I2C device"RESETCOLOR"\n" ); + + return success; +} + +void CNetworkDevice::Close() +{ + int32_t timeoutVal = 10; //10 Seconds + while( timeoutVal-- > 0 ) + { + if( iStack->ElementsPending() ) + { + ConsolePrintf( PRIO_MEDIUM, "NetworkDevice: Closing delayed, Actions pending..\n" ); + usleep( 1000000 ); + } + else + { + break; + } + } + sem_post( &methodMutex ); + isRunning = false; + Stop(); + for( uint32_t timeout = 0; timeout < 100; timeout++ ) + { + if( !IsThreadRunning() ) + break; + usleep( 10000 ); + } + ConsolePrintf( PRIO_LOW, "NetworkDevice: Closed..\n" ); +} + +uint8_t CNetworkDevice::GetDeviceApi() +{ + return deviceApi; +} + +NetworkState_t CNetworkDevice::GetNetState() +{ + return netState; +} + +void CNetworkDevice::SetNetstate( NetworkState_t newState ) +{ + netState = newState; +} + + void CNetworkDevice::SetTimingMaster(bool tm) + { + isTimingMaster = tm; + } + +bool CNetworkDevice::IsTimingMaster() +{ + return isTimingMaster; +} + +void CNetworkDevice::SetAsyncBandwidth(uint32_t bw) +{ + asyncBandwidth = bw; +} + +uint32_t CNetworkDevice::GetAsyncBandwidth() +{ + return asyncBandwidth; +} + +bool CNetworkDevice::ActionsPending() +{ + if( NULL == iStack || !isRunning ) + return true; + return iStack->ElementsPending(); +} + +void CNetworkDevice::ClearAllPendingActions() +{ + if( NULL == iStack ) + return; + iStack->ClearAllElements(); +} + +void CNetworkDevice::AddListener( CNetworkDeviceListener *listener ) +{ + allListeners.PushBack( listener ); +} + +uint32_t CNetworkDevice::GetAmountOfListners() +{ + return allListeners.Size(); +} + +CNetworkDeviceListener *CNetworkDevice::GetListener( uint32_t instance ) +{ + return allListeners[instance]; +} + +uint8_t CNetworkDevice::GetDeviceIndex() +{ + return deviceIndex; +} + +void CNetworkDevice::ScriptPause( uint32_t timeInMillis ) +{ + CISWaitElement *waitElement = new CISWaitElement(); + waitElement->SetTimeout(timeInMillis); + iStack->EnqueueElement(0x1, waitElement); + waitElement->RemoveReference(); +} + +void CNetworkDevice::ExecuteMcmScript( uint16_t nodeAddress, CSciptXml *scriptXml ) +{ + if( NULL == scriptXml ) + { + ConsolePrintf( + PRIO_ERROR, RED"ExecuteMcmScript failed to retrieve scripts from XML file"RESETCOLOR"\n" ); + return; + } + CSafeVector<CScript *> allScripts; + if( scriptXml->GetScripts( allScripts ) ) + { + for (uint32_t i = 0; i < allScripts.Size(); i++ ) + { + CScript *script = allScripts[i]; + if( NULL == script ) + continue; + switch( script->scriptType ) + { + case SCRIPT_MCM_SEND: + { + CGeneric_SendMostMessage *a = new CGeneric_SendMostMessage( + script->payload, script->payloadLength, nodeAddress, + script->fblockId, 0, script->functionId, script->opTypeRequest, + script->opTypeResponse); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); + break; + } + case SCRIPT_PAUSE: + { + CISWaitElement *waitElement = new CISWaitElement(); + waitElement->SetTimeout(script->pauseInMillis); + iStack->EnqueueElement(nodeAddress, waitElement); + waitElement->RemoveReference(); + break; + } + default: + ConsolePrintf( PRIO_ERROR, + YELLOW"ExecuteMcmScript ignoring unknown script type:%d"RESETCOLOR"\n", + script->scriptType ); + break; + } + } + } + allScripts.RemoveAll(true); +} + +void CNetworkDevice::ExecuteMcmScript( uint16_t nodeAddress, const char *pPathToScriptXml ) +{ + if( NULL == pPathToScriptXml ) + { + ConsolePrintf( PRIO_ERROR, RED"ExecuteMcmScript (from file) was called with invalid parameter"RESETCOLOR"\n" ); + return; + } + ConsolePrintf( PRIO_MEDIUM, "##### Executing MCM script from file: Address:%X '%s'\n", nodeAddress, + pPathToScriptXml ); + CSciptXml *scriptXml = new CSciptXml( pPathToScriptXml ); + ExecuteMcmScript( nodeAddress, scriptXml ); +} + +void CNetworkDevice::ExecuteMcmScript( uint16_t nodeAddress, const char *pStringBuffer, uint32_t bufferLength ) +{ + if( NULL == pStringBuffer || 0 == bufferLength ) + { + ConsolePrintf( PRIO_ERROR, RED"ExecuteMcmScript (from memory) was called with invalid parameter"RESETCOLOR"\n" ); + return; + } + ConsolePrintf( PRIO_MEDIUM, "##### Executing MCM script from memory: Address:%X buffer-len:\n", nodeAddress, + bufferLength ); + CSciptXml *scriptXml = new CSciptXml( pStringBuffer, bufferLength ); + ExecuteMcmScript( nodeAddress, scriptXml ); +} + +void CNetworkDevice::ToggleNotOk() +{ + CGeneric_SendConfigOk *a = new CGeneric_SendConfigOk(false); + iStack->EnqueueElement(0x3C8, a); + a->RemoveReference(); + + CGeneric_SendConfigOk *b = new CGeneric_SendConfigOk(true); + iStack->EnqueueElement(0x3C8, b); + b->RemoveReference(); +} + +void CNetworkDevice::GetMacAddress( uint16_t nodeAddress ) +{ + CGeneric_GetMacAddress *a = new CGeneric_GetMacAddress(nodeAddress); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::GetGroupAddresses( uint8_t maxNodePos ) +{ + for( uint32_t i = 0x400; maxNodePos != 0xFF && i < 0x400 + ( uint32_t )maxNodePos; i++ ) + { + uint16_t n = ( i == 0x400 ? 1 : i ); + CGeneric_GetGroupAddress *a = new CGeneric_GetGroupAddress(n); + iStack->EnqueueElement(n, a); + a->RemoveReference(); + } +} + +void CNetworkDevice::SetMostMacAddressV1( uint16_t nodeAddress, uint8_t macAddress1, uint8_t macAddress2, + uint8_t macAddress3, uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6, bool persistent ) +{ + CV1_ChangeEUI48 *a = new CV1_ChangeEUI48(this, nodeAddress, macAddress1, macAddress2, + macAddress3, macAddress4, macAddress5, macAddress6, persistent); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::StartMostV1( bool isTimingMaster, uint16_t packetBandWidth ) +{ + CV1_NetworkStartup *a = new CV1_NetworkStartup(this, isTimingMaster, packetBandWidth); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::MostNetworkShutdownV1() +{ + CISWaitForPendingElements *w = new CISWaitForPendingElements(0x1); + iStack->EnqueueElement(0x1, w); + w->RemoveReference(); + + CV1_NetworkShutdown *a = new CV1_NetworkShutdown(this); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::OpenTsiV1( uint16_t nodeAddress, V1TsiPortInstance_t tsiPortId, V1TsiPortMode tsiPortMode ) +{ + if (V1TsiPortInstanceNotSet == tsiPortId || V1TsiPortModeNotSet == tsiPortMode) + return; + CV1_TsiPortCreate *a = new CV1_TsiPortCreate(this, nodeAddress, tsiPortId, tsiPortMode); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateTsiSocketV1( uint16_t nodeAddress, V1TsiPortInstance_t portInst, + EPDataType_t epType, EPDirection_t epDir,uint16_t blockWidthTsi, uint32_t tag ) +{ + CV1_TsiSocketCreate *a = new CV1_TsiSocketCreate(this, nodeAddress, portInst, + epType, epDir, blockWidthTsi, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::OpenMlbV1( uint16_t nodeAddress, MlbPortSpeed_t mlbSpeed ) +{ + if( MlbSpeedNotSet == mlbSpeed ) + return; + CV1_MlbPortCreate *a = new CV1_MlbPortCreate(this, nodeAddress, mlbSpeed); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateMlbSocketV1( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint16_t mlbChannelAddress, uint16_t blockWidthMlb, uint32_t tag ) +{ + CV1_MlbSocketCreate *a = new CV1_MlbSocketCreate(this, nodeAddress, epType, epDir, + mlbChannelAddress, blockWidthMlb, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateSplittedMlbSocketV1( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint16_t mlbChannelAddress, uint16_t blockWidthMlb, uint16_t splittedOffset, uint16_t blockWidthCombined, + uint32_t tag ) +{ + CV1_SplittedMlbSocketCreate *a = new CV1_SplittedMlbSocketCreate(this, nodeAddress, + epType, epDir, mlbChannelAddress, blockWidthMlb, splittedOffset, blockWidthCombined, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateMostSocketV1( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint16_t connectionLabel, uint16_t blockWidthMost, uint32_t tag ) +{ + CV1_MostSocketCreate *a = new CV1_MostSocketCreate(this, nodeAddress, + epType, epDir, connectionLabel, blockWidthMost, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::ConnectSocketsV1( uint16_t nodeAddress, uint8_t inHandle, uint8_t outHandle, uint32_t tag ) +{ + CV1_ConnectSockets *a = new CV1_ConnectSockets(this, nodeAddress, + inHandle, outHandle, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::DestroySocketV1( uint16_t nodeAddress, uint8_t handle, uint32_t tag ) +{ + CV1_DestroySocket *a = new CV1_DestroySocket(this, nodeAddress, handle, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::DisconnectSocketsV1( uint16_t nodeAddress, uint8_t handle, uint32_t tag ) +{ + CV1_DisconnectSockets *a = new CV1_DisconnectSockets(this, nodeAddress, handle, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::OpenStreamPortV1( uint16_t nodeAddress, V1I2SPortClkDriveMode_t portMode, + V1I2SStreamingPortMode_t streamPortMode, V1I2SStreamingDataFormat_t format, uint32_t tag ) +{ + CV1_StreamPortOpen *a = new CV1_StreamPortOpen(this, nodeAddress, portMode, streamPortMode, format, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateStreamSocketV1( uint16_t nodeAddress, EPDirection_t epDir, uint16_t blockWidthI2S, + V1I2SPin_t pin, uint32_t tag ) +{ + CV1_StreamSocketCreate *a = new CV1_StreamSocketCreate(this, nodeAddress, epDir, blockWidthI2S, pin, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateSplittedStreamSocketV1( uint16_t nodeAddress, EPDirection_t epDir, uint16_t blockWidthI2S, + uint16_t splittedOffset, uint16_t blockWidthCombined, V1I2SPin_t pin, uint32_t tag ) +{ + CV1_SplittedStreamSocketCreate *a = new CV1_SplittedStreamSocketCreate(this, + nodeAddress, epDir, blockWidthI2S, splittedOffset, blockWidthCombined, pin, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::AttachV3() +{ + CV3_DeviceAttach *a = new CV3_DeviceAttach(); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::InicUnsychronizeV3() +{ + CISWaitForPendingElements *w = new CISWaitForPendingElements(0x1); + iStack->EnqueueElement(0x1, w); + w->RemoveReference(); + + CV3_Unsynchronize *a = new CV3_Unsynchronize(); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::DeviceSyncV3( uint16_t nodeAddress, bool sync ) +{ + CV3_DeviceSync *a = new CV3_DeviceSync(nodeAddress, sync); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::MostNetworkStartupV3( uint16_t autoForcedNotAvailable, uint16_t packetBW ) +{ + startV3autoForced = autoForcedNotAvailable; + startV3packetBW = packetBW; + CV3_NetworkStartup *a = new CV3_NetworkStartup(this, autoForcedNotAvailable, packetBW); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::MostNetworkStartupV3() +{ + if( 0xFFFF == startV3packetBW ) + { + ConsolePrintf( PRIO_ERROR, RED"Repeated MostNetworkStartupV3 was called"\ + " without calling the overloaded MostNetworkStartupV3 with parameters"\ + RESETCOLOR"\n" ); + return; + } + CV3_NetworkStartup *a = new CV3_NetworkStartup(this, startV3autoForced, startV3packetBW); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::MostNetworkShutdownV3() +{ + CISWaitForPendingElements *w = new CISWaitForPendingElements(0x1); + iStack->EnqueueElement(0x1, w); + w->RemoveReference(); + + CV3_NetworkShutdown *a = new CV3_NetworkShutdown(this); + iStack->EnqueueElement(0x1, a); + a->RemoveReference(); +} + +void CNetworkDevice::SetMostMacAddressV3( uint16_t nodeAddress, uint8_t macAddress1, uint8_t macAddress2, + uint8_t macAddress3, uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6 ) +{ + CV3_MostNetworkConfiguration *a = new CV3_MostNetworkConfiguration(this, nodeAddress, macAddress1, macAddress2, + macAddress3, macAddress4, macAddress5, macAddress6, promiscuous); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::OpenMlbV3( uint16_t nodeAddress, MlbPortSpeed_t mlbSpeed ) +{ + if( MlbSpeedNotSet == mlbSpeed ) + return; + CV3_MlbPortCreate *a = new CV3_MlbPortCreate(this, nodeAddress, mlbSpeed); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateUsbSocketV3( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint8_t endPointAddress, uint16_t packetsPerFrame, uint32_t tag ) +{ + CV3_UsbSocketCreate *a = new CV3_UsbSocketCreate(this, nodeAddress, epType, + epDir, endPointAddress, packetsPerFrame, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateSplittedUsbSocketV3( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint8_t endPointAddress, uint16_t packetsPerFrame, uint16_t bytesPerPacket, uint32_t tag ) +{ + CV3_SplittedUsbSocketCreate *a = new CV3_SplittedUsbSocketCreate(this, nodeAddress, + epType, epDir, endPointAddress, packetsPerFrame, bytesPerPacket, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateMlbSocketV3( uint16_t nodeAddress, uint16_t mlbPortHandle, EPDataType_t epType, + EPDirection_t epDir, uint16_t mlbChannelAddress, uint16_t blockwidthMlb, uint32_t tag ) +{ + CV3_MlbSocketCreate *a = new CV3_MlbSocketCreate(this, nodeAddress, mlbPortHandle, + epType, epDir, mlbChannelAddress, blockwidthMlb, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateSplittedMlbSocketV3( uint16_t nodeAddress, uint16_t mlbPortHandle, EPDataType_t epType, + EPDirection_t epDir, uint16_t mlbChannelAddress, uint16_t blockwidthMlb, uint16_t bytesPerPacket, uint32_t tag ) +{ + CV3_SplittedMlbSocketCreate *a = new CV3_SplittedMlbSocketCreate(this, nodeAddress, + mlbPortHandle, epType, epDir, mlbChannelAddress, blockwidthMlb, bytesPerPacket, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateMostSocketV3( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint16_t connectionLabel, uint16_t blockwidthMost, uint32_t tag ) +{ + CV3_MostSocketCreate *a = new CV3_MostSocketCreate(this, nodeAddress, epType, + epDir, connectionLabel, blockwidthMost, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::ConnectSocketsV3( uint16_t nodeAddress, EPDataType_t epType, uint16_t inHandle, + uint16_t outHandle, uint16_t offset, uint32_t tag ) +{ + CV3_ConnectSockets *a = new CV3_ConnectSockets(this, nodeAddress, epType, + inHandle, outHandle, offset, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::ResourceDestroyV3( uint16_t nodeAddress, uint8_t amountOfHandles, const uint16_t *pHandle, + uint32_t tag ) +{ + CV3_ResourceDestroy *a = new CV3_ResourceDestroy(this, nodeAddress, + amountOfHandles, pHandle, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::ConfigureStreamPortV3( uint16_t nodeAddress, uint8_t portInstance, V3I2SPortOption_t option, + V3I2SClockMode_t mode, V3I2SDelayMode_t delay, uint32_t tag ) +{ + CV3_StreamPortConfig *a = new CV3_StreamPortConfig(this, nodeAddress, + portInstance, option, mode, delay, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateStreamPortV3( uint16_t nodeAddress, uint8_t portInstance, V3I2SPortSpeed_t clock, + V3I2SAlignment_t align, uint32_t tag ) +{ + CV3_StreamPortCreate *a = new CV3_StreamPortCreate(this, nodeAddress, + portInstance, clock, align, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateStreamSocketV3( uint16_t nodeAddress, uint8_t portInstance, EPDirection_t epDir, + uint16_t blockWidthI2S, V3I2SPin_t pin, uint32_t tag ) +{ + CV3_StreamSocketCreate *a = new CV3_StreamSocketCreate(this, nodeAddress, + portInstance, epDir, blockWidthI2S, pin, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::CreateSplittedStreamSocketV3( uint16_t nodeAddress, uint8_t portInstance, EPDirection_t epDir, + uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t bytesPerPacket, uint32_t tag ) +{ + CV3_SplittedStreamSocketCreate *a = new CV3_SplittedStreamSocketCreate(this, nodeAddress, + portInstance, epDir, blockWidthI2S, pin, bytesPerPacket, tag); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +void CNetworkDevice::GetRingBreakResultV3( uint16_t nodeAddress, uint32_t tag ) +{ + CV3_GetRbdResult *a = new CV3_GetRbdResult(nodeAddress); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +bool CNetworkDevice::OpenMostControlChannel( void ) +{ + bool success = false; + for (uint8_t i = 0; !success && i < 10; i++) + { + if (-1 == controlEndpointRxHandle) + controlEndpointRxHandle = open( deviceNameControlRx, O_RDONLY ); + if (-1 == controlEndpointTxHandle) + controlEndpointTxHandle = open( deviceNameControlTx, O_WRONLY ); + success = (-1 != controlEndpointRxHandle && -1 != controlEndpointTxHandle); + if (!success) + { + ConsolePrintf( PRIO_ERROR, RED"Opened file handles failed TX:%d RX:%d, retrying.."RESETCOLOR"\n", controlEndpointTxHandle, controlEndpointRxHandle); + usleep(1000000); + } + } + + if( success ) + { + iStack = new CIndustrialStack(deviceApi, controlEndpointRxHandle, controlEndpointTxHandle); + v1Events = new CV1_OnMostRx(this); + v3Events = new CV3_OnMostRx(this); + iStack->AddInternalEventListener(this); + iStack->AddInternalEventListener(v1Events); + iStack->AddInternalEventListener(v3Events); + } + else + { + ConsolePrintf( PRIO_ERROR, RED"Failure while opening MOST control channel" \ + " ('%s' or '%s'), error='%s'"RESETCOLOR"\n" + , deviceNameControlRx, deviceNameControlTx, GetErrnoString() ); + } + return success; +} + +void CNetworkDevice::Run( void ) +{ + iStack->ServiceStack(GetTickCount()); + usleep( 1000 ); +} + +void CNetworkDevice::CloseMostControlChannel( void ) +{ + close( controlEndpointTxHandle ); + close( controlEndpointRxHandle ); + if (NULL != iStack) + { + delete iStack; + iStack = NULL; + } +} + +void CNetworkDevice::WaitForIpcResponse( const char *responseMessage ) +{ + if( isRunning ) + { + strncpy( ( char * )responseToWaitFor, responseMessage, sizeof( responseToWaitFor ) ); + sem_wait( &methodMutex ); + responseToWaitFor[0] = '\0'; + } +} + +bool CNetworkDevice::ConfigureUsbEndpoint( AimType_t aimType, uint8_t endpointAddress, EPDataType_t epType, + EPDirection_t epDir, char *deviceName, uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize, + uint32_t subbufferSize, uint32_t packetsPerTransaction ) +{ + char systemName[64]; + char linkName[64]; + bool success = GetUsbDeviceNames( deviceIndex, endpointAddress, deviceName, deviceNameBufLen, + systemName, sizeof( systemName ), linkName, sizeof( linkName ) ); + if( !success ) + return success; + CloseMostChannel( systemName ); + switch( epType ) + { + case EP_Synchron: + success = ConfigureSyncChannel( systemName, subbufferSize, packetsPerTransaction ); + if( success ) + success = ConfigureMostChannel( systemName, epType, epDir, amountOfBuffers, bufferSize ); + break; + case EP_Isochron: + success = ConfigureIsocChannel( systemName, subbufferSize, packetsPerTransaction ); + if( success ) + success = ConfigureMostChannel( systemName, epType, epDir, amountOfBuffers, bufferSize ); + break; + default: + break; + } + if( success ) + { + switch( aimType ) + { + case AIM_AUDIO: + success = LinkToAudioDevice( linkName, subbufferSize ); + break; + case AIM_V4L: + success = LinkToVideoForLinuxDevice( linkName ); + break; + case AIM_CDEV: + default: + success = LinkToCharacterDevice( linkName, deviceName ); + break; + } + } + return success; +} + +bool CNetworkDevice::ConfigureUsbEndpoint( uint8_t endpointAddress, EPDataType_t epType, EPDirection_t epDir, + char *deviceName, uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize ) +{ + return ConfigureUsbEndpoint( AIM_CDEV, endpointAddress, epType, epDir, deviceName, deviceNameBufLen, + amountOfBuffers, bufferSize, 0, 0 ); +} + +bool CNetworkDevice::ConfigureMlbChannel( AimType_t aimType, uint8_t mlbChannelAddress, EPDataType_t epType, + EPDirection_t epDir, char *deviceName, uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize, + uint32_t subbufferSize, uint32_t packetsPerTransaction ) +{ + char systemName[64]; + char linkName[64]; + bool success = GetMlbDeviceNames( deviceIndex, mlbChannelAddress, deviceName, deviceNameBufLen, + systemName, sizeof( systemName ), linkName, sizeof( linkName ) ); + if( !success ) + return false; + CloseMostChannel( systemName ); + switch( epType ) + { + case EP_Synchron: + success = ConfigureSyncChannel( systemName, subbufferSize, packetsPerTransaction ); + if( success ) + success = ConfigureMostChannel( systemName, epType, epDir, amountOfBuffers, bufferSize ); + if( success ) + { + switch( aimType ) + { + case AIM_AUDIO: + success = LinkToAudioDevice( linkName, subbufferSize ); + break; + case AIM_CDEV: + default: + success = LinkToCharacterDevice( linkName, deviceName ); + break; + } + } + break; + case EP_Isochron: + success = ConfigureIsocChannel( systemName, subbufferSize, packetsPerTransaction ); + if( success ) + success = ConfigureMostChannel( systemName, epType, epDir, amountOfBuffers, bufferSize ); + if( success ) + success = LinkToCharacterDevice( linkName, deviceName ); + break; + default: + break; + } + return success; +} + +bool CNetworkDevice::ConfigureMlbChannel( uint8_t mlbChannelAddress, EPDataType_t epType, EPDirection_t epDir, + char *deviceName, uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize ) +{ + return ConfigureMlbChannel( AIM_CDEV, mlbChannelAddress, epType, epDir, deviceName, deviceNameBufLen, + amountOfBuffers, bufferSize, 0, 0 ); +} + +bool CNetworkDevice::SendMostControlMessage( uint8_t devInst, uint32_t targetAddr, uint32_t nFBlock, uint32_t nInst, + uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ) +{ + CGeneric_SendMostMessage *a = new CGeneric_SendMostMessage(Payload, + nPayloadLen, targetAddr, nFBlock, nInst, nFunc, nOpType, 0xFF); + iStack->EnqueueElement(targetAddr, a); + a->RemoveReference(); + return true; +} + +void CNetworkDevice::GetDeviceVersion( uint16_t nodeAddress ) +{ + CV3_DeviceVersion *a = new CV3_DeviceVersion(this, nodeAddress, 0); + iStack->EnqueueElement(nodeAddress, a); + a->RemoveReference(); +} + +ISReturn_t CNetworkDevice::OnMostMessage(CIndustrialStack *iStack, CISMostMsg *r) +{ + if (NULL == r) + return ISReturn_NoChange; + for (uint32_t i = 0; i < allListeners.Size(); i++) + { + allListeners[i]->OnMostControlMessage(this, r->SourceAddress, r->TargetAddress, + r->FBlock, r->Inst, r->Func, r->OpType, r->PayloadLen, r->Payload); + } + return ISReturn_NoChange; +} + diff --git a/Src/Network/NetworkDevice.h b/Src/Network/NetworkDevice.h new file mode 100644 index 0000000..8a67556 --- /dev/null +++ b/Src/Network/NetworkDevice.h @@ -0,0 +1,862 @@ +/* + * 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 CNetworkDevice class. + */ +/*----------------------------------------------------------*/ +#ifndef _NETWORKDEVICE_H_ +#define _NETWORKDEVICE_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> +#include "SafeVector.h" +#include "ScriptXml.h" +#include "Types.h" +#include "Thread.h" +#include "NetworkDeviceListener.h" +#include "IndustrialStack.h" +#include "IndustrialStack_Types.h" + +typedef enum +{ + NetworkState_Unknown, + NetworkState_Unavailable, + NetworkState_Available, + NetworkState_ShutdownInProgress +} NetworkState_t; + +/*----------------------------------------------------------*/ +/*! \brief This class represents an INIC instance. + * It will be multiple instanced, for each connected OS81118. + * It generates INIC requests and parses INIC responses. + */ +/*----------------------------------------------------------*/ +class CNetworkDevice : public CThread, public CSInternalEvent +{ +private: + CIndustrialStack *iStack; + CV1_OnMostRx *v1Events; + CV3_OnMostRx *v3Events; + bool promiscuous; + NetworkState_t netState; + void *pInic; + void *pScriptMemoryArea; + bool isRunning; + bool isActionPending; + uint8_t deviceIndex; + uint8_t deviceApi; + bool isTimingMaster; + uint32_t asyncBandwidth; + sem_t methodMutex; + int controlEndpointRxHandle; + int controlEndpointTxHandle; + char *responseToWaitFor[64]; + char deviceNameControlRx[64]; + char deviceNameControlTx[64]; + CSafeVector<CNetworkDeviceListener *> allListeners; + + uint16_t startV3autoForced; + uint16_t startV3packetBW; + + bool OpenDevice( const char *systemNameControlRx, const char *systemNameControlTx, const char *linkNameControlRx, + const char *linkNameControlTx ); + bool OpenMostControlChannel( void ); + void CloseMostControlChannel( void ); + void WaitForIpcResponse( const char *responseMessage ); + void ExecuteMcmScript( uint16_t nodeAddress, CSciptXml *scriptXml ); +public: + /*----------------------------------------------------------*/ + /*! \brief Constructor of CNetworkDevice. + * \param deviceIndex - The index of the physical device instance of the server device. + * Starting at 0 for the first device instance. + * \param deviceApi - 1: OS81092, OS81110; 2: OS81118-C-Rev; 3:OS81118-D-Rev + * \param isTimingMaster - true, if this device shall act as timing master, otherwise it is timing slave + * \param asyncBandwidth - if set as timing master, how many bytes shall be reserved for the asynchronous channel + * \param promiscuousMode - true, promiscuous mode. false, perfect match filter with multicast and broadcast enabled. If enabled, tools like Wireshark will capture every packet. + */ + /*----------------------------------------------------------*/ + CNetworkDevice( uint8_t deviceIndex, uint8_t deviceApi, bool isTimingMaster, uint32_t asyncBandwidth, + bool promiscuousMode ); + + + /*----------------------------------------------------------*/ + /*! \brief Destructor of CNetworkDevice. + */ + /*----------------------------------------------------------*/ + virtual ~CNetworkDevice(); + + + /*----------------------------------------------------------*/ + /*! \brief Function of background thread. + * \note Do never call this method. It is used by internal threads. + */ + /*----------------------------------------------------------*/ + void Run(); + + + /*----------------------------------------------------------*/ + /*! \brief Opens the USB connection to the INIC. + * \param controlRxEndpointAddress - The USB endpoint address of the RX direction. + * \param controlTxEndpointAddress - The USB endpoint address of the TX direction. + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool OpenUsb( uint8_t controlRxEndpointAddress, uint8_t controlTxEndpointAddress ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Opens the MLB connection to the INIC. + * \param controlRxChannelAddress - The MLB channel address of the RX direction. + * \param controlTxChannelAddress - The MLB channel address of the TX direction. + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool OpenMlb( uint8_t controlRxChannelAddress, uint8_t controlTxChannelAddress ); + + + /*----------------------------------------------------------*/ + /*! \brief Opens the I2C connection to the INIC. + * \param inicApi - INIC API Version + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool OpenI2C(); + + + /*----------------------------------------------------------*/ + /*! \brief Closes the USB connection to the INIC. + */ + /*----------------------------------------------------------*/ + void Close(); + + /*----------------------------------------------------------*/ + /*! \brief Returns the used API of the INIC. + * \return INIC API Version 1: OS81092, OS81110; 2: OS81118-C-Rev; 3:OS81118-D-Rev + */ + /*----------------------------------------------------------*/ + uint8_t GetDeviceApi(); + + NetworkState_t GetNetState(); + void SetNetstate( NetworkState_t newState ); + void SetTimingMaster(bool tm); + bool IsTimingMaster(); + void SetAsyncBandwidth(uint32_t bw); + uint32_t GetAsyncBandwidth(); + + /*----------------------------------------------------------*/ + /*! \brief Determines if there are jobs currently in the working queue. + * \note This method will block until the result is queried from the worker process. + * \return true, if there are pending actions enqueued. + */ + /*----------------------------------------------------------*/ + bool ActionsPending(); + + + + /*----------------------------------------------------------*/ + /*! \brief Remove all pending actions from the working queue. + */ + /*----------------------------------------------------------*/ + void ClearAllPendingActions(); + + + + /*----------------------------------------------------------*/ + /*! \brief Configure the Linux character device driver to handle an USB connection. + * \note This overloaded function is used to configure synchronous channels. + * \param aimType - Specifies the type of used Linux Driver Application Interface Module. + * \param endpointAddress - The USB endpoint address. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param deviceName - On successful configuration, this method stores the name of the character device into the given buffer. + * \param deviceNameBufLen - The length of the given buffer. + * \param amountOfBuffers - The amount of buffers used in the driver. + * \param bufferSize - The amount of bytes used in a single buffer. + * \param subbufferSize - The amount of bytes used for a single subbuffer. For isoc channel this maybe 188 or 196 byte. + * \param packetsPerTransaction - The amount of packets per transaction. + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool ConfigureUsbEndpoint( AimType_t aimType, uint8_t endpointAddress, EPDataType_t epType, EPDirection_t epDir, + char *deviceName, uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize, + uint32_t subbufferSize, uint32_t packetsPerTransaction ); + + + + /*----------------------------------------------------------*/ + /*! \brief Configure the Linux character device driver to handle an USB connection. + * \param endpointAddress - The USB endpoint address. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param deviceName - On successful configuration, this method stores the name of the character device into the given buffer. + * \param deviceNameBufLen - The length of the given buffer. + * \param amountOfBuffers - The amount of buffers used in the driver. + * \param bufferSize - The amount of bytes used in a single buffer. + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool ConfigureUsbEndpoint( uint8_t endpointAddress, EPDataType_t epType, EPDirection_t epDir, char *deviceName, + uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize ); + + + /*----------------------------------------------------------*/ + /*! \brief Configure the Linux character device driver to handle an MLB connection. + * \note This overloaded function is used to configure synchronous channels. + * \param aimType - Specifies the type of used Linux Driver Application Interface Module. + * \param mlbChannelAddress - The MLB channel address + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param deviceName - On successful configuration, this method stores the name of the character device into the given buffer. + * \param deviceNameBufLen - The length of the given buffer. + * \param amountOfBuffers - The amount of buffers used in the driver. + * \param bufferSize - The amount of bytes used in a single buffer. + * \param subbufferSize - The amount of bytes used for a single subbuffer. For isoc channel this maybe 188 or 196 byte. + * \param packetsPerTransaction - The amount of packets per transaction. + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool ConfigureMlbChannel( AimType_t aimType, uint8_t mlbChannelAddress, EPDataType_t epType, EPDirection_t epDir, + char *deviceName, uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize, + uint32_t subbufferSize, uint32_t packetsPerTransaction ); + + + /*----------------------------------------------------------*/ + /*! \brief Configure the Linux character device driver to handle an MLB connection. + * \param mlbChannelAddress - The MLB channel address + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param deviceName - On successful configuration, this method stores the name of the character device into the given buffer. + * \param deviceNameBufLen - The length of the given buffer. + * \param amountOfBuffers - The amount of buffers used in the driver. + * \param bufferSize - The amount of bytes used in a single buffer. + * \return true, if successful. false, otherwise. + */ + /*----------------------------------------------------------*/ + bool ConfigureMlbChannel( uint8_t mlbChannelAddress, EPDataType_t epType, EPDirection_t epDir, char *deviceName, + uint32_t deviceNameBufLen, uint32_t amountOfBuffers, uint32_t bufferSize ); + + + + /*----------------------------------------------------------*/ + /*! \brief Adds a callback class, which derives CNetworkDeviceListener. + * This class will then be informed about any results and changes of MOST transactions. + * \note It is possible to register multiple listeners. + * \param listener - The class, which wants to be registered for MOST events. + */ + /*----------------------------------------------------------*/ + void AddListener( CNetworkDeviceListener *listener ); + + + + /*----------------------------------------------------------*/ + /*! \brief Retrieves the amount of registered listeners. + * \note Use this method in combination of GetListener() + * \return The amount of registered listeners. + */ + /*----------------------------------------------------------*/ + uint32_t GetAmountOfListners(); + + + /*----------------------------------------------------------*/ + /*! \brief Gets a pointer to the class implementing the CNetworkDeviceListener interface. + * \note Use this method in combination of GetAmountOfListners() + * \return The pointer to the given instance of Listener. + */ + /*----------------------------------------------------------*/ + CNetworkDeviceListener *GetListener( uint32_t instance ); + + + /*----------------------------------------------------------*/ + /*! \brief Gets the MOST instance index of the server device. + * \return The MOST instance index, starting at 0 for the first instance. + */ + /*----------------------------------------------------------*/ + uint8_t GetDeviceIndex(); + + + + /*----------------------------------------------------------*/ + /*! \brief Wait let the scripting engine wait for the given amount of time. + * \param timeInMillis - Time value in milliseconds. + */ + /*----------------------------------------------------------*/ + void ScriptPause( uint32_t timeInMillis ); + + + + /*----------------------------------------------------------*/ + /*! \brief Execute a bunch of MCM send and receive actions, as descibed in the XML file. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param pPathToScriptXml - Path to the XML file. + */ + /*----------------------------------------------------------*/ + void ExecuteMcmScript( uint16_t nodeAddress, const char *pPathToScriptXml ); + + + + /*----------------------------------------------------------*/ + /*! \brief Execute a bunch of MCM send and receive actions, as descibed in the XML zero terminated string. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param pPathToScriptXml - Path to the XML file. + */ + /*----------------------------------------------------------*/ + void ExecuteMcmScript( uint16_t nodeAddress, const char *pStringBuffer, uint32_t bufferLength ); + + + /*----------------------------------------------------------*/ + /*! \brief Sends a NetworkMaster.NOT_OK and NetworkMaster.OK, in order resolve address conflicts. + */ + /*----------------------------------------------------------*/ + void ToggleNotOk(); + + + + /*----------------------------------------------------------*/ + /*! \brief Retrieves the GroupAddresses of all available MOST devices in this MOST instance. + * \note The result of this request is reported in the callback method OnMostDeviceType of the CNetworkDeviceListener class. + * Use AddListener to get the result. + */ + /*----------------------------------------------------------*/ + void GetGroupAddresses( uint8_t maxNodePos ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Retrieves the MOST MAC address for the given node address in this MOST instance. + * \note The result of this request is reported in the callback method OnMostMacAddress of the CNetworkDeviceListener class. + * Use AddListener to get the result. + * \param nodeAddress - The MOST node address (e.g. 0x101). + */ + /*----------------------------------------------------------*/ + void GetMacAddress( uint16_t nodeAddress ); + + + /*----------------------------------------------------------*/ + /*! \brief Starts up the MOST on the local INIC of the server device. + * \param isTimingMaster - true, if the INIC shall act as a timing master. false, if the device shall act as a timing slave. + * \param packetBandWidth - The amount of Bytes, which are reserved for asynchronous data (MEP, MHP). + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void StartMostV1( bool isTimingMaster, uint16_t packetBandWidth ); + + + + /*----------------------------------------------------------*/ + /*! \brief Performs a network shutdown sequence on the local INIC attached to the server device. + * \note This method will cause a chain reaction on the MOST network. All devices will switch of their output signal on MOST. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void MostNetworkShutdownV1(); + + + /*----------------------------------------------------------*/ + /*! \brief Enables the usage of the MLB bus for the device on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param mlbSpeed - The used MLB speed. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void OpenMlbV1( uint16_t nodeAddress, MlbPortSpeed_t mlbSpeed ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Sets the MOST MAC address for the device on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param macAddress1 - The 1st byte of the MAC address. + * \param macAddress2 - The 2nd byte of the MAC address. + * \param macAddress3 - The 3rd byte of the MAC address. + * \param macAddress4 - The 4th byte of the MAC address. + * \param macAddress5 - The 5th byte of the MAC address. + * \param macAddress6 - The 6th byte of the MAC address. + * \param persistent - true, if the given MAC address shall be stored persistent into the INIC flash memory. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void SetMostMacAddressV1( uint16_t nodeAddress, uint8_t macAddress1, uint8_t macAddress2, uint8_t macAddress3, + uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6, bool persistent ); + + + /*----------------------------------------------------------*/ + /*! \brief Enables the usage of the MLB bus for the device on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param tsiPortId - The instance id of the used TSI port. + * \param tsiPortMode - The used mode for this TSI port. + * \note This is an INIC API Version 1 command. Use it for OS81110 only. + */ + /*----------------------------------------------------------*/ + void OpenTsiV1( uint16_t nodeAddress, V1TsiPortInstance_t tsiPortId, V1TsiPortMode tsiPortMode ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a TSI socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param portInst - The port instance id of the TSI port. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthTsi -The block width in bytes to be allocated on the MLB bus. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void CreateTsiSocketV1( uint16_t nodeAddress, V1TsiPortInstance_t portInst, + EPDataType_t epType, EPDirection_t epDir,uint16_t blockWidthTsi, uint32_t tag ); + + /*----------------------------------------------------------*/ + /*! \brief Creates a MLB socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param mlbChannelAddress - The MLB channel address (even value). + * \param blockWidthMlb -The block width in bytes to be allocated on the MLB bus. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void CreateMlbSocketV1( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, uint16_t mlbChannelAddress, + uint16_t blockWidthMlb, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Creates a MLB socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param mlbChannelAddress - The MLB channel address (even value). + * \param blockWidthMlb -The block width in bytes of this singular splitted socked. + * \param splittedOffset - Offset in between the splitted socket. + * \param blockWidthCombined - The block width in bytes of all splitted sockets combined. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void CreateSplittedMlbSocketV1( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint16_t mlbChannelAddress, uint16_t blockWidthMlb, uint16_t splittedOffset, uint16_t blockWidthCombined, + uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a MOST socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param connectionLabel - Only in case of if epDir is "EPDIR_IN": The connection label, which this socket will be bound. + * Otherwise, the value will be ignored. + * \param blockwidthMost - The block width in bytes to be allocated on the MOST bus. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void CreateMostSocketV1( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, uint16_t connectionLabel, + uint16_t blockwidthMost, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param handle - The handle of socket (will be reported by the callback callback methods of the create socket methods). + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void DestroySocketV1( uint16_t nodeAddress, uint8_t handle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param handle - The handle of socket (will be reported by the callback callback methods of the connect socket method). + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void DisconnectSocketsV1( uint16_t nodeAddress, uint8_t handle, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Connects two different sockets, which then is called a connection, on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param inHandle - The handle of the in-socket (will be reported by the callback callback methods of the create socket methods). + * \param outHandle - * The handle of out-socket (will be reported by the callback callback methods of the create socket methods). + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 1 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void ConnectSocketsV1( uint16_t nodeAddress, uint8_t inHandle, uint8_t outHandle, uint32_t tag ); + + /*----------------------------------------------------------*/ + /*! \brief Configures an I2S port on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void OpenStreamPortV1( uint16_t nodeAddress, V1I2SPortClkDriveMode_t portMode, + V1I2SStreamingPortMode_t streamPortMode, V1I2SStreamingDataFormat_t format, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates an I2S socket on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - he Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param pin - The physical I2S data pin of the INIC. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void CreateStreamSocketV1( uint16_t nodeAddress, EPDirection_t epDir, uint16_t blockWidthI2S, V1I2SPin_t pin, + uint32_t tag ); + + /*----------------------------------------------------------*/ + /*! \brief Creates an I2S socket on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - he Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param splittedOffset - Offset in between the splitted socket. + * \param blockWidthCombined - The block width in bytes of all splitted sockets combined. + * \param pin - The physical I2S data pin of the INIC. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81110 + */ + /*----------------------------------------------------------*/ + void CreateSplittedStreamSocketV1( uint16_t nodeAddress, EPDirection_t epDir, uint16_t blockWidthI2S, + uint16_t splittedOffset, uint16_t blockWidthCombined, V1I2SPin_t pin, uint32_t tag ); + + /*----------------------------------------------------------*/ + /*! \brief Attach to a local INIC on the server device. + * \note This command has to be called before any other commands to the local INIC. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void AttachV3(); + + + + /*----------------------------------------------------------*/ + /*! \brief Destroyes any resource on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param sync - true, if the device shall be used afterwise. false, if the device is going to suspend (shutdown). + * \note In any case (regardless if sync is true or false), all ports, sockets and connects are going to be destroyed). + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void DeviceSyncV3( uint16_t nodeAddress, bool sync ); + + + + /*----------------------------------------------------------*/ + /*! \brief Performs a network startup sequence on the local INIC attached to the server device. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118-D Revision + */ + /*----------------------------------------------------------*/ + void MostNetworkStartupV3( uint16_t autoForcedNotAvailable, uint16_t packetBW ); + + + + /*----------------------------------------------------------*/ + /*! \brief Performs a network startup sequence on the local INIC attached to the server device, after MostNetworkStartupV3 with parameters had failed. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118-D Revision + * \note Call this method only if the MostNetworkStartupV3( uint16_t autoForcedNotAvailable, uint16_t packetBW ) had failed. This will be treated as retry. + */ + /*----------------------------------------------------------*/ + void MostNetworkStartupV3(); + + + /*----------------------------------------------------------*/ + /*! \brief Performs a network shutdown sequence on the local INIC attached to the server device. + * \note This method will cause a chain reaction on the MOST network. All devices will switch of their output signal on MOST. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void MostNetworkShutdownV3(); + + + + /*----------------------------------------------------------*/ + /*! \brief Closes the IPC connection to local attached INIC. + * \note This will also cleanup any used resource in the INIC. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void InicUnsychronizeV3(); + + + + + /*----------------------------------------------------------*/ + /*! \brief Sets the MOST MAC address for the device on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param macAddress1 - The 1st byte of the MAC address. + * \param macAddress2 - The 2nd byte of the MAC address. + * \param macAddress3 - The 3rd byte of the MAC address. + * \param macAddress4 - The 4th byte of the MAC address. + * \param macAddress5 - The 5th byte of the MAC address. + * \param macAddress6 - The 6th byte of the MAC address. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118-D Rev + */ + /*----------------------------------------------------------*/ + void SetMostMacAddressV3( uint16_t nodeAddress, uint8_t macAddress1, uint8_t macAddress2, uint8_t macAddress3, + uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6 ); + + + /*----------------------------------------------------------*/ + /*! \brief Enables the usage of the MLB bus for the device on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param mlbSpeed - The speed of the MLB bus. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void OpenMlbV3( uint16_t nodeAddress, MlbPortSpeed_t mlbSpeed ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates an USB socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param endPointAddress - The USB endpoint address. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \param packetsPerFrame - The amount of packets stored in a single USB frame (512 byte). + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateUsbSocketV3( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, uint8_t endPointAddress, + uint16_t packetsPerFrame, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates an splitted USB socket on the given node address to use with Combiner or Splitter. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param endPointAddress - The USB endpoint address. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \param packetsPerFrame - The amount of packets stored in a single USB frame (512 byte). + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateSplittedUsbSocketV3( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, + uint8_t endPointAddress, uint16_t packetsPerFrame, uint16_t bytesPerPacket, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Creates a MLB socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param mlbChannelAddress - The MLB channel address (even value). + * \param blockwidthMlb - The block width in bytes to be allocated on the MLB bus. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateMlbSocketV3( uint16_t nodeAddress, uint16_t mlbPortHandle, EPDataType_t epType, EPDirection_t epDir, + uint16_t mlbChannelAddress, uint16_t blockwidthMlb, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Creates a splitted MLB socket on the given node address to use with Combiner or Splitter. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param mlbChannelAddress - The MLB channel address (even value). + * \param blockwidthMlb - The block width in bytes to be allocated on the MLB bus. + * \param bytesPerPacket - The total number of data bytes to be transfered each MOST frame. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateSplittedMlbSocketV3( uint16_t nodeAddress, uint16_t mlbPortHandle, EPDataType_t epType, + EPDirection_t epDir, uint16_t mlbChannelAddress, uint16_t blockwidthMlb, uint16_t bytesPerPacket, + uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a MOST socket on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this MOST channel. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param connectionLabel - Only in case of if epDir is "EPDIR_IN": The connection label, which this socket will be bound. + * Otherwise, the value will be ignored. + * \param blockwidthMost - The block width in bytes to be allocated on the MOST bus. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateMostSocketV3( uint16_t nodeAddress, EPDataType_t epType, EPDirection_t epDir, uint16_t connectionLabel, + uint16_t blockwidthMost, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Connects two different sockets, which then is called a connection, on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param epType - The data type, which then will be transmitted on this connection. + * \param inHandle - The handle of the in-socket (will be reported by the callback callback methods of the create socket methods). + * \param outHandle - * The handle of out-socket (will be reported by the callback callback methods of the create socket methods). + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void ConnectSocketsV3( uint16_t nodeAddress, EPDataType_t epType, uint16_t inHandle, uint16_t outHandle, + uint16_t offset, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Destroyes up to three resources (Ports or connections) on the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \param amountOfHandles - The amount of resources to be destroyed. (value must be between 1 to 3). + * \param handle1 - The first resource to be destroyed. + * \param handle2 - The second resource to be destroyed. + * \param handle3 - The third resource to be destroyed. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void ResourceDestroyV3( uint16_t nodeAddress, uint8_t amountOfHandles, const uint16_t *pHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Configures an I2S port on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param option - The I2S port option. + * \param mode - The I2S clock mode. + * \param delay - The I2S delay mode. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void ConfigureStreamPortV3( uint16_t nodeAddress, uint8_t portInstance, V3I2SPortOption_t option, + V3I2SClockMode_t mode, V3I2SDelayMode_t delay, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Creates an I2S port on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param clock - The I2S port speed in multiple of MOST base clock. + * \param align - The I2S data format alignment. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateStreamPortV3( uint16_t nodeAddress, uint8_t portInstance, V3I2SPortSpeed_t clock, + V3I2SAlignment_t align, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Creates an I2S socket on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - he Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param pin - The physical I2S data pin of the INIC. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateStreamSocketV3( uint16_t nodeAddress, uint8_t portInstance, EPDirection_t epDir, uint16_t blockWidthI2S, + V3I2SPin_t pin, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates an splitted I2S socket on the given node address to use with Combiner or Splitter. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - he Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param pin - The physical I2S data pin of the INIC. + * \param bytesPerPacket - The total number of data bytes to be transfered each MOST frame. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void CreateSplittedStreamSocketV3( uint16_t nodeAddress, uint8_t portInstance, EPDirection_t epDir, + uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t bytesPerPacket, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates an I2S socket on the given node address. + * \param nodeAddr -The device with this MOST node address raised this event. + * \param tag - Any 32 bit value. This value will be unmodified passed back in the corresponding callback method. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void GetRingBreakResultV3( uint16_t nodeAddress, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Sends the given Control Message out to MOST ring. + * \param targetAddr - The MOST target address + * \param nFBlock - The MOST Function Block Identifier + * \param nInst - The MOST Function Block Instance Identifier + * \param nFunc - The MOST Function Block Function Identifier + * \param nPayloadLen - The amount of bytes stored in Payload + * \param Payload - The pointer to the payload byte array. + */ + /*----------------------------------------------------------*/ + bool SendMostControlMessage( uint8_t devInst, uint32_t targetAddr, uint32_t nFBlock, uint32_t nInst, + uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ); + + /*----------------------------------------------------------*/ + /*! \brief Gets the device information for the given node address. + * \param nodeAddress - The MOST node address (e.g. 0x101). + * \note The corresponding callback to this request is OnDeviceVersion. + * \note This is an INIC API Version 3 command. Use it for e.g. OS81118 + */ + /*----------------------------------------------------------*/ + void GetDeviceVersion( uint16_t nodeAddress ); + + /* Callback from underlying layers */ + virtual ISReturn_t OnMostMessage(CIndustrialStack *iStack, CISMostMsg *r); +}; + +#endif //_NETWORKDEVICE_H_ diff --git a/Src/Network/NetworkDeviceListener.cpp b/Src/Network/NetworkDeviceListener.cpp new file mode 100644 index 0000000..be62d33 --- /dev/null +++ b/Src/Network/NetworkDeviceListener.cpp @@ -0,0 +1,306 @@ +/* + * 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. + * + */ + +#include <stdint.h> +#include <stdio.h> +#include <Board.h> +#include "Console.h" +#include "NetworkDeviceListener.h" + +void CNetworkDeviceListener::OnSync( void *source, bool isSynced ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnSync\n" ); +} + +void CNetworkDeviceListener::OnNetworkState( void *source, bool mpValChanged, bool systemNotOk, + bool mostAvailable, uint8_t availableSubState, uint8_t availableTransition, uint16_t nodeAddress, uint8_t nodePos, + uint8_t maxPos, uint16_t packetBW ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnNetworkState\n" ); +} + +void CNetworkDeviceListener::OnNetworkStartupV3( void *source, bool success ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnNetworkStartupV3, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnNetworkShutdownV3( void *source, bool success ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnNetworkShutdownV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnMostMacAddress( void *source, bool success, uint16_t nodeAddress, uint8_t macAddress1, + uint8_t macAddress2, uint8_t macAddress3, uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6 ) +{ + if( success ) + { + ConsolePrintf( PRIO_LOW, + "BASE->OnMostMacAddress:nodeAddress:0x%X, MAC-Address:%02X-%02X-%02X-%02X-%02X-%02X)\n", nodeAddress, + macAddress1, macAddress2, macAddress3, macAddress4, macAddress5, macAddress6 ); + } + else + { + ConsolePrintf( PRIO_ERROR, + RED"BASE->OnMostMacAddress reports failure for nodeAddress:0x%X"RESETCOLOR"\n", nodeAddress ); + } +} + +void CNetworkDeviceListener::OnMostDeviceType( void *source, bool success, uint16_t nodeAddress, uint16_t deviceType ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnMostDeviceType, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnInitCompleteV1( void *source ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnInitCompleteV1\n" ); +} + +void CNetworkDeviceListener::OnNetOnV1( void *source, bool isMaster ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnNetOnV1, mode=%s\n", ( isMaster ? "master" : "slave" ) ); +} + +void CNetworkDeviceListener::OnShutDownV1( void *source ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnShutDownV1\n" ); +} + +void CNetworkDeviceListener::OnNprV1( void *source, uint8_t npr ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnNprV1, NPR=%d\n", npr ); +} + +void CNetworkDeviceListener::OnUnlockV1( void *source ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnUnlockV1\n" ); +} + +void CNetworkDeviceListener::OnMprV1( void *source, uint8_t oldMpr, uint8_t newMpr ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnMprV1, old MPR=%d, new MPR:%d\n", oldMpr, newMpr ); +} + +void CNetworkDeviceListener::OnOpenTsiV1( void *source, bool success, uint16_t nodeAddress ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnOpenTsiV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateTsiSocketV1( void *source, bool success, uint16_t nodeAddr, V1TsiPortInstance_t tsiPortInst, + EPDataType_t epType, EPDirection_t epDir, uint16_t blockWidthTsi, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateTsiSocketV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnOpenMlbV1( void *source, bool success, uint16_t nodeAddress ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnOpenMlbV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateMlbSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateMlbSocketV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateMostSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateMostSocketV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnConnectSocketsV1( void *source, bool success, uint16_t nodeAddr, + uint16_t inSocketHandle, uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnConnectSocketsV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnDestroySocketV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, + uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnDestroySocketV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnDisconnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, + uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnDisconnectSocketsV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnOpenI2SPortV1( void *source, bool success, uint16_t nodeAddress, + V1I2SPortClkDriveMode_t portMode, V1I2SStreamingDataFormat_t format, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnOpenI2SPortV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateI2SSocketV1( void *source, bool success, uint16_t nodeAddr, EPDirection_t epDir, + uint16_t blockWidthI2S, V1I2SPin_t pin, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateI2SSocketV1, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnOpenMlbV3( void *source, bool success, uint16_t nodeAddress, uint16_t mlbPortHandle ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnOpenMlbV2, success=%s, Handle:%X\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ), mlbPortHandle ); +} + +void CNetworkDeviceListener::OnCreateUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateUsbSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateSplittedUsbSocketV3( void *source, bool success, uint16_t nodeAddr, + EPDataType_t epType, EPDirection_t epDir, uint8_t endPointAddress, uint16_t usbHandle, uint16_t splitterHandle, + uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateSplittedUsbSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateMlbSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateSplittedMlbSocketV3( void *source, bool success, uint16_t nodeAddr, + EPDataType_t epType, EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, + uint16_t mlbSocketHandle, uint16_t splittertHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateSplittedMlbSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateMostSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateMostSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnConnectSocketsV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + uint16_t inSocketHandle, uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnConnectSocketsV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + + +void CNetworkDeviceListener::OnResourceDestroyV3( void *source, bool success, uint16_t nodeAddress, + uint8_t amountOfHandles, const uint16_t *pHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnResourceDestroyV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnConfigureI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortOption_t option, V3I2SClockMode_t mode, V3I2SDelayMode_t delay, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnConfigureI2SPortV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortSpeed_t clock, V3I2SAlignment_t align, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateI2SPortV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t socketHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateI2SSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnCreateSplittedI2SSocketV3( void *source, bool success, uint16_t nodeAddr, + uint8_t portInstance, EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t i2sSocketHandle, + uint16_t splitterHandle, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->CNetworkDeviceListener::OnCreateSplittedI2SSocketV2, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} + +void CNetworkDeviceListener::OnRbdResultV3( void *source, uint16_t nodeAddress, uint8_t result, uint8_t position, + uint8_t status, uint16_t id ) +{ + ConsolePrintfStart( PRIO_HIGH, YELLOW"BASE->OnRbdResultV3: Diagnosis Result from node=0x%X, result=0x%X (", + nodeAddress, result ); + switch( result ) + { + case 0: + ConsolePrintfContinue( "NoError" ); + break; + case 1: + ConsolePrintfContinue( "PosDetected" ); + break; + case 2: + ConsolePrintfContinue( "DiagFailed" ); + break; + case 3: + ConsolePrintfContinue( "Pos0WeakSig" ); + break; + case 0xFF: + ConsolePrintfContinue( "No result" ); + break; + default: + ConsolePrintfContinue( "UNKNOWN" ); + break; + } + ConsolePrintfExit( ") Position: %d"RESETCOLOR"\n", position ); +} + +void CNetworkDeviceListener::OnControlChannelReadEnd( void *source ) +{ + ConsolePrintf( PRIO_LOW, "BASE->OnControlChannelReadEnd\n" ); +} + +void CNetworkDeviceListener::OnMostControlMessage( void *source, uint32_t sourceAddr, uint32_t targetAddr, + uint32_t nFBlock, uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ) +{ + ConsolePrintf( PRIO_LOW, "Base->OnMostControlMessage\n" ); +} + +void CNetworkDeviceListener::OnDeviceVersion( void *source, bool success, uint32_t sourceAddr, uint32_t productId, + uint32_t fwVersion, uint32_t buildVersion, uint8_t hwVersion, uint16_t diagnosisId, uint32_t tag ) +{ + ConsolePrintf( PRIO_LOW, "BASE->OnDeviceVersion::OnDeviceVersion, success=%s\n", + ( success ? GREEN"yes"RESETCOLOR : RED"no"RESETCOLOR ) ); +} diff --git a/Src/Network/NetworkDeviceListener.h b/Src/Network/NetworkDeviceListener.h new file mode 100644 index 0000000..719bc5f --- /dev/null +++ b/Src/Network/NetworkDeviceListener.h @@ -0,0 +1,568 @@ +/* + * 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 CNetworkDeviceListener class. + */ +/*----------------------------------------------------------*/ +#ifndef _NETWORKDEVICELISTENER_H_ +#define _NETWORKDEVICELISTENER_H_ + +#include <stdint.h> +#include "Types.h" + +/*----------------------------------------------------------*/ +/*! \brief This class defines callbacks methods which will be called by CNetworkDevice to any + * registered listener. Also this class implements empty implementation of each method. + * So the integrator has only to override methods, he is interessted in. + */ +/*----------------------------------------------------------*/ +class CNetworkDeviceListener +{ +public: + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a sync event has been detected on the server network device. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnSync( void *source, bool isSynced ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a Network State event has been detected on the server network device. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param mpValChanged - true, there was a change in the Maximum Position Information. false, no change. + * \param systemNotOk - true, system state changes to NotOk. false, no change. + * \param mostAvailable - true, the MOST network is available. false, The MOST network is not available for sending control/packet data. + * \param availableSubState - 0=Regular, 2=Diagnosis, 4=RxOnBlocked, 6=ForcedNA, 0x10=Unstable, 0x11=Stable + * \param availableTransition - 0=Command, 1=RxActivity, 2=DiagnosisReady, 0x10=Normal, 0x11=SuddenSignalOff, 0x12=CriticalUnlock + * 0x13=ErrorSystem, 0xFF=NoTransition + * \param nodeAddress - The assigned MOST node address. + * \param nodePos - The position in the MOST ring. + * \param maxPos - The maximum amount of devices in the MOST ring. + * \param packetBW - The amount of bytes reserved for packet channel (MEP/MHP) + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnNetworkState( void *source, bool mpValChanged, bool systemNotOk, + bool mostAvailable, uint8_t availableSubState, uint8_t availableTransition, uint16_t nodeAddress, + uint8_t nodePos, uint8_t maxPos, uint16_t packetBW ); + + + + virtual void OnInitCompleteV1( void *source ); + virtual void OnUnlockV1( void *source ); + virtual void OnNetOnV1( void *source, bool isMaster ); + virtual void OnShutDownV1( void *source ); + virtual void OnNprV1( void *source, uint8_t npr ); + virtual void OnMprV1( void *source, uint8_t oldMpr, uint8_t newMpr ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever the MOST had been tried to start. + * \param success - true, when the operation was successful. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 D-Rev + */ + /*----------------------------------------------------------*/ + virtual void OnNetworkStartupV3( void *source, bool success ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever the MOST had been tried to shutdown. + * \param success - true, when the operation was successful. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 D-Rev + */ + /*----------------------------------------------------------*/ + virtual void OnNetworkShutdownV3( void *source, bool success ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MAC address has been changed in the network. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddress - The device with this MOST node address raised this event. + * \param macAddress1 - The 1st byte of the MAC address. + * \param macAddress2 - The 2nd byte of the MAC address. + * \param macAddress3 - The 3rd byte of the MAC address. + * \param macAddress4 - The 4th byte of the MAC address. + * \param macAddress5 - The 5th byte of the MAC address. + * \param macAddress6 - The 6th byte of the MAC address. + * \note This is event will be raised by all INIC APIS (V1 & V2). + */ + /*----------------------------------------------------------*/ + virtual void OnMostMacAddress( void *source, bool success, uint16_t nodeAddress, uint8_t macAddress1, + uint8_t macAddress2, uint8_t macAddress3, uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6 ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a Device type has been detected. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param nodeAddress - The device with this MOST node address raised this event. + * \param deviceType - Identifier which sorts the MOST device to a specific function group. + * \note In this implementation the Device Type is simply derived from the Group Address set in the INIC config string! + * \note This is event will be raised by all INIC APIS (V1 & V2). + */ + /*----------------------------------------------------------*/ + virtual void OnMostDeviceType( void *source, bool success, uint16_t nodeAddress, uint16_t deviceType ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever the TSI bus was opened. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddress - The device with this MOST node address raised this event. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnOpenTsiV1( void *source, bool success, uint16_t nodeAddress ); + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a TSI socket was created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param tsiPortInst - The use TSI port. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthMlb - The block width in bytes allocated on the MLB bus. + * \param mlbChannelAddress - The MLB channel address (even value). + * \param socketHandle - Unique handle for this socket. Use this for creating connections or closing this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateTsiSocketV1( void *source, bool success, uint16_t nodeAddr, V1TsiPortInstance_t tsiPortInst, + EPDataType_t epType, EPDirection_t epDir, uint16_t blockWidthTsi, uint16_t socketHandle, uint32_t tag ); + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever the MLB bus was opened. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddress - The device with this MOST node address raised this event. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnOpenMlbV1( void *source, bool success, uint16_t nodeAddress ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MLB socket was created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthMlb - The block width in bytes allocated on the MLB bus. + * \param mlbChannelAddress - The MLB channel address (even value). + * \param socketHandle - Unique handle for this socket. Use this for creating connections or closing this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateMlbSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MOST socket was created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockwidthMost - The block width in bytes allocated on the MOST bus. + * \param connectionLabel - The MOST connection label, which this socket will be bound. + * \param socketHandle - Unique handle for this socket. Use this for creating connections or closing this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateMostSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever two MOST sockets where connected. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param inSocketHandle - The user given IN-handle. + * \param outSocketHandle - The user given OUT-handle. + * \param connectionHandle - Unique handle for this connection. Use this for disconnecting this connection again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnConnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t inSocketHandle, + uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MOST socket was deestroyed. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddress - The device with this MOST node address raised this event. + * \param handle - The unique handle for this socket. After this call, the handle is invalid. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnDestroySocketV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MOST connection was disconnected. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddress - The device with this MOST node address raised this event. + * \param handle - The unique handle for this connection. After this call, the handle is invalid. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 1 event. It is raised from e.g. OS81110 + */ + /*----------------------------------------------------------*/ + virtual void OnDisconnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a I2S port has been configured. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnOpenI2SPortV1( void *source, bool success, uint16_t nodeAddress, V1I2SPortClkDriveMode_t portMode, + V1I2SStreamingDataFormat_t format, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a I2S socket has been created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - he Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param pin - The physical I2S data pin of the INIC. + * \param socketHandle - Unique handle for this socket. Use this for creating connections or destroying this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateI2SSocketV1( void *source, bool success, uint16_t nodeAddr, EPDirection_t epDir, + uint16_t blockWidthI2S, V1I2SPin_t pin, uint16_t socketHandle, uint32_t tag ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever the MLB bus was opened. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddress - The device with this MOST node address raised this event. + * \param mlbPortHandle - The device with this MOST node address raised this event. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnOpenMlbV3( void *source, bool success, uint16_t nodeAddress, uint16_t mlbPortHandle ); + + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a USB socket was created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param endPointAddress - The USB endpoint address, which is now usable. + * \param socketHandle - Unique handle for this socket. Use this for creating connections or closing this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t socketHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a USB socket was created, which uses a Splitter or a Combiner. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param endPointAddress - The USB endpoint address, which is now usable. + * \param usbHandle - Unique handle for this USB socket. Do not use this for creating connections! + * \param splitterHandle - Unique handle for this Splitter socket. Use this for creating connections or closing this socket again! + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateSplittedUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t usbHandle, uint16_t splitterHandle, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MLB socket was created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthMlb - The block width in bytes allocated on the MLB bus. + * \param mlbChannelAddress - The MLB channel address (even value). + * \param socketHandle - Unique handle for this socket. Use this for creating connections or closing this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MLB socket was created, which uses a Splitter or a Combiner. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthMlb - The block width in bytes allocated on the MLB bus. + * \param mlbChannelAddress - The MLB channel address (even value). + * \param mlbSocketHandle - Unique handle for this socket. Use this for creating connections or closing this socket again. + * \param splitterHandle - Unique handle for this Splitter socket. Use this for creating connections or closing this socket again! + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateSplittedMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t mlbSocketHandle, + uint16_t splitterHandle, uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a MOST socket was created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this endpoint. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockwidthMost - The block width in bytes allocated on the MOST bus. + * \param connectionLabel - The MOST connection label, which this socket will be bound. + * \param socketHandle - Unique handle for this socket. Use this for creating connections or destroying this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateMostSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever two MOST sockets where connected. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param epType - The data type, which then will be transmitted on this connection. + * \param inSocketHandle - The user given IN-handle. + * \param outSocketHandle - The user given OUT-handle. + * \param connectionHandle - Unique handle for this connection. Use this for destroying this connection again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnConnectSocketsV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + uint16_t inSocketHandle, uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever MOST resources where destroyed. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param amountOfHandles - The amount of resources to be destroyed. (value will be between 1 to 3). + * \param pHandle - Pointer to the resource list + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnResourceDestroyV3( void *source, bool success, uint16_t nodeAddr, uint8_t amountOfHandles, + const uint16_t *pHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a I2S port has been configured. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param option - The I2S port option. + * \param mode - The I2S clock mode. + * \param delay - The I2S delay mode. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnConfigureI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortOption_t option, V3I2SClockMode_t mode, V3I2SDelayMode_t delay, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a I2S port has been created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param clock - The I2S port speed in multiple of MOST base clock. + * \param align - The I2S data format alignment. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortSpeed_t clock, V3I2SAlignment_t align, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a I2S socket has been created. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - he Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param pin - The physical I2S data pin of the INIC. + * \param socketHandle - Unique handle for this socket. Use this for creating connections or destroying this socket again. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t socketHandle, uint32_t tag ); + + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when ever a I2S socket has been created, which uses a Splitter or a Combiner. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param nodeAddr - The device with this MOST node address raised this event. + * \param portInstance - The I2S port instance. 0 = Port A, 1 = Port B. + * \param epDir - The Direction of the stream. (EPDIR_IN == Data from the INIC to the EHC, EPDIR_OUT == Data from the EHC to the INIC) + * \param blockWidthI2S - The block width in bytes allocated on the I2S bus. + * \param pin - The physical I2S data pin of the INIC. + * \param i2sSocketHandle - Unique handle for this socket. Use this for creating connections or destroying this socket again. + * \param splitterHandle - Unique handle for this Splitter socket. Use this for creating connections or closing this socket again! + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnCreateSplittedI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t i2sSocketHandle, uint16_t splitterHandle, + uint32_t tag ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when a Ring Break Diagnosis Result was received. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param nodeAddr - The device with this MOST node address raised this event. + * \praram result - The ring break diagnosis result + * \param position - Relative position to the ring break. + * \param status - Gives information about the activity state. + * \param id - The RBD identifier as configured in config string. + * \note This is an INIC API Version 3 event. It is raised from e.g. OS81118 + */ + /*----------------------------------------------------------*/ + virtual void OnRbdResultV3( void *source, uint16_t nodeAddress, uint8_t result, uint8_t position, + uint8_t status, uint16_t id ); + + + /*----------------------------------------------------------*/ + /*! \brief Callback, when the MOST control channel receive thread has ended. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + */ + /*----------------------------------------------------------*/ + virtual void OnControlChannelReadEnd( void *source ); + + + /*----------------------------------------------------------*/ + /*! \brief This callback method is called whenever a MOST control message was sent or received. + * \note In order to be informed about this event, derive this class, implement this method and register the class with AddListener method of CNetwork class. + * \note The user may interpret the data and sent a corresponding MOST control message via CNetwork::SendMostControlMessage. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param sourceAddr - The MOST source address (may be not accurate) + * \param targetAddr - The MOST target address + * \param nFBlock - The MOST Function Block Identifier + * \param nInst - The MOST Function Block Instance Identifier + * \param nFunc - The MOST Function Block Function Identifier + * \param nPayloadLen - The amount of bytes stored in Payload + * \param Payload - The pointer to the payload byte array. + * + */ + /*----------------------------------------------------------*/ + virtual void OnMostControlMessage( void *source, uint32_t sourceAddr, uint32_t targetAddr, uint32_t nFBlock, + uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ); + + /*----------------------------------------------------------*/ + /*! \brief This callback method is as result of the DeviceVersion query. + * \param source - Cast this pointer to (CNetworkDevice*), it points to server network device, which received this event. + * \param success - true, when the operation was successful. + * \param sourceAddr - The device with this MOST node address raised this event. + * \param productId - Unique identifier that represents the product name. + * \param fwVersion - INIC firmware version: Byte[3] Major, Byte[2] Minor, Byte[1] Release. + * \param buildVersion - Build version of the firmware. + * \param hwVersion - Chip revision number. + * \param diagnosisId - Unique diagnosis identifier of the device. + * \param tag - Any 32 bit value. This value was passed to the corresponding function call of the CNetworkDevice class. + */ + /*----------------------------------------------------------*/ + virtual void OnDeviceVersion( void *source, bool success, uint32_t sourceAddr, + uint32_t productId, uint32_t fwVersion, uint32_t buildVersion, uint8_t hwVersion, uint16_t diagnosisId, uint32_t tag ); + +}; + +#endif //_NETWORKDEVICELISTENER_H_ diff --git a/Src/Network/Network_CB.cpp b/Src/Network/Network_CB.cpp new file mode 100644 index 0000000..3a91cc2 --- /dev/null +++ b/Src/Network/Network_CB.cpp @@ -0,0 +1,1823 @@ +/* + * 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. + * + */ + +#include <stdint.h> +#include <stddef.h> +#include "SafeVector.h" +#include "Network.h" +#include "NetworkDevice.h" +#include "DriverConfiguration.h" +#include "MacAddr.h" +#include "Board.h" +#include "Console.h" +#include "NodeDatabase.h" + +#define PRINT_ALL_INFOS() + +void CNetwork::OnSync( void *source, bool isSynced ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + ConsolePrintf( PRIO_MEDIUM, "CNetwork::OnSync(deviceInstance:%d, isSynced:%d\n", devInstance, isSynced ); + + if( isSynced ) + { + device->SetNetstate( NetworkState_Unknown ); + device->AttachV3(); + } +} + +void CNetwork::OnNetworkState( void *source, bool mpValChanged, bool systemNotOk, bool mostAvailable, + uint8_t availableSubState, uint8_t availableTransition, uint16_t nodeAddress, uint8_t nodePos, uint8_t maxPos, + uint16_t packetBW ) +{ + if( NULL == source || !allowNetworkRun ) + return; + if (0x100 != nodeAddress && 0x1 != nodeAddress && 0xFFFF != nodeAddress) + return; + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + ConsolePrintf( PRIO_HIGH, + YELLOW"CNetwork::OnNetworkState(inst:%d, mpChanged:%d, " \ + "notOk:%d, available:%d, sub:0x%X, trans:0x%X, address:0x%X, pos:%d, " \ + "mpr:%d, bw:%d"RESETCOLOR"\n", devInstance, mpValChanged, + systemNotOk, mostAvailable, availableSubState, availableTransition, + nodeAddress, nodePos, maxPos, packetBW ); + + NetworkState_t curState = device->GetNetState(); + if (NetworkState_ShutdownInProgress == curState) + { + ConsolePrintf( PRIO_HIGH, "Ignoring OnNetworkState, because shutdown is still in progress\n"); + return; + } + + for( uint32_t i = 0; i < allListeners.Size(); i++ ) + { + allListeners[i]->OnNetworkState(devInstance, mostAvailable, maxPos, packetBW); + } + + if( mostAvailable ) + { + if( NetworkState_Available == curState ) + { + if( 0x10 == availableSubState ) + { + ConsolePrintf( PRIO_ERROR, RED"Unlock detected, shutting down MOST."RESETCOLOR"\n" ); + device->SetNetstate( NetworkState_ShutdownInProgress ); + device->ClearAllPendingActions(); + device->MostNetworkShutdownV3(); + return; + } + else if( mpValChanged && 0xFF != maxPos ) + { + ConsolePrintf( PRIO_ERROR, RED"MPR change detected, shutting down MOST."RESETCOLOR"\n" ); + device->SetNetstate( NetworkState_ShutdownInProgress ); + device->ClearAllPendingActions(); + device->MostNetworkShutdownV3(); + return; + } + else if( 0x11 == availableSubState ) + { + ConsolePrintf( PRIO_MEDIUM, YELLOW"CNetwork::OnNetworkState was called with the same mostAvailable (%d) value as before, ignoring.."RESETCOLOR"\n", + mostAvailable ); + return; + } + } + } + else + { + if( 0x02 == availableSubState ) + { + ConsolePrintf( PRIO_HIGH, YELLOW"INIC enters Ring Break Diagnosis mode!"RESETCOLOR"\n" ); + device->GetRingBreakResultV3( 1, 0 ); + } + if( NetworkState_Unavailable == curState ) + { + ConsolePrintf( PRIO_MEDIUM, YELLOW"CNetwork::OnNetworkState was called with the same mostAvailable (%d) value as before, ignoring.."RESETCOLOR"\n", + mostAvailable ); + return; + } + } + + bool isTimingMaster = device->IsTimingMaster(); + uint32_t asyncBandwidth = device->GetAsyncBandwidth(); + + if( !mostAvailable ) + { + device->SetNetstate( NetworkState_Unavailable ); + device->ClearAllPendingActions(); + DestroyAllResources( device, 0x1 ); + //Clear all existing connection information for this MOST instance + while( true ) + { + bool deleted = false; + for( uint16_t i = 0; i < CNodeEntry::GetAmountOfNodeEntries(); i++ ) + { + CNodeEntry *entry = CNodeEntry::GetNodeEntry( i ); + if( NULL == entry ) + continue; + if( devInstance == entry->deviceInstance ) + { + for( uint16_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByIndex( j ); + RaiseUnavailable( connection ); + } + CNodeEntry::DeleteNodeEntry( i ); + deleted = true; + break; + } + } + if( !deleted ) + break; + } + if( 2 == device->GetDeviceApi() ) + { + ConsolePrintf( PRIO_ERROR, RED"Error, device API V2 is not supported by "\ + "this version of NetworkManager!"RESETCOLOR ); + } + else if( 3 == device->GetDeviceApi() && isTimingMaster ) + { + ConsolePrintf( PRIO_MEDIUM, "CNetwork::OnNetworkState calling MostNetworkStartupV3\n" ); + device->MostNetworkStartupV3( 0xFFFF, asyncBandwidth ); + } + else + { + ConsolePrintf( PRIO_ERROR, RED"Error, device API '%d' is not supported by "\ + "this version of NetworkManager!"RESETCOLOR, device->GetDeviceApi() ); + } + } + else if (asyncBandwidth != packetBW) + { + ConsolePrintf( PRIO_ERROR, RED"Packet Bandwidth does not match."\ + " Expected:%d Is:%d, forcing MOST shutdown"RESETCOLOR"\n", asyncBandwidth, packetBW ); + device->SetNetstate( NetworkState_ShutdownInProgress ); + device->MostNetworkShutdownV3(); + } + else if( !systemNotOk + && ( maxPos <= 64 ) + && ( packetBW <= 372 ) + && ( 0x11 == availableSubState ) ) + { + //Everything is ok. Start query network devices + device->SetNetstate( NetworkState_Available ); + if( isTimingMaster ) + { + device->ToggleNotOk(); + } + device->GetGroupAddresses( maxPos ); + } +} + +void CNetwork::OnNetworkStartupV3( void *source, bool success ) +{ + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + if( success ) + { + ConsolePrintf( PRIO_MEDIUM, GREEN"CNetwork::OnNetworkStartupV3 success!"RESETCOLOR"\n" ); + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnNetworkStartupV3 failed, retrying.."RESETCOLOR"\n" ); + device->ScriptPause(500); + device->MostNetworkStartupV3(); + } +} + +void CNetwork::OnNetworkShutdownV3( void *source, bool success ) +{ + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + if( success ) + { + ConsolePrintf( PRIO_HIGH, GREEN"CNetwork::OnNetworkShutdownV2 success"RESETCOLOR"\n" ); + } + else + { + ConsolePrintf( PRIO_ERROR, RED"CNetwork::OnNetworkShutdownV2 failed"RESETCOLOR"\n" ); + } + device->SetNetstate( NetworkState_Unknown ); + device->InicUnsychronizeV3(); +} + +void CNetwork::OnMostDeviceType( void *source, bool success, uint16_t nodeAddress, uint16_t deviceType ) +{ + if( NULL == source ) + return; + if( nodeAddress >= 0x400 && nodeAddress <= 0x4FF ) + nodeAddress = nodeAddress - 0x300; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnMostDeviceType reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddress ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, "CNetwork::OnMostDeviceType(deviceInstance:%d, nodeAddress:0x%X, deviceType: 0x%X)\n", + devInstance, nodeAddress, deviceType ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddress ); + sem_wait( &vodXmlMutex ); + if( ( NULL == entry ) || ( NULL == vodXml ) ) + { + sem_post( &vodXmlMutex ); + return; + } + entry->deviceType = deviceType; + CSafeVector<CChannelConfiguration *> allChannels; + uint32_t apiVer = vodXml->GetDeviceApi( deviceType ); + + if( 0xFFFFFFFF == apiVer ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnMostDeviceType reports unknown API version '%d' for"\ + " device 0x%X with node address 0x%X, please check GroupAddress in ConfigString or edit configuration file"\ + RESETCOLOR"\n", apiVer, deviceType, nodeAddress ); + sem_post( &vodXmlMutex ); + RaiseUknownConnection( devInstance, nodeAddress, EP_Unknown ); + return; + } + else if( 2 == apiVer || apiVer > 3 ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnMostDeviceType reports API version '%d' for"\ + " device 0x%X with node address 0x%X, this is not longer supported by this version of NetworkManager"\ + RESETCOLOR"\n", apiVer, deviceType, nodeAddress ); + sem_post( &vodXmlMutex ); + RaiseUknownConnection( devInstance, nodeAddress, EP_Unknown ); + return; + } + + //Set MAC address regardless if set permanently or not. This MAC address contains MOST specific informations. + //This is necessary, because the bytes in the MAC address are used to identify the streams in the multiplexer. + CMacAddr *macAddress = SetMacAddress( device, devInstance, nodeAddress, apiVer ); + if( NULL != macAddress ) + { + if( NULL != entry->macAddress ) + { + CMacAddr *temp = entry->macAddress; + entry->macAddress = macAddress; + delete temp; + } + else + { + entry->macAddress = macAddress; + } + for( uint16_t i = 0; i < entry->GetAmountOfConnections(); i++ ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByIndex( i ); + if( NULL != connection ) + { + RaiseAvailable( connection ); + } + } + } + else + { + ConsolePrintf( PRIO_ERROR, RED"Setting MAC address failed!"RESETCOLOR"\n" ); + RaiseUknownConnection( devInstance, nodeAddress, EP_Unknown ); + } + + if( vodXml->GetChannelConfigurations( deviceType, allChannels ) ) + { + if( 0 == allChannels.Size() ) + { + RaiseUknownConnection( devInstance, nodeAddress, EP_Unused ); + } + else + for( uint32_t i = 0; i < allChannels.Size(); i++ ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( allChannels[i]->channelId, true ); + if( NULL == connection->channelConfig ) + { + connection->channelConfig = allChannels[i]; + } + + if( 1 == apiVer ) + { + /*------------------------------------*/ + /*- INIC API VERSION 1 */ + /*------------------------------------*/ + + if( ( PORT_MLB == connection->channelConfig->inSocket.port ) + || ( PORT_MLB == connection->channelConfig->outSocket.port ) ) + { + EPDirection_t direction = EPDIR_Unknown; + CSocketConfiguration *conf = NULL; + if( PORT_MLB == connection->channelConfig->inSocket.port ) + { + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + direction = EPDIR_IN; + conf = &connection->channelConfig->inSocket; + } + else + { + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + direction = EPDIR_OUT; + conf = &connection->channelConfig->outSocket; + } + if( !entry->isMlbPortOpened ) + { + entry->isMlbPortOpened = true; + device->OpenMlbV1( nodeAddress, vodXml->GetDeviceMlbPortSpeed( deviceType ) ); + } + if( 0xFFFFFFFF == conf->splittedOffset ) + { + //Normal socket is used + device->CreateMlbSocketV1( nodeAddress, conf->type, direction, conf->address, + conf->blockWidth, allChannels[i]->channelId ); + } + else + { + //Enhanced (Splitted) Sockets are used + device->CreateSplittedMlbSocketV1( nodeAddress, conf->type, direction, conf->address, + conf->blockWidth, conf->splittedOffset, conf->subbufferSize, + allChannels[i]->channelId ); + } + } + if( ( PORT_TSI == connection->channelConfig->inSocket.port ) + || ( PORT_TSI == connection->channelConfig->outSocket.port ) ) + { + EPDirection_t direction = EPDIR_Unknown; + CSocketConfiguration *conf = NULL; + if( PORT_TSI == connection->channelConfig->inSocket.port ) + { + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + direction = EPDIR_IN; + conf = &connection->channelConfig->inSocket; + } + else + { + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + direction = EPDIR_OUT; + conf = &connection->channelConfig->outSocket; + } + if( !entry->isTsiPortOpened ) + { + entry->isTsiPortOpened = true; + device->OpenTsiV1( nodeAddress, conf->tsiConfig.tsiPortInstance, + conf->tsiConfig.tsiPortMode ); + } + device->CreateTsiSocketV1( nodeAddress, conf->tsiConfig.tsiPortInstance, conf->type, direction, + conf->blockWidth, allChannels[i]->channelId ); + } + if( ( PORT_I2S == connection->channelConfig->inSocket.port ) + || ( PORT_I2S == connection->channelConfig->outSocket.port ) ) + { + EPDirection_t direction = EPDIR_Unknown; + CSocketConfiguration *conf = NULL; + if( PORT_I2S == connection->channelConfig->inSocket.port ) + { + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + direction = EPDIR_IN; + conf = &connection->channelConfig->inSocket; + } + else + { + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + direction = EPDIR_OUT; + conf = &connection->channelConfig->outSocket; + } + if( !entry->isI2SPortOpened ) + { + if( V1I2sClockModeUnknown != conf->i2sConfig.portClkDriveModeV1 + && V1I2sDataFormatUnknown != conf->i2sConfig.streamingDataFormatV1 ) + { + entry->isI2SPortOpened = true; + device->OpenStreamPortV1( nodeAddress, conf->i2sConfig.portClkDriveModeV1, + conf->i2sConfig.portOptionV1, conf->i2sConfig.streamingDataFormatV1, + allChannels[i]->channelId ); + } + } + if( 0xFFFFFFFF == conf->splittedOffset ) + { + //Normal socket is used + device->CreateStreamSocketV1( nodeAddress, direction, conf->blockWidth, conf->i2sConfig.pinV1, + allChannels[i]->channelId ); + } + else + { + //Enhanced (Splitted) Sockets are used + device->CreateSplittedStreamSocketV1( nodeAddress, direction, + conf->blockWidth, conf->splittedOffset, conf->subbufferSize, conf->i2sConfig.pinV1, + allChannels[i]->channelId ); + } + + } + + if( PORT_MOST == connection->channelConfig->outSocket.port ) + { + //Open MOST in case of out-connections + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + CSocketConfiguration *conf = &connection->channelConfig->outSocket; + device->CreateMostSocketV1( nodeAddress, conf->type, EPDIR_OUT, conf->address, + conf->blockWidth, allChannels[i]->channelId ); + } + else if( ( PORT_MOST == connection->channelConfig->inSocket.port ) + && ( 0xFFFFFFFF != connection->channelConfig->inSocket.address ) ) + { + //Or open MOST in case of in-connections with set connection label + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + CSocketConfiguration *conf = &connection->channelConfig->inSocket; + ConsolePrintf( PRIO_MEDIUM, + "Creating MOST socket for preconfigured Connection Label %d (0x%X)\n", conf->address, + conf->address ); + device->CreateMostSocketV1( nodeAddress, conf->type, EPDIR_IN, conf->address, conf->blockWidth, + allChannels[i]->channelId ); + } + } + else if( 3 == apiVer ) + { + /*--------------------------------------------*/ + /*-INIC API VERSION 3 (OS81118-D-Rev FW2.3.0) */ + /*--------------------------------------------*/ + if (0 == i) + device->GetDeviceVersion( nodeAddress ); + + //Destroy all resources + if( !entry->isUsbPortOpened && ( 0x1 != nodeAddress ) ) + { + entry->isUsbPortOpened = true; + device->DeviceSyncV3( nodeAddress, true ); + } + + if( ( PORT_USB == connection->channelConfig->inSocket.port ) + || ( PORT_USB == connection->channelConfig->outSocket.port ) ) + { + EPDirection_t direction = EPDIR_Unknown; + CSocketConfiguration *conf = NULL; + if( PORT_USB == connection->channelConfig->inSocket.port ) + { + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + direction = EPDIR_IN; + conf = &connection->channelConfig->inSocket; + } + else + { + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + direction = EPDIR_OUT; + conf = &connection->channelConfig->outSocket; + } + if( 0xFFFFFFFF == conf->splittedOffset ) + { + //No Splitter / No Combiner + device->CreateUsbSocketV3( nodeAddress, conf->type, direction, conf->address, + conf->packetsPerTransaction, allChannels[i]->channelId ); + } + else + { + //Splitter or Combiner is used + //Do not create multiple USB sockets for a single Splitter / Combiner connection + bool skip = false; + for( uint16_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *checkConn = entry->GetConnectionByIndex( j ); + CSocketConfiguration *checkConf = NULL; + if( EPDIR_IN == direction ) + checkConf = &checkConn->channelConfig->inSocket; + else + checkConf = &checkConn->channelConfig->outSocket; + + if( ( checkConf != conf ) && ( conf->address == checkConf->address ) ) + { + skip = true; + break; + } + } + RaiseAvailable( connection ); + if( !skip ) + device->CreateSplittedUsbSocketV3( nodeAddress, conf->type, direction, conf->address, + conf->packetsPerTransaction, conf->subbufferSize, allChannels[i]->channelId ); + } + } + if( ( PORT_MLB == connection->channelConfig->inSocket.port ) + || ( PORT_MLB == connection->channelConfig->outSocket.port ) ) + { + EPDirection_t direction = EPDIR_Unknown; + CSocketConfiguration *conf = NULL; + if( PORT_MLB == connection->channelConfig->inSocket.port ) + { + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + direction = EPDIR_IN; + conf = &connection->channelConfig->inSocket; + } + else + { + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + direction = EPDIR_OUT; + conf = &connection->channelConfig->outSocket; + } + if( !entry->isMlbPortOpened ) + { + entry->isMlbPortOpened = true; + device->OpenMlbV3( nodeAddress, vodXml->GetDeviceMlbPortSpeed( deviceType ) ); + } + if( 0xFFFFFFFF == conf->splittedOffset ) + { + //No Splitter / No Combiner + device->CreateMlbSocketV3( nodeAddress, ( uint16_t )0x0A00, //Const value for first instance of MLB bus + conf->type, direction, conf->address, conf->blockWidth, allChannels[i]->channelId ); + } + else + { + //Splitter or Combiner is used + //Do not create multiple MLB sockets for a single Splitter / Combiner connection + bool skip = false; + for( uint16_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *checkConn = entry->GetConnectionByIndex( j ); + CSocketConfiguration *checkConf = NULL; + if( EPDIR_IN == direction ) + checkConf = &checkConn->channelConfig->inSocket; + else + checkConf = &checkConn->channelConfig->outSocket; + + if( ( checkConf != conf ) && ( conf->address == checkConf->address ) ) + { + skip = true; + break; + } + } + RaiseAvailable( connection ); + if( !skip ) + device->CreateSplittedMlbSocketV3( nodeAddress, ( uint16_t )0x0A00, //Const value for first instance of MLB bus + conf->type, direction, conf->address, conf->blockWidth, conf->subbufferSize, + allChannels[i]->channelId ); + } + } + if( ( PORT_I2S == connection->channelConfig->inSocket.port ) + || ( PORT_I2S == connection->channelConfig->outSocket.port ) ) + { + EPDirection_t direction = EPDIR_Unknown; + CSocketConfiguration *conf = NULL; + uint8_t portInst = 0xFF; + if( PORT_I2S == connection->channelConfig->inSocket.port ) + { + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + direction = EPDIR_IN; + conf = &connection->channelConfig->inSocket; + } + else + { + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + direction = EPDIR_OUT; + conf = &connection->channelConfig->outSocket; + } + switch( conf->i2sConfig.pin ) + { + case V3I2SSRXA0: + case V3I2SSRXA1: + portInst = 0; + break; + case V3I2SSRXB0: + case V3I2SSRXB1: + portInst = 1; + break; + default: + break; + } + if( !entry->isI2SPortOpened ) + { + if( V3I2SOptionUnknown != conf->i2sConfig.portOption ) + { + entry->isI2SPortOpened = true; + device->ConfigureStreamPortV3( nodeAddress, 0, conf->i2sConfig.portOption, + conf->i2sConfig.clockMode, conf->i2sConfig.delayMode, allChannels[i]->channelId ); + device->ConfigureStreamPortV3( nodeAddress, 1, conf->i2sConfig.portOption, + V3I2SClockModeWildcard, V3I2SDelayWildcard, allChannels[i]->channelId ); + } + if( V3I2SSpeedUnknown != conf->i2sConfig.portSpeed ) + { + entry->isI2SPortOpened = true; + device->CreateStreamPortV3( nodeAddress, 0, conf->i2sConfig.portSpeed, + conf->i2sConfig.alignment, allChannels[i]->channelId ); + device->CreateStreamPortV3( nodeAddress, 1, V3I2SSpeedWildcard, + conf->i2sConfig.alignment, allChannels[i]->channelId ); + } + } + if( 0xFFFFFFFF == conf->splittedOffset ) + { + //No Splitter / No Combiner + device->CreateStreamSocketV3( nodeAddress, portInst, direction, conf->blockWidth, + conf->i2sConfig.pin, allChannels[i]->channelId ); + } + else + { + //Splitter or Combiner is used + //Do not create multiple I2S sockets for a single Splitter / Combiner connection + bool skip = false; + for( uint16_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *checkConn = entry->GetConnectionByIndex( j ); + CSocketConfiguration *checkConf = NULL; + if( EPDIR_IN == direction ) + checkConf = &checkConn->channelConfig->inSocket; + else + checkConf = &checkConn->channelConfig->outSocket; + + if( ( checkConf != conf ) && ( conf->i2sConfig.pin == checkConf->i2sConfig.pin ) ) + { + skip = true; + break; + } + } + RaiseAvailable( connection ); + if( !skip ) + device->CreateSplittedStreamSocketV3( nodeAddress, portInst, direction, + conf->blockWidth, conf->i2sConfig.pin, conf->subbufferSize, + allChannels[i]->channelId ); + } + + } + if( PORT_MOST == connection->channelConfig->outSocket.port ) + { + //Open MOST in case of out-connections + if( connection->outSocketState != NodeConnection_NotUsed ) + continue; + connection->outSocketState = NodeConnection_Pending_Up; + CSocketConfiguration *conf = &connection->channelConfig->outSocket; + device->CreateMostSocketV3( nodeAddress, conf->type, EPDIR_OUT, conf->address, + conf->blockWidth, allChannels[i]->channelId ); + } + else if( ( PORT_MOST == connection->channelConfig->inSocket.port ) + && ( 0xFFFFFFFF != connection->channelConfig->inSocket.address ) ) + { + //Or open MOST in case of in-connections with set connection label + if( connection->inSocketState != NodeConnection_NotUsed ) + continue; + connection->inSocketState = NodeConnection_Pending_Up; + CSocketConfiguration *conf = &connection->channelConfig->inSocket; + ConsolePrintf( PRIO_MEDIUM, + "Creating MOST socket for preconfigured Connection Label %d (0x%X)\n", conf->address, + conf->address ); + device->CreateMostSocketV3( nodeAddress, conf->type, EPDIR_IN, conf->address, conf->blockWidth, + allChannels[i]->channelId ); + } + } + else + { + ConsolePrintf( PRIO_ERROR, RED"Unknown INIC api version:%d"RESETCOLOR"\n", apiVer ); + } + //Perform external script at the end + if( i == ( allChannels.Size() - 1 ) ) + { + if( NULL != connection->channelConfig->externalScipt ) + { + char configPath[300]; + if( NULL != searchPath ) + snprintf( configPath, sizeof ( configPath ), "%s/%s", searchPath, + connection->channelConfig->externalScipt ); + else + strncpy( configPath, connection->channelConfig->externalScipt, sizeof ( configPath ) ); + device->ExecuteMcmScript( nodeAddress, configPath ); + } + } + } + } + else + { + ConsolePrintf( PRIO_ERROR, + YELLOW"CNetwork::OnMostDeviceType(deviceType: 0x%X) there is no channel configuration for this device type."RESETCOLOR"\n", + deviceType ); + RaiseUknownConnection( devInstance, nodeAddress, EP_Unknown ); + } + sem_post( &vodXmlMutex ); +} + +void CNetwork::OnCreateTsiSocketV1( void *source, bool success, uint16_t nodeAddr, V1TsiPortInstance_t tsiPortInst, + EPDataType_t epType, EPDirection_t epDir, uint16_t blockWidthTsi, uint16_t socketHandle, uint32_t tag ) +{ + assert(EP_Isochron == epType); + if( NULL == source || EP_Isochron != epType ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateTsiSocketV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateTsiSocketV1, inst:%d, addr:0x%X, port:%d, type:%d, dir:%d, bwTsi:%d, handle:0x%X, tag:0x%X\n", + devInstance, nodeAddr, tsiPortInst, epType, epDir, blockWidthTsi, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateTsiSocketV1, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateMlbSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateMlbSocketV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateMlbSocketV1, inst:%d, addr:0x%X, type:%d, dir:%d, bwMlb:%d, mlbAddr:0x%X, handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, epType, epDir, blockWidthMlb, mlbChannelAddress, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + AimType_t aimType = AIM_UNKNOWN; + uint32_t amountOfBuffers = 0xFFFFFFFF; + uint32_t bufferSize = 0xFFFFFFFF; + uint32_t subbufferSize = 0xFFFFFFFF; + uint32_t packetsPerTransaction = 0xFFFFFFFF; + uint32_t splittedOffset = 0xFFFFFFFF; + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + amountOfBuffers = connection->channelConfig->inSocket.amountOfBuffers; + bufferSize = connection->channelConfig->inSocket.bufferSize; + subbufferSize = connection->channelConfig->inSocket.subbufferSize; + packetsPerTransaction = + connection->channelConfig->inSocket.packetsPerTransaction; + aimType = connection->channelConfig->inSocket.aimType; + splittedOffset = connection->channelConfig->inSocket.splittedOffset; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + amountOfBuffers = connection->channelConfig->outSocket.amountOfBuffers; + bufferSize = connection->channelConfig->outSocket.bufferSize; + subbufferSize = connection->channelConfig->outSocket.subbufferSize; + packetsPerTransaction = + connection->channelConfig->outSocket.packetsPerTransaction; + aimType = connection->channelConfig->outSocket.aimType; + splittedOffset = connection->channelConfig->outSocket.splittedOffset; + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateMlbSocketV1, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + if( EP_Asynchron == epType ) + { + connection->channelConfig->outSocket.type = EP_Asynchron; + connection->channelConfig->inSocket.type = EP_Asynchron; + connection->inSocketState = NodeConnection_Used; + connection->outSocketState = NodeConnection_Used; + connection->connectedSocketState = NodeConnection_Used; + connection->mostConnectionLabel = 0xA; + } + else if( EP_Unknown == epType || EP_Unused == epType ) + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateMlbSocketV1, Channel configuration is invalid, because data type is unknown"RESETCOLOR"\n" ); + } + + TryToConnectSockets( devInstance, nodeAddr, tag ); + if( 0x1 == entry->nodeAddress && ( 0xFFFFFFFF == splittedOffset || 0x0 == splittedOffset ) ) + { + connection->bufferSize = bufferSize; + switch( epType ) + { + case EP_Synchron: + case EP_Isochron: + device->ConfigureMlbChannel( aimType, mlbChannelAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Unknown: + case EP_Unused: + //Do nothing + break; + default: + device->ConfigureMlbChannel( mlbChannelAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize ); + break; + } + } + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateMostSocketV1( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateMostSocketV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateMostSocketV1, inst:%d, addr:0x%X, type:%d, dir:%d, bwMost:%d, conLabel:0x%X, handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, epType, epDir, blockwidthMost, connectionLabel, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + connection->mostConnectionLabel = connectionLabel; + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnConnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t inSocketHandle, + uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnConnectSocketsV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnConnectSocketsV1, inst:%d, addr:0x%X, inHandle:0x%X, outHandle:0x%X, conHandle:0x%X, tag:0x%X\n", + devInstance, nodeAddr, inSocketHandle, outSocketHandle, connectionHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + connection->connectedSocketState = NodeConnection_Used; + connection->connectHandle = connectionHandle; + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnDestroySocketV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, uint32_t tag ) +{ + if( NULL == source ) + return; + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnDestroySocketV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "CNetwork::OnDestroySocketV1(deviceInstance:%d, nodeAddress:0x%X, handle:0x%X, tag:0x%X\n", devInstance, + nodeAddr, handle, tag ); + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + if( ( handle == connection->inHandle ) && + ( NodeConnection_Pending_Down == connection->inSocketState ) ) + { + connection->inHandle = ( 0xFFFFFFFF ); + connection->inSocketState = NodeConnection_NotUsed; + if( ( NULL != connection->channelConfig ) + && ( PORT_MOST == connection->channelConfig->inSocket.port ) ) + { + connection->mostConnectionLabel = 0xFFFFFFFF; + } + } + else if( ( handle == connection->outHandle ) && + ( NodeConnection_Pending_Down == connection->outSocketState ) ) + { + connection->outHandle = ( 0xFFFFFFFF ); + connection->outSocketState = NodeConnection_NotUsed; + if( ( NULL != connection->channelConfig ) + && ( PORT_MOST == connection->channelConfig->outSocket.port ) ) + { + connection->mostConnectionLabel = 0xFFFFFFFF; + } + } + RaiseUnavailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnDisconnectSocketsV1( void *source, bool success, uint16_t nodeAddr, uint16_t handle, uint32_t tag ) +{ + if( NULL == source ) + return; + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnDisconnectSocketsV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "CNetwork::OnDisconnectSocketsV1(deviceInstance:%d, nodeAddress:0x%X, handle:0x%X, tag:0x%X\n", devInstance, + nodeAddr, handle, tag ); + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + if( ( handle == connection->connectHandle ) + && ( NodeConnection_Pending_Down == connection->connectedSocketState ) ) + { + connection->connectHandle = ( 0xFFFFFFFF ); + connection->connectedSocketState = NodeConnection_NotUsed; + } + RaiseUnavailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateI2SSocketV1( void *source, bool success, uint16_t nodeAddr, EPDirection_t epDir, + uint16_t blockWidthI2S, V1I2SPin_t pin, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateI2SSocketV1 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateI2SSocketV1, addr:0x%X, port:%d, dir:%d, blockwidth:%d, pin:%d, handle:0x%X, tag:0x%X\n", + devInstance, nodeAddr, epDir, blockWidthI2S, pin, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateI2SSocket, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateUsbSocketV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateUsbSocketV2, inst:%d, addr:0x%X, type:%d, dir:%d, epAddr:%d, handle:0x%X, tag:0x%X\n", + devInstance, nodeAddr, epType, epDir, endPointAddress, socketHandle, tag ); + + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + AimType_t aimType = AIM_UNKNOWN; + uint32_t amountOfBuffers = 0xFFFFFFFF; + uint32_t bufferSize = 0xFFFFFFFF; + uint32_t subbufferSize = 0xFFFFFFFF; + uint32_t packetsPerTransaction = 0xFFFFFFFF; + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + amountOfBuffers = connection->channelConfig->inSocket.amountOfBuffers; + bufferSize = connection->channelConfig->inSocket.bufferSize; + subbufferSize = connection->channelConfig->inSocket.subbufferSize; + packetsPerTransaction = + connection->channelConfig->inSocket.packetsPerTransaction; + aimType = connection->channelConfig->inSocket.aimType; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + amountOfBuffers = connection->channelConfig->outSocket.amountOfBuffers; + bufferSize = connection->channelConfig->outSocket.bufferSize; + subbufferSize = connection->channelConfig->outSocket.subbufferSize; + packetsPerTransaction = + connection->channelConfig->outSocket.packetsPerTransaction; + aimType = connection->channelConfig->outSocket.aimType; + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateUsbSocketV2, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + + if( 0x1 == entry->nodeAddress ) + { + switch( epType ) + { + case EP_Synchron: + connection->bufferSize = bufferSize; + device->ConfigureUsbEndpoint( aimType, endPointAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Isochron: + connection->bufferSize = bufferSize; + device->ConfigureUsbEndpoint( aimType, endPointAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Unknown: + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateUsbSocketV2, Channel configuration is invalid, because data type is unknown"RESETCOLOR"\n" ); + break; + default: + connection->bufferSize = bufferSize; + device->ConfigureUsbEndpoint( endPointAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize ); + break; + } + } + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateSplittedUsbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint8_t endPointAddress, uint16_t usbHandle, uint16_t splitterHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateSplittedUsbSocketV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateSplittedUsbSocketV2, inst:%d, addr:0x%X, type:%d, dir:%d, epAddr:%d, USB-handle:0x%X, Splitter-handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, epType, epDir, endPointAddress, usbHandle, splitterHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, false ); + if( NULL != connection ) + { + AimType_t aimType = AIM_UNKNOWN; + uint32_t amountOfBuffers = 0xFFFFFFFF; + uint32_t bufferSize = 0xFFFFFFFF; + uint32_t subbufferSize = 0xFFFFFFFF; + uint32_t packetsPerTransaction = 0xFFFFFFFF; + bool valSet = false; + for( uint16_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *checkConn = entry->GetConnectionByIndex( j ); + if( EPDIR_IN == epDir ) + { + if( connection->channelConfig->inSocket.address != checkConn->channelConfig->inSocket.address ) + continue; + checkConn->inSocketState = NodeConnection_Used; + checkConn->inHandle = splitterHandle; + checkConn->splittedSourceHandle = usbHandle; + if( !valSet ) + { + valSet = true; + amountOfBuffers = checkConn->channelConfig->inSocket.amountOfBuffers; + bufferSize = checkConn->channelConfig->inSocket.bufferSize; + subbufferSize = checkConn->channelConfig->inSocket.subbufferSize; + packetsPerTransaction = + checkConn->channelConfig->inSocket.packetsPerTransaction; + aimType = connection->channelConfig->inSocket.aimType; + } + TryToConnectSockets( devInstance, nodeAddr, checkConn->channelId ); + } + else if( EPDIR_OUT == epDir ) + { + if( connection->channelConfig->outSocket.address != checkConn->channelConfig->outSocket.address ) + continue; + checkConn->outSocketState = NodeConnection_Used; + checkConn->outHandle = splitterHandle; + checkConn->splittedSourceHandle = usbHandle; + if( !valSet ) + { + valSet = true; + amountOfBuffers = checkConn->channelConfig->outSocket.amountOfBuffers; + bufferSize = checkConn->channelConfig->outSocket.bufferSize; + subbufferSize = checkConn->channelConfig->outSocket.subbufferSize; + packetsPerTransaction = + checkConn->channelConfig->outSocket.packetsPerTransaction; + aimType = connection->channelConfig->outSocket.aimType; + } + TryToConnectSockets( devInstance, nodeAddr, checkConn->channelId ); + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateUsbSocketV2, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + return; + } + } + + if( 0x1 == entry->nodeAddress ) + { + switch( epType ) + { + case EP_Synchron: + connection->bufferSize = bufferSize; + device->ConfigureUsbEndpoint( aimType, endPointAddress, epType, epDir, + connection->deviceName, sizeof ( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Isochron: + connection->bufferSize = bufferSize; + device->ConfigureUsbEndpoint( aimType, endPointAddress, epType, epDir, + connection->deviceName, sizeof ( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Unknown: + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateUsbSocketV2, Channel configuration is invalid, because data type is unknown"RESETCOLOR"\n" ); + break; + default: + connection->bufferSize = bufferSize; + device->ConfigureUsbEndpoint( endPointAddress, epType, epDir, + connection->deviceName, sizeof ( connection->deviceName ), amountOfBuffers, bufferSize ); + break; + } + } + RaiseAvailable( connection ); + } + PRINT_ALL_INFOS(); + } +} + +void CNetwork::OnCreateMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateMlbSocketV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateMlbSocketV2, inst:%d, addr:0x%X, type:%d, dir:%d, mlbAddr:%d, handle:0x%X, tag:0x%X\n", + devInstance, nodeAddr, epType, epDir, mlbChannelAddress, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + AimType_t aimType = AIM_UNKNOWN; + uint32_t amountOfBuffers = 0xFFFFFFFF; + uint32_t bufferSize = 0xFFFFFFFF; + uint32_t subbufferSize = 0xFFFFFFFF; + uint32_t packetsPerTransaction = 0xFFFFFFFF; + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + amountOfBuffers = connection->channelConfig->inSocket.amountOfBuffers; + bufferSize = connection->channelConfig->inSocket.bufferSize; + subbufferSize = connection->channelConfig->inSocket.subbufferSize; + packetsPerTransaction = + connection->channelConfig->inSocket.packetsPerTransaction; + aimType = connection->channelConfig->inSocket.aimType; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + amountOfBuffers = connection->channelConfig->outSocket.amountOfBuffers; + bufferSize = connection->channelConfig->outSocket.bufferSize; + subbufferSize = connection->channelConfig->outSocket.subbufferSize; + packetsPerTransaction = + connection->channelConfig->outSocket.packetsPerTransaction; + aimType = connection->channelConfig->outSocket.aimType; + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateMlbSocketV2, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + if( 0x1 == entry->nodeAddress ) + { + connection->bufferSize = bufferSize; + switch( epType ) + { + case EP_Synchron: + case EP_Isochron: + device->ConfigureMlbChannel( aimType, mlbChannelAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Unknown: + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateMlbSocketV2, Channel configuration is invalid, because data type is unknown"RESETCOLOR"\n" ); + break; + default: + device->ConfigureMlbChannel( mlbChannelAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize ); + break; + } + } + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateSplittedMlbSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockWidthMlb, uint8_t mlbChannelAddress, uint16_t mlbSocketHandle, + uint16_t splitterHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateSplittedMlbSocketV3 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateSplittedMlbSocketV3, inst:%d, addr:0x%X, type:%d, dir:%d, mlbAddr:%d, mlb-handle:0x%X, Splitter-handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, epType, epDir, mlbChannelAddress, mlbSocketHandle, splitterHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + AimType_t aimType = AIM_UNKNOWN; + uint32_t amountOfBuffers = 0xFFFFFFFF; + uint32_t bufferSize = 0xFFFFFFFF; + uint32_t subbufferSize = 0xFFFFFFFF; + uint32_t packetsPerTransaction = 0xFFFFFFFF; + bool valSet = false; + for( uint16_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *checkConn = entry->GetConnectionByIndex( j ); + if( EPDIR_IN == epDir ) + { + if( connection->channelConfig->inSocket.address != checkConn->channelConfig->inSocket.address ) + continue; + checkConn->inSocketState = NodeConnection_Used; + checkConn->inHandle = splitterHandle; + checkConn->splittedSourceHandle = mlbSocketHandle; + if( !valSet ) + { + valSet = true; + amountOfBuffers = checkConn->channelConfig->inSocket.amountOfBuffers; + bufferSize = checkConn->channelConfig->inSocket.bufferSize; + subbufferSize = checkConn->channelConfig->inSocket.subbufferSize; + packetsPerTransaction = + checkConn->channelConfig->inSocket.packetsPerTransaction; + aimType = connection->channelConfig->inSocket.aimType; + } + TryToConnectSockets( devInstance, nodeAddr, checkConn->channelId ); + } + else if( EPDIR_OUT == epDir ) + { + if( connection->channelConfig->outSocket.address != checkConn->channelConfig->outSocket.address ) + continue; + checkConn->outSocketState = NodeConnection_Used; + checkConn->outHandle = splitterHandle; + checkConn->splittedSourceHandle = mlbSocketHandle; + if( !valSet ) + { + valSet = true; + amountOfBuffers = checkConn->channelConfig->outSocket.amountOfBuffers; + bufferSize = checkConn->channelConfig->outSocket.bufferSize; + subbufferSize = checkConn->channelConfig->outSocket.subbufferSize; + packetsPerTransaction = + checkConn->channelConfig->outSocket.packetsPerTransaction; + aimType = connection->channelConfig->outSocket.aimType; + } + TryToConnectSockets( devInstance, nodeAddr, checkConn->channelId ); + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateSplittedMlbSocketV3, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + return; + } + } + if( 0x1 == entry->nodeAddress ) + { + connection->bufferSize = bufferSize; + switch( epType ) + { + case EP_Synchron: + case EP_Isochron: + device->ConfigureMlbChannel( aimType, mlbChannelAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize, + subbufferSize, packetsPerTransaction ); + break; + case EP_Unknown: + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateMlbSocketV2, Channel configuration is invalid, because data type is unknown"RESETCOLOR"\n" ); + break; + default: + device->ConfigureMlbChannel( mlbChannelAddress, epType, epDir, + connection->deviceName, sizeof( connection->deviceName ), amountOfBuffers, bufferSize ); + break; + } + } + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateI2SSocket reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateI2SSocket, inst:%d, addr:0x%X, port:%d, dir:%d, blockwidth:%d, pin:%d, handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, portInstance, epDir, blockWidthI2S, pin, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateI2SSocket, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateSplittedI2SSocketV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + EPDirection_t epDir, uint16_t blockWidthI2S, V3I2SPin_t pin, uint16_t i2sSocketHandle, uint16_t splitterHandle, + uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateSplittedI2SSocketV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateI2SSocket, inst:%d, addr:0x%X, port:%d, dir:%d, blockwidth:%d, pin:%d, i2s-handle:0x%X, Splitter-handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, portInstance, epDir, blockWidthI2S, pin, i2sSocketHandle, splitterHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + if( EPDIR_IN == epDir ) + { + //Find all related pin configurations, this is the use case of splitted I2S sockets + V3I2SPin_t pin = connection->channelConfig->inSocket.i2sConfig.pin; + uint16_t all = entry->GetAmountOfConnections(); + for (uint16_t i = 0; i < all; i++) + { + CNodeConnectionEntry *con = entry->GetConnectionByIndex(i); + if (pin == con->channelConfig->inSocket.i2sConfig.pin) + { + con->inSocketState = NodeConnection_Used; + con->inHandle = splitterHandle; + con->splittedSourceHandle = i2sSocketHandle; + TryToConnectSockets( devInstance, nodeAddr, con->channelId ); + } + } + } + else if( EPDIR_OUT == epDir ) + { + //Find all related pin configurations, this is the use case of splitted I2S sockets + V3I2SPin_t pin = connection->channelConfig->outSocket.i2sConfig.pin; + uint16_t all = entry->GetAmountOfConnections(); + for (uint16_t i = 0; i < all; i++) + { + CNodeConnectionEntry *con = entry->GetConnectionByIndex(i); + if (pin == con->channelConfig->outSocket.i2sConfig.pin) + { + con->outSocketState = NodeConnection_Used; + con->outHandle = splitterHandle; + con->splittedSourceHandle = i2sSocketHandle; + TryToConnectSockets( devInstance, nodeAddr, con->channelId ); + } + } + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"Network::OnCreateI2SSocket, Channel configuration is invalid, because direction of stream is unknown"RESETCOLOR"\n" ); + } + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnCreateMostSocketV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + EPDirection_t epDir, uint16_t blockwidthMost, uint16_t connectionLabel, uint16_t socketHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateMostSocketV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnCreateMostSocketV2, inst:%d, addr:0x%X, type:%d, dir:%d, bwMost:%d, conLabel:0x%X, handle:0x%X, tag:0x%X\n", devInstance, nodeAddr, epType, epDir, blockwidthMost, connectionLabel, socketHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + connection->mostConnectionLabel = connectionLabel; + if( EPDIR_IN == epDir ) + { + connection->inSocketState = NodeConnection_Used; + connection->inHandle = socketHandle; + } + else if( EPDIR_OUT == epDir ) + { + connection->outSocketState = NodeConnection_Used; + connection->outHandle = socketHandle; + } + TryToConnectSockets( devInstance, nodeAddr, tag ); + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnConnectSocketsV3( void *source, bool success, uint16_t nodeAddr, EPDataType_t epType, + uint16_t inSocketHandle, uint16_t outSocketHandle, uint16_t connectionHandle, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnConnectSocketsV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } + ConsolePrintf( PRIO_MEDIUM, + "Network::OnConnectSocketsV2, inst:%d, addr:0x%X, Type0x%X, inHandle:0x%X, outHandle:0x%X, conHandle:0x%X, tag:0x%X\n", devInstance, nodeAddr, epType, inSocketHandle, outSocketHandle, connectionHandle, tag ); + + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( tag, true ); + if( NULL != connection ) + { + connection->connectedSocketState = NodeConnection_Used; + connection->connectHandle = connectionHandle; + RaiseAvailable( connection ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::OnControlChannelReadEnd( void *source ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + connectionBitMask = connectionBitMask & ~( 1 << devInstance ); + ConsolePrintf( PRIO_ERROR, RED"Destroying NetworkDevice with instance %d, because the reader thread has ended"RESETCOLOR"\n", + devInstance ); + + allNetworkDevices.Remove(device); + delete device; +} + +void CNetwork::OnMostControlMessage( void *source, uint32_t sourceAddr, uint32_t targetAddr, uint32_t nFBlock, + uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen, const uint8_t *Payload ) +{ + if( NULL == source ) + return; + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + for( uint32_t i = 0; i < allListeners.Size(); i++ ) + { + allListeners[i]->OnMostControlMessage( devInstance, sourceAddr, targetAddr, nFBlock, nInst, nFunc, nOpType, + nPayloadLen, Payload ); + } +} + +void CNetwork::OnRbdResultV3( void *source, uint16_t nodeAddress, uint8_t result, uint8_t position, + uint8_t status, uint16_t id ) +{ + CNetworkDeviceListener::OnRbdResultV3( source, nodeAddress, result, position, status, id ); + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + for( uint32_t i = 0; i < allListeners.Size(); i++ ) + { + allListeners[i]->OnRingBreakDiagnosisResultV3( devInstance, nodeAddress, result, position, status, id ); + } +} + +void CNetwork::OnMostMacAddress( void *source, bool success, uint16_t nodeAddress, uint8_t macAddress1, + uint8_t macAddress2, uint8_t macAddress3, uint8_t macAddress4, uint8_t macAddress5, uint8_t macAddress6 ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnMostMacAddress reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddress ); + ShutdownMostBecauseOfErrors( device ); + return; + } +} + +void CNetwork::OnConfigureI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortOption_t option, V3I2SClockMode_t mode, V3I2SDelayMode_t delay, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnConfigureI2SPortV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + ShutdownMostBecauseOfErrors( device ); + return; + } +} + +void CNetwork::OnCreateI2SPortV3( void *source, bool success, uint16_t nodeAddr, uint8_t portInstance, + V3I2SPortSpeed_t clock, V3I2SAlignment_t align, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnCreateI2SPortV2 reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, nodeAddr ); + return; + } +} + +void CNetwork::OnDeviceVersion( void *source, bool success, uint32_t sourceAddr, + uint32_t productId, uint32_t fwVersion, uint32_t buildVersion, + uint8_t hwVersion, uint16_t diagnosisId, uint32_t tag ) +{ + if( NULL == source ) + return; + + CNetworkDevice *device = ( ( CNetworkDevice * )source ); + uint32_t devInstance = device->GetDeviceIndex(); + if( !success ) + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::OnDeviceVersion reports failure for device:%d, nodeAddress:0x%X"RESETCOLOR"\n", + devInstance, sourceAddr ); + return; + } + ConsolePrintf( PRIO_MEDIUM, "Got Device version for nodeAddress:0x%X, productId:0x%X, fwVersion:0x%X, "\ + "buildVersion:0x%X, hwVersion:%d, diagnosisId:0x%X\n", sourceAddr, productId, fwVersion, + buildVersion, hwVersion, diagnosisId); + if( 0x81118 == productId ) + { + uint8_t exMajor = 2; + uint8_t exMinor = 4; + uint8_t exRelease = 0; + uint32_t expectedFW = exMajor << 24 | exMinor << 16 | exRelease << 8; + if (fwVersion < expectedFW) + { + ConsolePrintf( PRIO_ERROR, RED"Warning, the device with node address:0x%X uses"\ + " too old firmware! Please update to: V%d.%d.%d"RESETCOLOR"\n", + sourceAddr, exMajor, exMinor, exRelease); + } + } +}
\ No newline at end of file diff --git a/Src/Network/Network_Private.cpp b/Src/Network/Network_Private.cpp new file mode 100644 index 0000000..2aaef6e --- /dev/null +++ b/Src/Network/Network_Private.cpp @@ -0,0 +1,695 @@ +/* + * 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. + * + */ + +#include <stdint.h> +#include <stddef.h> +#include "SafeVector.h" +#include "Network.h" +#include "NetworkDevice.h" +#include "DriverConfiguration.h" +#include "MacAddr.h" +#include "Board.h" +#include "Console.h" +#include "NodeDatabase.h" + +#define PRINT_ALL_INFOS() +#define MAX_MOST_DEVICES 4 + +void CNetwork::DestroyAllResources( CNetworkDevice *device, uint16_t nodeAddress ) +{ + if( NULL == device ) + return; + + CNodeEntry *node = CNodeEntry::GetNodeEntry( device->GetDeviceIndex(), nodeAddress ); + if( NULL == node ) + return; + + sem_wait( &vodXmlMutex ); + uint32_t apiVer = vodXml->GetDeviceApi( node->deviceType ); + sem_post( &vodXmlMutex ); + if( 1 == apiVer ) + { + for( int i = 0; i < node->GetAmountOfConnections(); i++ ) + { + CNodeConnectionEntry *connection = node->GetConnectionByIndex( i ); + if( NULL == connection || NULL == connection->channelConfig ) + continue; + + uint32_t inHandle = connection->inHandle; + uint32_t outHandle = connection->outHandle; + uint32_t conHandle = connection->connectHandle; + NodeConnectionState_t inState = connection->inSocketState; + NodeConnectionState_t outState = connection->outSocketState; + NodeConnectionState_t conState = connection->connectedSocketState; + uint32_t channelId = connection->channelConfig->channelId; + connection->deviceName[0] = '\0'; + connection->mostConnectionLabel = 0xFFFFFFFF; + connection->inHandle = 0xFFFFFFFF; + connection->outHandle = 0xFFFFFFFF; + connection->connectHandle = 0xFFFFFFFF; + connection->inSocketState = NodeConnection_NotUsed; + connection->outSocketState = NodeConnection_NotUsed; + connection->connectedSocketState = NodeConnection_NotUsed; + if( NodeConnection_NotUsed != conState && 0xFFFFFFFF != conHandle ) + { + device->DisconnectSocketsV1( nodeAddress, conHandle, channelId ); + } + if( NodeConnection_NotUsed != inState && 0xFFFFFFFF != inHandle ) + { + device->DestroySocketV1( nodeAddress, inHandle, channelId ); + } + if( NodeConnection_NotUsed != outState && 0xFFFFFFFF != outHandle ) + { + device->DestroySocketV1( nodeAddress, outHandle, channelId ); + } + RaiseUnavailable( connection ); + } + } + else if( 2 == apiVer || 3 == apiVer ) + { + uint8_t amount; +#define MAX_DESTROY_ELEMENTS 10 + uint16_t handles[MAX_DESTROY_ELEMENTS]; + + //Start to destroy the connections first: + do + { + amount = 0; + for( int i = 0; amount < MAX_DESTROY_ELEMENTS && i < node->GetAmountOfConnections(); i++ ) + { + CNodeConnectionEntry *connection = node->GetConnectionByIndex( i ); + if( NULL == connection || NULL == connection->channelConfig ) + continue; + if( NodeConnection_NotUsed != connection->connectedSocketState ) + { + handles[amount++] = connection->connectHandle; + connection->connectHandle = 0xFFFFFFFF; + connection->connectedSocketState = NodeConnection_NotUsed; + } + } + if( amount != 0 ) + { + device->ResourceDestroyV3( nodeAddress, amount, handles, 0 ); + } + } + while( amount != 0 ); + + do + { + amount = 0; + //Continue to destroy the In and Out sockets: + for( int i = 0; amount < MAX_DESTROY_ELEMENTS && i < node->GetAmountOfConnections(); i++ ) + { + CNodeConnectionEntry *connection = node->GetConnectionByIndex( i ); + if( NULL == connection || NULL == connection->channelConfig ) + continue; + if( ( NodeConnection_NotUsed != connection->inSocketState ) + && ( 0xFFFFFFFF != connection->inHandle ) ) + { + handles[amount++] = connection->inHandle; + for( int j = 0; j < node->GetAmountOfConnections(); j++ ) + { + if( i == j ) + continue; + CNodeConnectionEntry *otherConn = node->GetConnectionByIndex( j ); + if( ( otherConn != NULL ) && ( otherConn->inHandle == connection->inHandle ) ) + { + otherConn->inHandle = 0xFFFFFFFF; + otherConn->inSocketState = NodeConnection_NotUsed; + } + } + connection->inHandle = 0xFFFFFFFF; + connection->inSocketState = NodeConnection_NotUsed; + } + if( amount < MAX_DESTROY_ELEMENTS && + ( NodeConnection_NotUsed != connection->outSocketState ) + && ( 0xFFFFFFFF != connection->outHandle ) ) + { + handles[amount++] = connection->outHandle; + for( int j = 0; j < node->GetAmountOfConnections(); j++ ) + { + if( i == j ) + continue; + CNodeConnectionEntry *otherConn = node->GetConnectionByIndex( j ); + if( ( otherConn != NULL ) && ( otherConn->outHandle == connection->outHandle ) ) + { + otherConn->outHandle = 0xFFFFFFFF; + otherConn->outSocketState = NodeConnection_NotUsed; + } + } + connection->outHandle = 0xFFFFFFFF; + connection->outSocketState = NodeConnection_NotUsed; + RaiseUnavailable( connection ); + } + + } + if( amount != 0 ) + { + device->ResourceDestroyV3( nodeAddress, amount, handles, 0 ); + } + } + while( amount != 0 ); + + //Last step destroy Splitter / Combiner input / output + do + { + amount = 0; + for( int i = 0; i < node->GetAmountOfConnections(); i++ ) + { + CNodeConnectionEntry *connection = node->GetConnectionByIndex( i ); + if( NULL == connection || NULL == connection->channelConfig ) + continue; + if( 0xFFFFFFFF != connection->splittedSourceHandle ) + { + handles[amount++] = connection->splittedSourceHandle; + for( int j = 0; j < node->GetAmountOfConnections(); j++ ) + { + if( i == j ) + continue; + CNodeConnectionEntry *otherConn = node->GetConnectionByIndex( j ); + if( ( otherConn != NULL ) && ( otherConn->splittedSourceHandle == connection-> + splittedSourceHandle ) ) + { + otherConn->splittedSourceHandle = 0xFFFFFFFF; + } + } + connection->splittedSourceHandle = 0xFFFFFFFF; + } + } + if( amount != 0 ) + { + device->ResourceDestroyV3( nodeAddress, amount, handles, 0 ); + } + } + while( amount != 0 ); + } +} + +void CNetwork::DestroyAllResources() +{ + CNetworkDevice *device; + uint16_t nodeAmount = CNodeEntry::GetAmountOfNodeEntries(); + for( int i = 0; i < nodeAmount; i++ ) + { + CNodeEntry *node = CNodeEntry::GetNodeEntry( i ); + if( NULL == node ) + continue; + CNetworkDevice *device = GetNetworkDevice( node->deviceInstance ); + uint16_t nodeAddress = node->nodeAddress; + DestroyAllResources( device, nodeAddress ); + } + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + device = allNetworkDevices[i]; + if( NULL != device ) + { + sem_wait( &vodXmlMutex ); + if( NULL != vodXml ) + { + sem_post( &vodXmlMutex ); + if( device->IsTimingMaster() ) + { + ConsolePrintf( PRIO_MEDIUM, "DestroyAllResources, Performing MOST Shutdown index: %d\n", + device->GetDeviceIndex() ); + device->ToggleNotOk(); + device->SetNetstate( NetworkState_ShutdownInProgress ); + device->MostNetworkShutdownV3(); + } + } + else + sem_post( &vodXmlMutex ); + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::CloseAllNetworkDevices() +{ + DestroyAllResources(); + CNetworkDevice *device; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + device = allNetworkDevices[i]; + if( NULL != device ) + { + ConsolePrintf( PRIO_MEDIUM, "CloseAllNetworkDevices, Closing device index: %d\n", + device->GetDeviceIndex() ); + device->Close(); + } + } + allNetworkDevices.RemoveAll(true); + connectionBitMask = 0; +} + +void CNetwork::FindNewNetworkDevices() +{ + sem_wait( &vodXmlMutex ); + if( NULL == vodXml ) + { + sem_post( &vodXmlMutex ); + return; + } + bool success = false; + bool infoQueried = false; + uint8_t *controlRxAddress = NULL; + uint8_t *controlTxAddress = NULL; + uint32_t *apiVersion = NULL; + SocketPort_t *hwPort = NULL; + bool *isTimingMaster = NULL; + uint32_t *asyncBW = NULL; + uint8_t serverNum = 0; + for( uint8_t devInstance = 0; devInstance < MAX_MOST_DEVICES; devInstance++ ) + { + if( 0 != ( connectionBitMask & ( 1 << devInstance ) ) ) + continue; + + if( !infoQueried ) + infoQueried = vodXml->GetLocalInicConfigurations( &controlRxAddress, &controlTxAddress, &apiVersion, + &hwPort, &isTimingMaster, &asyncBW, &serverNum ); + + if( !infoQueried ) + { + ConsolePrintf( PRIO_ERROR, RED"Can not parse XML file to configure server device"RESETCOLOR"\n" ); + sem_post( &vodXmlMutex ); + return; + } + for( uint8_t conIndex = 0; conIndex < serverNum; conIndex++ ) + { + if( ( ( PORT_MLB == hwPort[conIndex] ) && ExistsMlbDeviceInstance( devInstance ) ) + || ( ( PORT_USB == hwPort[conIndex] ) && ExistsUsbDeviceInstance( devInstance ) ) ) + { + connectionBitMask += ( 1 << devInstance ); + ConsolePrintf( PRIO_MEDIUM, "=======Server %d device uses %s, INIC API V%d=======\n", + devInstance, ( PORT_USB == hwPort[conIndex] ? "USB" : PORT_MLB == hwPort[conIndex] ? "MLB" : + "UNKNOWN" ), apiVersion[conIndex] ); + ConsolePrintf( PRIO_MEDIUM, "Opening device instance %d\n", devInstance ); + CNetworkDevice *newDevice = new CNetworkDevice( devInstance, + apiVersion[conIndex], isTimingMaster[conIndex], asyncBW[conIndex], promiscuous ); + switch( hwPort[conIndex] ) + { + case PORT_USB: + success = newDevice->OpenUsb( controlRxAddress[conIndex], controlTxAddress[conIndex] ); + break; + case PORT_MLB: + success = newDevice->OpenMlb( controlRxAddress[conIndex], controlTxAddress[conIndex] ); + break; + default: + success = false; + break; + } + if( success ) + { + allNetworkDevices.PushBack( newDevice ); + newDevice->AddListener( this ); + } + else + { + if( ( PORT_USB == hwPort[conIndex] ) && ( apiVersion[conIndex] < 3 ) ) + ConsolePrintf( PRIO_ERROR, RED"Failed to open device instance %d"\ + RESETCOLOR"\n", devInstance ); + delete newDevice; + } + } + } + } + if( NULL != controlRxAddress ) + free( controlRxAddress ); + if( NULL != controlTxAddress ) + free( controlTxAddress ); + if( NULL != apiVersion ) + free( apiVersion ); + if( NULL != hwPort ) + free( hwPort ); + sem_post( &vodXmlMutex ); +} + +void CNetwork::TryToCreateRoute( uint32_t devInstance, bool mostIsTx, void *e, void *t ) +{ + if( NULL == e || NULL == t ) + return; + CNodeEntry *entry = ( CNodeEntry * )e; + CRouteTerminal *terminal = ( CRouteTerminal * )t; + CSafeVector<CRouteTerminal *> connectedTerminals; + + sem_wait( &vodXmlMutex ); + bool found = vodXml->GetRouteTerminals( terminal, connectedTerminals ); + sem_post( &vodXmlMutex ); + if( !found ) + return; + CNodeEntry *oppositeEntry = NULL; + for( uint32_t i = 0; i < connectedTerminals.Size(); i++ ) + { + if( NULL != ( oppositeEntry = CNodeEntry::GetNodeEntry( devInstance, connectedTerminals[i]->deviceType, + connectedTerminals[i]->instance ) ) ) + { + if( mostIsTx ) + ConnectSourceToSink( entry, oppositeEntry, terminal->channelId, connectedTerminals[i]->channelId ); + else + ConnectSourceToSink( oppositeEntry, entry, connectedTerminals[i]->channelId, terminal->channelId ); + } + delete connectedTerminals[i]; + } +} + +void CNetwork::TryToConnectSockets( uint32_t devInstance, uint16_t nodeAddr, uint32_t channelId ) +{ + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddr ); + if( NULL != entry ) + { + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( channelId, true ); + CNetworkDevice *device = GetNetworkDevice( devInstance ); + CChannelConfiguration *config = connection->channelConfig; + sem_wait( &vodXmlMutex ); + uint32_t deviceApi = vodXml->GetDeviceApi( connection->channelConfig->deviceType ); + sem_post( &vodXmlMutex ); + if( ( NULL != connection ) && ( NULL != device ) && ( NULL != config ) ) + { + CRouteTerminal terminal; + terminal.channelId = channelId; + terminal.deviceType = entry->deviceType; + terminal.instance = CNodeEntry::GetTerminalInstance( devInstance, nodeAddr, entry->deviceType ); + + if( ( NodeConnection_Used == connection->inSocketState ) + && ( NodeConnection_Used == connection->outSocketState ) + && ( NodeConnection_NotUsed == connection->connectedSocketState ) ) + { + if( deviceApi > 3 ) + { + ConsolePrintf( + PRIO_ERROR, RED"TryToConnectSockets found unknown device API version: %d"RESETCOLOR"\n", + deviceApi ); + return; + } + connection->connectedSocketState = NodeConnection_Pending_Up; + if( 1 == deviceApi ) + { + device->ConnectSocketsV1( nodeAddr, connection->inHandle, connection->outHandle, channelId ); + } + else if( ( 2 == deviceApi ) || ( 3 == deviceApi ) ) + { + uint32_t offset = config->inSocket.splittedOffset; + if( 0xFFFFFFFF == offset ) + { + offset = config->outSocket.splittedOffset; + if( 0xFFFFFFFF == offset ) + offset = 0; + } + device->ConnectSocketsV3( nodeAddr, config->outSocket.type, connection->inHandle, + connection->outHandle, offset, channelId ); + } + TryToCreateRoute( devInstance, true, entry, &terminal ); + } + else if( ( NodeConnection_NotUsed == connection->inSocketState ) + && ( NodeConnection_Used == connection->outSocketState ) + && ( PORT_MOST == config->inSocket.port ) ) + { + TryToCreateRoute( devInstance, false, entry, &terminal ); + } + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::TryToCloseExistingMostConnection( void *inNode, uint32_t inChannelId, void *outNode, + uint32_t outChannelId ) +{ + if( ( NULL == inNode ) || ( NULL == outNode ) ) + return; + + for( uint8_t i = 0; i < 2; i++ ) + { + CNodeConnectionEntry *closeEntry = NULL; + switch( i ) + { + case 0: + closeEntry = ( ( CNodeEntry * )outNode )->GetConnectionByChannelId( outChannelId, false ); + break; + case 1: + closeEntry = ( ( CNodeEntry * )inNode )->GetConflictingConnection( inChannelId, + ( ( CNodeEntry * )outNode ) ); + break; + } + if( NULL == closeEntry || NULL == closeEntry->channelConfig + || NULL == closeEntry->parentNode ) + continue; + + if( ( NodeConnection_Used == closeEntry->inSocketState ) && + ( NodeConnection_Used == closeEntry->connectedSocketState ) && + ( PORT_MOST == closeEntry->channelConfig->inSocket.port ) ) + { + uint8_t oppInst = closeEntry->parentNode->deviceInstance; + CNetworkDevice *oppDevice = GetNetworkDevice( oppInst ); + if( NULL != oppDevice ) + { + uint16_t oppNodeAddress = closeEntry->parentNode->nodeAddress; + uint32_t oppApiVer = closeEntry->parentNode->deviceType; + uint32_t oppConHandle = closeEntry->connectHandle; + uint32_t oppInHandle = closeEntry->inHandle; + uint32_t oppChannelId = closeEntry->channelId; + + closeEntry->connectedSocketState = NodeConnection_Pending_Down; + closeEntry->inSocketState = NodeConnection_Pending_Down; + + if( 1 == oppApiVer ) + { + oppDevice->DisconnectSocketsV1( oppNodeAddress, oppConHandle, oppChannelId ); + oppDevice->DestroySocketV1( oppNodeAddress, oppInHandle, oppChannelId ); + } + else if( 2 == oppApiVer || 3 == oppApiVer ) + { + uint16_t a[2]; + a[0] = oppConHandle; + a[1] = oppInHandle; + oppDevice->ResourceDestroyV3( oppNodeAddress, 2, a, oppChannelId ); + } + } + } + } + PRINT_ALL_INFOS(); +} + +void CNetwork::RaiseAvailable( void *con ) +{ + CNodeConnectionEntry *connection = ( CNodeConnectionEntry * )con; + if( ( NULL != connection ) + && ( NULL != connection->parentNode ) + && ( NULL != connection->channelConfig ) + ) + { + uint32_t blockWidth = connection->channelConfig->outSocket.blockWidth; + if( 0xFFFFFFFF == blockWidth ) + blockWidth = connection->channelConfig->inSocket.blockWidth; + + uint16_t xact = 0; + if ( PORT_USB == connection->channelConfig->inSocket.port ) + xact = connection->channelConfig->inSocket.packetsPerTransaction; + else if ( PORT_USB == connection->channelConfig->outSocket.port ) + xact = connection->channelConfig->outSocket.packetsPerTransaction; + + uint32_t devInst = CNodeEntry::GetTerminalInstance( connection->parentNode->deviceInstance, + connection->parentNode->nodeAddress, connection->parentNode->deviceType ); + for( uint32_t i = 0; i < allListeners.Size(); i++ ) + { + int offset = -1; + int maxBW = -1; + if( 0xFFFFFFFF != connection->channelConfig->inSocket.splittedOffset ) + { + offset = connection->channelConfig->inSocket.splittedOffset; + maxBW = connection->channelConfig->inSocket.subbufferSize; + } + else if( 0xFFFFFFFF != connection->channelConfig->outSocket.splittedOffset ) + { + offset = connection->channelConfig->outSocket.splittedOffset; + maxBW = connection->channelConfig->outSocket.subbufferSize; + } + allListeners[i]->OnChannelAvailable( connection->parentNode->macAddress, + connection->parentNode->deviceType, devInst, connection->channelId, + connection->parentNode->deviceInstance, connection->channelConfig->outSocket.type, + blockWidth, ( PORT_MOST == connection->channelConfig->outSocket.port ), ( NodeConnection_Used == + connection->inSocketState ), ( NodeConnection_Used == connection->outSocketState ), + ( NodeConnection_Used == connection->connectedSocketState ), connection->bufferSize, + connection->mostConnectionLabel, offset, maxBW, xact, connection->deviceName ); + } + } +} + +void CNetwork::RaiseUnavailable( void *con ) +{ + CNodeConnectionEntry *connection = ( CNodeConnectionEntry * )con; + if( ( NULL != connection ) + && ( NULL != connection->parentNode ) + && ( NULL != connection->channelConfig ) + && ( NULL != connection->parentNode->macAddress ) + ) + { + for( uint32_t i = 0; i < allListeners.Size(); i++ ) + { + allListeners[i]->OnChannelUnavailable( connection->parentNode->macAddress, connection->channelId, + connection->parentNode->deviceInstance ); + } + } +} + +CNetworkDevice *CNetwork::GetNetworkDevice( uint32_t devInstance ) +{ + CNetworkDevice *device = NULL; + for( uint32_t i = 0; i < allNetworkDevices.Size(); i++ ) + { + if( devInstance == allNetworkDevices[i]->GetDeviceIndex() ) + { + device = allNetworkDevices[i]; + break; + } + } + return device; +} + +CMacAddr *CNetwork::SetMacAddress( CNetworkDevice *device, uint32_t devInstance, uint16_t nodeAddress, + uint8_t inicApiVersion ) +{ + if( NULL == device ) + return NULL; + CMacAddr *mac = new CMacAddr( devInstance, nodeAddress ); + if( NULL == mac ) + { + ConsolePrintf( PRIO_ERROR, RED"Failed to instance CMacAddr object"RESETCOLOR"\n" ); + return NULL; + } + ConsolePrintf( PRIO_MEDIUM, + "Creating local MAC for deviceInstance:%d: nodeAddress:0x%X, MAC-Address:%02X-%02X-%02X-%02X-%02X-%02X)\n", + devInstance, nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4], ( *mac )[5] ); + + switch( inicApiVersion ) + { + case 1: + device->SetMostMacAddressV1( nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4], + ( *mac )[5], false ); + break; + case 2: + device->SetMostMacAddressV3( nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4], + ( *mac )[5] ); + break; + case 3: + device->SetMostMacAddressV3( nodeAddress, ( *mac )[0], ( *mac )[1], ( *mac )[2], ( *mac )[3], ( *mac )[4], + ( *mac )[5] ); + break; + default: + ConsolePrintf( + PRIO_ERROR, RED"Can not set local MAC, because device API version (%d) is unknown"RESETCOLOR"\n", + inicApiVersion ); + delete mac; + mac = NULL; + break; + } + return mac; +} + +bool CNetwork::ConnectSourceToSink( void *mostTxNode, void *mostRxNode, uint32_t sourceChannelId, + uint32_t sinkChannelId ) +{ + bool success = false; + PRINT_ALL_INFOS(); + if( ( NULL != mostTxNode ) && ( NULL != mostRxNode ) ) + { + CNodeEntry *txNode = ( CNodeEntry * )mostTxNode; + CNodeEntry *rxNode = ( CNodeEntry * )mostRxNode; + CNodeConnectionEntry *inConnection = txNode->GetConnectionByChannelId( sourceChannelId, false ); + CNodeConnectionEntry *outConnection = rxNode->GetConnectionByChannelId( sinkChannelId, false ); + CNetworkDevice *outDevice = GetNetworkDevice( rxNode->deviceInstance ); + if( ( NULL != inConnection ) && ( NULL != outConnection ) && ( NULL != outDevice ) + && ( NULL != outConnection->channelConfig ) && ( 0xFFFFFFFF != inConnection->mostConnectionLabel ) ) + { + if( ( NodeConnection_Used == inConnection->outSocketState ) + && ( NodeConnection_NotUsed == outConnection->inSocketState ) ) + { + uint32_t connectionLabel = inConnection->mostConnectionLabel; + sem_wait( &vodXmlMutex ); + uint32_t inApiVer = vodXml->GetDeviceApi( txNode->deviceType ); + uint32_t outApiVer = vodXml->GetDeviceApi( rxNode->deviceType ); + sem_post( &vodXmlMutex ); + ConsolePrintf( PRIO_MEDIUM, + BLUE"CNetwork::ConnectSourceToSink Connection Label:0x%X, IN-API-Ver:%d, OUT-API-Ver:%d, devIndex:%d, address:0x%X"RESETCOLOR"\n", + connectionLabel, inApiVer, outApiVer, rxNode->deviceInstance, + rxNode->nodeAddress ); + TryToCloseExistingMostConnection( txNode, sourceChannelId, rxNode, sinkChannelId ); + if( 1 == outApiVer ) + { + outDevice->CreateMostSocketV1( rxNode->nodeAddress, outConnection->channelConfig->inSocket.type, + EPDIR_IN, connectionLabel, outConnection->channelConfig->inSocket.blockWidth, sinkChannelId ); + success = true; + } + else if( 2 == outApiVer || 3 == outApiVer ) + { + outDevice->CreateMostSocketV3( rxNode->nodeAddress, outConnection->channelConfig->inSocket.type, + EPDIR_IN, connectionLabel, outConnection->channelConfig->inSocket.blockWidth, sinkChannelId ); + success = true; + } + if( success ) + { + outConnection->inSocketState = NodeConnection_Pending_Up; + outConnection->mostConnectionLabel = connectionLabel; + } + } + } + } + else + { + ConsolePrintf( + PRIO_ERROR, RED"CNetwork::SetSinkToChannel failed to resolve given MAC addresses"RESETCOLOR"\n" ); + } + PRINT_ALL_INFOS(); + return success; +} + +void CNetwork::RaiseUknownConnection( uint32_t devInstance, uint16_t nodeAddress, EPDataType_t dType ) +{ + CNodeEntry *entry = CNodeEntry::GetNodeEntry( devInstance, nodeAddress ); + CNodeConnectionEntry *connection = entry->GetConnectionByChannelId( 0xFF, true ); + entry->macAddress = new CMacAddr( devInstance, nodeAddress ); + connection->channelConfig = new CChannelConfiguration(); + connection->channelConfig->inSocket.type = dType; + connection->channelConfig->outSocket.type = dType; + RaiseAvailable( connection ); +} + +void CNetwork::ShutdownMost( CNetworkDevice *device ) +{ + if( NULL == device ) + return; + device->ClearAllPendingActions(); + device->SetNetstate( NetworkState_ShutdownInProgress ); + device->MostNetworkShutdownV3(); +} + +void CNetwork::ShutdownMostBecauseOfErrors( CNetworkDevice *device ) +{ + if (retryCounter < 5) + { + retryExecTime = GetTickCount(); + retryCounter++; + ConsolePrintf( + PRIO_ERROR, RED"Restart MOST because of resources allocation /"\ + " configuration problems, retry count=%d"RESETCOLOR"\n", retryCounter ); + ShutdownMost( device ); + } +}
\ No newline at end of file diff --git a/Src/Network/NodeDatabase.cpp b/Src/Network/NodeDatabase.cpp new file mode 100644 index 0000000..d53d2d1 --- /dev/null +++ b/Src/Network/NodeDatabase.cpp @@ -0,0 +1,287 @@ +/* + * 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. + * + */ + +#include <stdio.h> +#include <stddef.h> +#include "Console.h" +#include "NodeDatabase.h" + +CSafeVector<CNodeEntry *> CNodeEntry::allNodes; + +CNodeConnectionEntry::CNodeConnectionEntry( CNodeEntry *parent ) : parentNode( parent ), channelConfig( NULL ), + channelId( 0xFFFFFFFF ), inHandle( 0xFFFFFFFF ), + outHandle( 0xFFFFFFFF ), + connectHandle( 0xFFFFFFFF ), + splittedSourceHandle( 0xFFFFFFFF ), + mostConnectionLabel( 0xFFFFFFFF ), + inSocketState( NodeConnection_NotUsed ), + outSocketState( NodeConnection_NotUsed ), + connectedSocketState( NodeConnection_NotUsed ), + bufferSize( -1 ) +{ + memset( deviceName, 0, sizeof( deviceName ) ); +}; + +CNodeConnectionEntry::~CNodeConnectionEntry() +{ + if( NULL != channelConfig ) + { + delete channelConfig; + channelConfig = NULL; + } +} + +CNodeEntry::CNodeEntry() : deviceInstance( 0xFF ), nodeAddress( 0xFFFF ), deviceType( 0xFFFF ), macAddress( NULL ), + isTsiPortOpened(false), isMlbPortOpened( false ), isUsbPortOpened( false ), isI2SPortOpened( false ) +{ +} + +CNodeEntry::~CNodeEntry() +{ + if( NULL != macAddress ) + delete macAddress; +} + +uint16_t CNodeEntry::GetAmountOfNodeEntries() +{ + return allNodes.Size(); +} + +CNodeEntry *CNodeEntry::GetNodeEntry( uint16_t index ) +{ + return allNodes[index]; +} + +CNodeEntry *CNodeEntry::GetNodeEntry( uint8_t deviceInstance, uint16_t nodeAddress ) +{ + CNodeEntry *entry = NULL; + for( uint32_t i = 0; i < allNodes.Size(); i++ ) + { + if( ( allNodes[i]->deviceInstance == deviceInstance ) + && ( allNodes[i]->nodeAddress == nodeAddress ) ) + { + entry = allNodes[i]; + break; + } + } + if( NULL == entry ) + { + entry = new CNodeEntry(); + entry->deviceInstance = deviceInstance; + entry->nodeAddress = nodeAddress; + allNodes.PushBack( entry ); + } + return entry; +} + +CNodeEntry *CNodeEntry::GetNodeEntry( CMacAddr *macAddress ) +{ + if( NULL == macAddress ) + return NULL; + CNodeEntry *entry = NULL; + for( uint32_t i = 0; i < allNodes.Size(); i++ ) + { + CNodeEntry *node = allNodes[i]; + if( ( NULL != node->macAddress ) && ( *node->macAddress == *macAddress ) ) + { + entry = node; + break; + } + } + return entry; +} + +CNodeEntry *CNodeEntry::GetNodeEntry( uint8_t deviceInstance, uint32_t deviceType, uint32_t terminalInstance ) +{ + uint32_t inst = 0; + CNodeEntry *entry = NULL; + for( uint32_t i = 0; i < allNodes.Size(); i++ ) + { + CNodeEntry *node = allNodes[i]; + if( ( allNodes[i]->deviceInstance == deviceInstance ) + && ( allNodes[i]->deviceType == deviceType ) ) + { + if( inst == terminalInstance ) + { + entry = node; + break; + } + else + { + ++inst; + } + } + } + return entry; +} + +uint32_t CNodeEntry::GetTerminalInstance( uint8_t deviceInstance, uint16_t nodeAddress, uint32_t deviceType ) +{ + uint32_t terminalInst = 0; + for( uint32_t i = 0; i < allNodes.Size(); i++ ) + { + if( ( allNodes[i]->deviceInstance == deviceInstance ) + && ( allNodes[i]->deviceType == deviceType ) ) + { + if( ( allNodes[i]->nodeAddress == nodeAddress ) ) + break; + else + ++terminalInst; + } + } + return terminalInst; +} + +void CNodeEntry::DeleteAllNodeEntries() +{ + allNodes.RemoveAll(true); +} + +void CNodeEntry::DeleteNodeEntry( uint16_t index ) +{ + CNodeEntry *ent = allNodes[index]; + if( NULL == ent ) + return; + + allNodes.Remove(ent); + delete ent; +} + +const char *CNodeEntry::GetConnectionStateString( NodeConnectionState_t conState ) +{ + switch( conState ) + { + case NodeConnection_NotUsed: + return "Idle"; + case NodeConnection_Pending_Up: + return "Pending-Up"; + case NodeConnection_Pending_Down: + return "Pending-Down"; + case NodeConnection_Used: + return "Established"; + default: + return "Unknown State"; + } +} + +void CNodeEntry::PrintAllInformations() +{ + ConsolePrintfStart( PRIO_LOW, "==================================================================\n" ); + for( uint32_t i = 0; i < allNodes.Size(); i++ ) + { + CNodeEntry *entry = allNodes[i]; + ; + if( NULL != entry ) + { + ConsolePrintfContinue( "Inst:%d, NodeAddr:0x%X, DevType:0x%X, MAC:%s, open:%d\n", entry->deviceInstance, + entry->nodeAddress, entry->deviceType, ( NULL != entry->macAddress ? entry->macAddress->ToString() : + "None" ), ( entry->isUsbPortOpened || entry->isMlbPortOpened ) ); + for( uint32_t j = 0; j < entry->GetAmountOfConnections(); j++ ) + { + CNodeConnectionEntry *con = entry->GetConnectionByIndex( j ); + ConsolePrintfContinue( + "Id:%d, inHandle:0x%X, outHandle:0x%X, conHandle:0x%X, conLabel:0x%X, inState:%s, outState:%s, conState:%s, bufferSize:%d, name:%s\n", con->channelId, con->inHandle, con->outHandle, con->connectHandle, con->mostConnectionLabel, GetConnectionStateString( con->inSocketState ), GetConnectionStateString( con->outSocketState ), GetConnectionStateString( con->connectedSocketState ), con->bufferSize, con->deviceName ); + } + } + if( i < allNodes.Size() - 1 ) + ConsolePrintfContinue( "------------------------------------------------------------------\n" ); + } + ConsolePrintfExit( "==================================================================\n" ); +} + +uint16_t CNodeEntry::GetAmountOfConnections() +{ + return allConnections.Size(); +} + +CNodeConnectionEntry *CNodeEntry::GetConnectionByIndex( uint16_t index ) +{ + return allConnections[index]; +} + +CNodeConnectionEntry *CNodeEntry::GetConnectionByChannelId( uint32_t channelId, bool createNewIfUnknown ) +{ + CNodeConnectionEntry *entry = NULL; + for( uint32_t i = 0; i < allConnections.Size(); i++ ) + { + if( allConnections[i]->channelId == channelId ) + { + entry = allConnections[i]; + break; + } + } + if( createNewIfUnknown && NULL == entry ) + { + entry = new CNodeConnectionEntry( this ); + entry->channelId = channelId; + allConnections.PushBack( entry ); + } + return entry; +} + +CNodeConnectionEntry *CNodeEntry::GetConflictingConnection( uint32_t channelId, CNodeEntry *opposite ) +{ + if( NULL == opposite ) + return NULL; + if( opposite->deviceInstance != deviceInstance ) + return NULL; + CNodeConnectionEntry *entry = NULL; + uint32_t connectionLabel = 0xFFFFFFFF; + for( uint32_t i = 0; i < allConnections.Size(); i++ ) + { + if( allConnections[i]->channelId == channelId ) + { + connectionLabel = allConnections[i]->mostConnectionLabel; + break; + } + } + if( 0xFFFFFFFF != connectionLabel ) + { + for( uint32_t i = 0; i < opposite->allConnections.Size(); i++ ) + { + if( opposite->allConnections[i]->mostConnectionLabel == connectionLabel ) + { + entry = opposite->allConnections[i]; + break; + } + } + } + return entry; +} + +void CNodeEntry::DeleteConnection( uint32_t channelId ) +{ + uint32_t index = 0xFFFFFFFF; + for( uint32_t i = 0; i < allConnections.Size(); i++ ) + { + if( allConnections[i]->channelId == channelId ) + { + index = i; + } + } + if( index >= allNodes.Size() ) + return; + CNodeConnectionEntry *ent = allConnections[index]; + allConnections.Remove(ent); + delete ent; +} diff --git a/Src/Network/NodeDatabase.h b/Src/Network/NodeDatabase.h new file mode 100644 index 0000000..16eb863 --- /dev/null +++ b/Src/Network/NodeDatabase.h @@ -0,0 +1,379 @@ +/* + * 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 CNodeEntry and the CNodeConnectionEntry class. + */ +/*----------------------------------------------------------*/ +#ifndef NODEDATABASE_H +#define NODEDATABASE_H + +#include <stdint.h> +#include <stdbool.h> +#include "SafeVector.h" +#include "VodXml.h" +#include "MacAddr.h" + +class CNodeEntry; +class CNodeConnectionEntry; + +/*----------------------------------------------------------*/ +/*! \brief Enumeration describing the state of a Node socket + */ +/*----------------------------------------------------------*/ +typedef enum NodeConnectionState_tag +{ + NodeConnection_NotUsed, + NodeConnection_Pending_Up, + NodeConnection_Pending_Down, + NodeConnection_Used +} NodeConnectionState_t; + +/*----------------------------------------------------------*/ +/*! \brief Storage class holding informations of a specific MOST connection (Ports) + */ +/*----------------------------------------------------------*/ +class CNodeConnectionEntry +{ +public: + /*----------------------------------------------------------*/ + /*! \brief Pointer to the device, which this connection belongs to. + */ + /*----------------------------------------------------------*/ + CNodeEntry *parentNode; + + + /*----------------------------------------------------------*/ + /*! \brief Pointer to the XML generated configuration, holding the user specific part of this connection. + */ + /*----------------------------------------------------------*/ + CChannelConfiguration *channelConfig; + + + /*----------------------------------------------------------*/ + /*! \brief Identifier determinating the connection based on the XML configuration. + */ + /*----------------------------------------------------------*/ + uint32_t channelId; + + + /*----------------------------------------------------------*/ + /*! \brief In-Handle provided from INIC when the In-Socket was created + */ + /*----------------------------------------------------------*/ + uint32_t inHandle; + + + /*----------------------------------------------------------*/ + /*! \brief Out-Handle provided from INIC when the Out-Socket was created + */ + /*----------------------------------------------------------*/ + uint32_t outHandle; + + + /*----------------------------------------------------------*/ + /*! \brief Connection-Handle provided from INIC when the In- and the Out-Socket were connected. + */ + /*----------------------------------------------------------*/ + uint32_t connectHandle; + + + /*----------------------------------------------------------*/ + /*! \brief If this connection uses combiner or splitter, this handle points to the source / sink of the splitter / combiner. + * \note The idea of storing this handle, is only for cleanup purposes. + * \warning Do not use this handle for creating connections. + */ + /*----------------------------------------------------------*/ + uint32_t splittedSourceHandle; + + + /*----------------------------------------------------------*/ + /*! \brief Connection-Handle provided from INIC when the MOST-Socket was created. + */ + /*----------------------------------------------------------*/ + uint32_t mostConnectionLabel; + + + /*----------------------------------------------------------*/ + /*! \brief The state of the In-Socket + */ + /*----------------------------------------------------------*/ + NodeConnectionState_t inSocketState; + + + /*----------------------------------------------------------*/ + /*! \brief The state of the Out-Socket + */ + /*----------------------------------------------------------*/ + NodeConnectionState_t outSocketState; + + + /*----------------------------------------------------------*/ + /*! \brief The connection state between In-Socket and Out-Socket + */ + /*----------------------------------------------------------*/ + NodeConnectionState_t connectedSocketState; + + /*----------------------------------------------------------*/ + /*! \brief The used buffer size for this connection. + * \note bufferSize is -1 in case, there were no buffers configured. + */ + /*----------------------------------------------------------*/ + int32_t bufferSize; + + /*----------------------------------------------------------*/ + /*! \brief The Linux character device name, when this connection belongs to a local connection. May be strlen of 0. + */ + /*----------------------------------------------------------*/ + char deviceName[64]; + + + /*----------------------------------------------------------*/ + /*! \brief Constructor of CNodeConnectionEntry. + * \param Pointer to the device this connection belongs to. + */ + /*----------------------------------------------------------*/ + CNodeConnectionEntry( CNodeEntry *parentNode ); + + + /*----------------------------------------------------------*/ + /*! \brief Destructor of CNodeConnectionEntry. + */ + /*----------------------------------------------------------*/ + ~CNodeConnectionEntry(); +}; + +/*----------------------------------------------------------*/ +/*! \brief Storage class holding information of a specific MOST device + */ +/*----------------------------------------------------------*/ +class CNodeEntry +{ +private: + static CSafeVector<CNodeEntry *> allNodes; + CSafeVector<CNodeConnectionEntry *> allConnections; + + CNodeEntry(); + static const char *GetConnectionStateString( NodeConnectionState_t state ); +public: + ~CNodeEntry(); + + /*----------------------------------------------------------*/ + /*! \brief MOST instance. 0 for the first instance. If the server has multiple MOST devices, this value will be increased. + */ + /*----------------------------------------------------------*/ + uint8_t deviceInstance; + + + /*----------------------------------------------------------*/ + /*! \brief The unique address of the MOST device. + */ + /*----------------------------------------------------------*/ + uint16_t nodeAddress; + + + /*----------------------------------------------------------*/ + /*! \brief The type of the device (derived from the group address), as described in the XML configuration. + */ + /*----------------------------------------------------------*/ + uint16_t deviceType; + + + /*----------------------------------------------------------*/ + /*! \brief The unique MAC address of the device. + */ + /*----------------------------------------------------------*/ + CMacAddr *macAddress; + + + /*----------------------------------------------------------*/ + /*! \brief Determines if the TSI port is opened. + * \return true, if the port is opened. false + */ + /*----------------------------------------------------------*/ + bool isTsiPortOpened; + + /*----------------------------------------------------------*/ + /*! \brief Determines if the MLB port is opened. + * \return true, if the port is opened. false + */ + /*----------------------------------------------------------*/ + bool isMlbPortOpened; + + + /*----------------------------------------------------------*/ + /*! \brief Determines if the USB port is opened. + * \return true, if the port is opened. false + */ + /*----------------------------------------------------------*/ + bool isUsbPortOpened; + + + /*----------------------------------------------------------*/ + /*! \brief Determines if the USB port A is opened. + * \return true, if the port is opened. false + */ + /*----------------------------------------------------------*/ + bool isI2SPortOpened; + + + + /*----------------------------------------------------------*/ + /*! \brief Gets the amount of available MOST devices. + * \return The number of MOST devices. + */ + /*----------------------------------------------------------*/ + static uint16_t GetAmountOfNodeEntries(); + + + /*----------------------------------------------------------*/ + /*! \brief Gets an instance of CNodeEntry by the given instance index + * \param index - starting at 0 for the first instance. "GetAmountOfNodeEntries() - 1" for the last instance. + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + static CNodeEntry *GetNodeEntry( uint16_t index ); + + + /*----------------------------------------------------------*/ + /*! \brief Gets an instance of CNodeEntry by the given MOST instance and the unique node address of the device. + * \param deviceInstance - MOST instance id, starting at 0 for the first MOST ring. When the server have multiple MOST devices, + * This value may be above 0. + * \param nodeAddress - The MOST node address of the specific device (0x100 e.g.). + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + static CNodeEntry *GetNodeEntry( uint8_t deviceInstance, uint16_t nodeAddress ); + + + + /*----------------------------------------------------------*/ + /*! \brief Gets an instance of CNodeEntry by the given unique MAC address of the device. + * \param macAddress - Unique MAC address of the device + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + static CNodeEntry *GetNodeEntry( CMacAddr *macAddress ); + + /*----------------------------------------------------------*/ + /*! \brief Gets an instance of CNodeEntry by the given device type and terminal instance + * \param deviceInstance - MOST instance id, starting at 0 for the first MOST ring. When the server have multiple MOST devices, + * This value may be above 0. + * \param deviceType - The type of the device (derived from the group address), as described in the XML configuration. + * \param terminalInstance - The instance of the terminal, starting at 0 for the first terminal. + * + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + static CNodeEntry *GetNodeEntry( uint8_t deviceInstance, uint32_t deviceType, uint32_t terminalInstance ); + + + /*----------------------------------------------------------*/ + /*! \brief Gets the terminal instance number for the given device type. + * \param deviceInstance - MOST instance id, starting at 0 for the first MOST ring. When the server have multiple MOST devices, + * This value may be above 0. + * \param nodeAddress - The MOST node address of the specific device (0x100 e.g.). + * \param deviceType - The type of the device (derived from the group address), as described in the XML configuration. + * + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + static uint32_t GetTerminalInstance( uint8_t deviceInstance, uint16_t nodeAddress, uint32_t deviceType ); + + /*----------------------------------------------------------*/ + /*! \brief Deleting all informations of any device. + */ + /*----------------------------------------------------------*/ + static void DeleteAllNodeEntries(); + + + + /*----------------------------------------------------------*/ + /*! \brief Deleting all informations of a specific device. + * \param index - starting at 0 for the first instance. "GetAmountOfNodeEntries() - 1" for the last instance. + */ + /*----------------------------------------------------------*/ + static void DeleteNodeEntry( uint16_t index ); + + + + /*----------------------------------------------------------*/ + /*! \brief Dumps out all information of all devices to stdout + */ + /*----------------------------------------------------------*/ + static void PrintAllInformations(); + + + + /*----------------------------------------------------------*/ + /*! \brief Gets the amount of connection for the current instance of MOST device. + * \return The amount of connections. + */ + /*----------------------------------------------------------*/ + uint16_t GetAmountOfConnections(); + + + + /*----------------------------------------------------------*/ + /*! \brief Gets an instance of CNodeConnectionEntry by the given instance index. + * \param index - starting at 0 for the first instance. "GetAmountOfConnections() - 1" for the last instance. + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + CNodeConnectionEntry *GetConnectionByIndex( uint16_t index ); + + + + /*----------------------------------------------------------*/ + /*! \brief Gets an instance of CNodeConnectionEntry by the given channel identifier. + * \param channelId - The channel identifier as specified in the XML file. + * \param createNewIfUnknown - TRUE, if this function shall create a new entry, when there is no existing object. + * \return The requested instance, when successful. Otherwise NULL pointer. + */ + /*----------------------------------------------------------*/ + CNodeConnectionEntry *GetConnectionByChannelId( uint32_t channelId, bool createNewIfUnknown ); + + + + /*----------------------------------------------------------*/ + /*! \brief Retrieves a conflicting connection by the given parameters.# + * This method checks if the in and out configurations are unique for one device. + * \param channelId - The channel identifier as specified in the XML file. + * \param opposite - The other side to be connected to. + * \return The instance, which causes an conflict. If there is no conflict, a NULL pointer will be returned. + */ + /*----------------------------------------------------------*/ + CNodeConnectionEntry *GetConflictingConnection( uint32_t channelId, CNodeEntry *opposite ); + + + + /*----------------------------------------------------------*/ + /*! \brief Delets all informations of the given channel identifier. + * \param channelId - The channel identifier as specified in the XML file. + */ + /*----------------------------------------------------------*/ + void DeleteConnection( uint32_t channelId ); +}; + +#endif //NODEDATABASE_H diff --git a/Src/Network/base/.svn/dir-prop-base b/Src/Network/base/.svn/dir-prop-base new file mode 100644 index 0000000..c4fbe3b --- /dev/null +++ b/Src/Network/base/.svn/dir-prop-base @@ -0,0 +1,14 @@ +K 16 +bugtraq:logregex +V 67 +(?:[Bb]ugs?|[Ii]ssues?|[Rr]eports?)+\s+#(?:(?:\d+)[#,\.\s]*)+ +(\d+) +K 15 +bugtraq:message +V 21 +Mantis issue #%BUGID% +K 11 +bugtraq:url +V 33 +http://mantis/view.php?id=%BUGID% +END diff --git a/Src/Network/base/.svn/entries b/Src/Network/base/.svn/entries new file mode 100644 index 0000000..eba0b2c --- /dev/null +++ b/Src/Network/base/.svn/entries @@ -0,0 +1,164 @@ +10 + +dir +6611 +svn://kar-vm-svn01.mchp-main.com/svn/AppsTeam/Samples/iMX6+OS81118/Industrial/VideoOnDemand/tags/V3.0.4/source/Examples/NetworkManager/Server/Src/Network/base +svn://kar-vm-svn01.mchp-main.com/svn/AppsTeam + + + +2016-03-08T10:11:00.246092Z +5263 +tkummermehr +has-props + + + + + + + + + + + + + +c50209ca-6af6-4c1a-9d47-4b11eae79d1c + +Board.c +file + + + + +2016-11-29T13:32:01.206172Z +002b1b0937a1a1653ff724364be62050 +2016-03-08T10:11:00.246092Z +5263 +tkummermehr + + + + + + + + + + + + + + + + + + + + + +1685 + +DriverConfiguration.h +file + + + + +2016-11-29T13:32:01.206172Z +05273e72ca5b7af8c2f55a35fcdaa5a0 +2015-12-17T09:32:42.832988Z +5040 +ashvetsov +has-props + + + + + + + + + + + + + + + + + + + + +11839 + +Board.h +file + + + + +2016-11-29T13:32:01.206172Z +40cb461e8d0039b063b790d626d37f1a +2016-03-08T10:11:00.246092Z +5263 +tkummermehr + + + + + + + + + + + + + + + + + + + + + +1799 + +DriverConfiguration.c +file + + + + +2016-11-29T13:32:01.202172Z +b8e55c1b0e2437a8513afd32ae4f5446 +2015-12-17T09:32:42.832988Z +5040 +ashvetsov +has-props + + + + + + + + + + + + + + + + + + + + +18468 + diff --git a/Src/Network/base/.svn/prop-base/DriverConfiguration.c.svn-base b/Src/Network/base/.svn/prop-base/DriverConfiguration.c.svn-base new file mode 100644 index 0000000..3160658 --- /dev/null +++ b/Src/Network/base/.svn/prop-base/DriverConfiguration.c.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mergeinfo +V 0 + +END diff --git a/Src/Network/base/.svn/prop-base/DriverConfiguration.h.svn-base b/Src/Network/base/.svn/prop-base/DriverConfiguration.h.svn-base new file mode 100644 index 0000000..3160658 --- /dev/null +++ b/Src/Network/base/.svn/prop-base/DriverConfiguration.h.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mergeinfo +V 0 + +END diff --git a/Src/Network/base/.svn/text-base/Board.c.svn-base b/Src/Network/base/.svn/text-base/Board.c.svn-base new file mode 100644 index 0000000..50daf0c --- /dev/null +++ b/Src/Network/base/.svn/text-base/Board.c.svn-base @@ -0,0 +1,51 @@ +/* + * 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 Base Board initialisation */ +/*----------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include "Board.h" +#include "Console.h" + +uint32_t GetTickCount( void ) +{ + struct timespec currentTime; + if (clock_gettime(CLOCK_MONOTONIC_RAW, ¤tTime)) + { + ConsolePrintf( PRIO_ERROR, RED"GetTickCount failed!!"RESETCOLOR"\n" ); + return 0; + } + return ( currentTime.tv_sec * 1000 ) + ( currentTime.tv_nsec / 1000000 ); +} + +uint16_t GetTickCountWord() +{ + return ( uint16_t )( GetTickCount() & UINT16_MAX ); +} diff --git a/Src/Network/base/.svn/text-base/Board.h.svn-base b/Src/Network/base/.svn/text-base/Board.h.svn-base new file mode 100644 index 0000000..585a862 --- /dev/null +++ b/Src/Network/base/.svn/text-base/Board.h.svn-base @@ -0,0 +1,63 @@ +/* + * 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 component abstracts platform specific functionalities. + */ +/*----------------------------------------------------------*/ +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + + /*----------------------------------------------------------*/ + /*! \brief reads the ms tick counter. + * + * \return value of the ms counter. + */ + /*----------------------------------------------------------*/ + uint32_t GetTickCount( void ); + + + + + /*----------------------------------------------------------*/ + /*! \brief reads the ms tick counter + * + * \return value of the ms counter as word + */ + /*----------------------------------------------------------*/ + uint16_t GetTickCountWord( void ); + + +#ifdef __cplusplus +} +#endif + +#endif // _BOARD_H_ diff --git a/Src/Network/base/.svn/text-base/DriverConfiguration.c.svn-base b/Src/Network/base/.svn/text-base/DriverConfiguration.c.svn-base new file mode 100644 index 0000000..7a98d25 --- /dev/null +++ b/Src/Network/base/.svn/text-base/DriverConfiguration.c.svn-base @@ -0,0 +1,608 @@ +/* + * 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. + * + */ + +#include <dirent.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <errno.h> +#include "DriverConfiguration.h" +#include "Console.h" + +static bool WriteCharactersToFile( const char *pFileName, const char *pString ) +{ + bool success = false; + FILE *fh = fopen( pFileName, "a" ); + if( NULL != fh ) + { + int result = fputs( pString, fh ); + if( result >= 0 ) + fputc( '\n', fh ); + if( result >= 0 ) + success = true; + fclose( fh ); + } + if( success ) + ConsolePrintf( PRIO_MEDIUM, "*** configured device: '%s = %s', success:%d\n", pFileName, pString, success ); + else + ConsolePrintf( PRIO_ERROR, RED"DriverConfiguration.WriteCharactersToFile failed for file '%s', errno:'%s'"RESETCOLOR"\n", + pFileName, GetErrnoString() ); + return success; +} + +static bool WriteIntegerToFile( const char *pFileName, int intValue ) +{ + char tempBuffer[16]; + snprintf( tempBuffer, sizeof( tempBuffer ), "%d", intValue ); + return WriteCharactersToFile( pFileName, tempBuffer ); +} + +static bool ReadFromFile( const char *pFileName, char *pString, uint16_t bufferLen ) +{ + bool success = false; + if( NULL == pString || 0 == bufferLen ) + return success; + FILE *fh = fopen( pFileName, "r" ); + if( NULL != fh ) + { + success = ( NULL != fgets( pString, bufferLen, fh ) ); + fclose( fh ); + } + if( !success ) + ConsolePrintf( PRIO_ERROR, RED"DriverConfiguration.ReadFromFile failed for file '%s', errno:'%s'"RESETCOLOR"\n", + pFileName, GetErrnoString() ); + return success; +} + +static bool ExistsDevice( const char *pDeviceName ) +{ + struct stat buffer; + return ( stat( pDeviceName, &buffer ) == 0 ); +} + +static bool WaitForDevice( const char *pDeviceName ) +{ + int timeout; + bool deviceExists = false; + for( timeout = 0; timeout < 40; timeout++ ) + { + deviceExists = ExistsDevice( pDeviceName ); + if( deviceExists ) + { + break; + } + else + { + usleep( 2500 ); + } + } + if( !deviceExists ) + ConsolePrintf( PRIO_ERROR, RED"Waiting for device '%s' to appear, timed out"RESETCOLOR"\n", + pDeviceName ); + return deviceExists; +} + +static bool GetDeviceDescription( uint8_t deviceInstance, char *deviceString, uint32_t stringLen ) +{ + bool descriptionFound = false; + char descriptionPath[64]; + char descriptionValue[32]; + + if( NULL == deviceString ) + return descriptionFound; + + snprintf( descriptionPath, sizeof( descriptionPath ), + "/sys/devices/virtual/most/mostcore/devices/mdev%d/description", deviceInstance ); + + if( !ExistsDevice( descriptionPath ) ) + return descriptionFound; + + descriptionFound = ReadFromFile( descriptionPath, descriptionValue, sizeof( descriptionValue ) ); + if( descriptionFound ) + { + strncpy( deviceString, descriptionValue, stringLen ); + } + return descriptionFound; +} + +static bool ExistsDeviceWithType( uint8_t deviceInstance, const char *deviceString, uint32_t stringLen ) +{ + bool deviceFound = false; + char interfacePath[64]; + char interfaceValue[32]; + + if( NULL == deviceString ) + return deviceFound; + + snprintf( interfacePath, sizeof( interfacePath ), "/sys/devices/virtual/most/mostcore/devices/mdev%d/interface", + deviceInstance ); + + if( !ExistsDevice( interfacePath ) ) + return deviceFound; + + deviceFound = ReadFromFile( interfacePath, interfaceValue, sizeof( interfaceValue ) ); + if( deviceFound ) + { + deviceFound = ( 0 == strncmp( interfaceValue, deviceString, stringLen ) ); + } + return deviceFound; +} + +static bool GetAlsaConfiguration( uint16_t subBufferSize, uint8_t *amountOfChannels, uint8_t *bitDepth ) +{ + if( NULL == amountOfChannels || NULL == bitDepth ) + { + ConsolePrintf( PRIO_ERROR, RED"GetAlsaConfiguration was called with invalid parameters"RESETCOLOR"\n" ); + return false; + } + switch( subBufferSize ) + { + case 2: + *amountOfChannels = 1; + *bitDepth = 16; + break; + case 4: + *amountOfChannels = 2; + *bitDepth = 16; + break; + case 6: + *amountOfChannels = 2; + *bitDepth = 24; + break; + case 8: + *amountOfChannels = 2; + *bitDepth = 32; + break; + case 12: + *amountOfChannels = 6; + *bitDepth = 16; + break; + case 18: + *amountOfChannels = 6; + *bitDepth = 24; + break; + case 16: + *amountOfChannels = 8; + *bitDepth = 16; + break; + case 24: + *amountOfChannels = 8; + *bitDepth = 24; + break; + default: + ConsolePrintf( PRIO_ERROR, RED"Configure ALSA device was called"\ + " with unknown sub-buffer size: %d"RESETCOLOR"\n", subBufferSize ); + return false; + } + return true; +} + +bool ExistsUsbDeviceInstance( uint8_t deviceInstance ) +{ + uint32_t i; + bool found = false; + uint8_t curDevInst = 0; + char lastDescr[64]; + lastDescr[0] = '\0'; + for( i = 0; i < 12; i++ ) + { + uint32_t curDescrLen; + char curDescr[64]; + if( !ExistsDeviceWithType( i, "usb", 3 ) ) + continue; + + if( !GetDeviceDescription( i, curDescr, sizeof( curDescr ) ) ) + continue; + + curDescrLen = strnlen( curDescr, sizeof( curDescr ) ); + if( curDescrLen <= 2 ) + continue; + + //Cut away the last two characters, as they are different for the 3 interfaces of INIC + curDescrLen -= 2; + + if( 0 == strncmp( curDescr, lastDescr, curDescrLen ) ) + continue; + + strncpy( lastDescr, curDescr, curDescrLen ); + lastDescr[curDescrLen] = '\0'; + + if( curDevInst++ != deviceInstance ) + continue; + + found = true; + break; + } + return found; +} + +bool ExistsMlbDeviceInstance( uint8_t deviceInstance ) +{ + return ExistsDeviceWithType( deviceInstance, "mlb", 3 ); +} + +bool ExistsI2CDeviceInstance( uint8_t deviceInstance ) +{ + return ExistsDeviceWithType( deviceInstance, "i2c", 3 ); +} + +bool GetUsbDeviceNames( uint8_t deviceInstance, uint8_t endpointAddress, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) +{ + uint32_t i; + bool systemFound = false; + uint8_t curDevInst = 0; + char lastDescr[64]; + lastDescr[0] = '\0'; + char endpointBuffer[16]; + char systemSourceDir[64]; + DIR *d; + struct dirent *dir; + + if( NULL == deviceName || NULL == systemName || NULL == linkName ) + return false; + + deviceName[0] = '\0'; + systemName[0] = '\0'; + + for( i = 0; !systemFound && i < 12; i++ ) + { + uint32_t curDescrLen; + char curDescr[64]; + if( !ExistsDeviceWithType( i, "usb", 3 ) ) + continue; + + if( !GetDeviceDescription( i, curDescr, sizeof( curDescr ) ) ) + continue; + + curDescrLen = strnlen( curDescr, sizeof( curDescr ) ); + if( curDescrLen <= 2 ) + continue; + + //Cut away the last two characters, as they are different for the 3 interfaces of INIC + curDescrLen -= 2; + + if( ( '\0' != lastDescr[0] ) + && ( 0 != strncmp( curDescr, lastDescr, curDescrLen ) ) ) + { + ++curDevInst; + } + + strncpy( lastDescr, curDescr, curDescrLen ); + lastDescr[curDescrLen] = '\0'; + + if( curDevInst < deviceInstance ) + continue; + else if( curDevInst > deviceInstance ) + break; + + snprintf( endpointBuffer, sizeof( endpointBuffer ), "ep%02x", endpointAddress ); + snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", i ); + d = opendir( systemSourceDir ); + if( d ) + { + while( ( dir = readdir( d ) ) != NULL ) + { + if( strstr( dir->d_name, endpointBuffer ) ) + { + snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); + snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); + snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", i, dir->d_name, deviceInstance, + dir->d_name ); + systemFound = true; + break; + } + } + closedir( d ); + } + } + return systemFound; +} + +bool GetMlbDeviceNames( uint8_t deviceInstance, uint8_t mlbChannelAddress, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) +{ + bool systemFound = false; + char channelBuffer[16]; + char systemSourceDir[64]; + DIR *d; + struct dirent *dir; + + if( NULL == deviceName || NULL == systemName || NULL == linkName ) + return false; + + deviceName[0] = '\0'; + systemName[0] = '\0'; + + snprintf( channelBuffer, sizeof( channelBuffer ), "ca%d", mlbChannelAddress ); + snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", + deviceInstance ); + d = opendir( systemSourceDir ); + if( d ) + { + while( ( dir = readdir( d ) ) != NULL ) + { + if( strstr( dir->d_name, channelBuffer ) ) + { + snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); + snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); + snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", deviceInstance, dir->d_name, deviceInstance, + dir->d_name ); + systemFound = true; + break; + } + } + closedir( d ); + } + return systemFound; +} + +bool GetI2CDeviceNames( uint8_t deviceInstance, bool isTx, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) +{ + bool systemFound = false; + char systemSourceDir[64]; + DIR *d; + struct dirent *dir; + + if( NULL == deviceName || NULL == systemName || NULL == linkName ) + return false; + + deviceName[0] = '\0'; + systemName[0] = '\0'; + + snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", + deviceInstance ); + d = opendir( systemSourceDir ); + if( d ) + { + while( ( dir = readdir( d ) ) != NULL ) + { + if( strstr( dir->d_name, ( isTx ? "tx" : "rx" ) ) ) + { + snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); + snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); + snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", deviceInstance, dir->d_name, deviceInstance, + dir->d_name ); + systemFound = true; + break; + } + } + closedir( d ); + } + return systemFound; +} + +bool CloseMostChannel( const char *device ) +{ + return true; +} + +bool ConfigureMostChannel( const char *device, EPDataType_t mostType, EPDirection_t direction, uint32_t numBuf, + uint32_t bufSize ) +{ + static const char *controlType = "control"; + static const char *asyncType = "async"; + static const char *syncType = "sync"; + static const char *isocType = "isoc_avp"; + static const char *rxDirection = "dir_rx"; + static const char *txDirection = "dir_tx"; + bool success = true; + char tempBuffer[128]; + const char *typeString = NULL; + const char *directionString = NULL; + + switch( mostType ) + { + case EP_Control: + typeString = controlType; + break; + case EP_Asynchron: + typeString = asyncType; + break; + case EP_Synchron: + typeString = syncType; + break; + case EP_Isochron: + typeString = isocType; + break; + default: + return false; + } + + switch( direction ) + { + case EPDIR_IN: + directionString = txDirection; + break; + case EPDIR_OUT: + directionString = rxDirection; + break; + default: + return false; + } + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_datatype", device ); /// Setting data type + success = WriteCharactersToFile( tempBuffer, typeString ); + if( success ) + { + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_direction", device ); /// Setting direction + success = WriteCharactersToFile( tempBuffer, directionString ); + } + if( success ) + { + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_number_of_buffers", device ); /// Setting amount of buffers + success = WriteIntegerToFile( tempBuffer, numBuf ); + } + if( success ) + { + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_buffer_size", device ); /// Setting amount of buffers + success = WriteIntegerToFile( tempBuffer, bufSize ); + } + return success; +} + +bool ConfigureIsocChannel( const char *device, uint32_t subbufferSize, uint32_t packetsPerTransaction ) +{ + char tempBuffer[128]; + bool success; + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_subbuffer_size", device ); /// Setting the subbuffer size in bytes + success = WriteIntegerToFile( tempBuffer, subbufferSize ); + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_packets_per_xact", device ); /// Setting the packets per transaction + success = WriteIntegerToFile( tempBuffer, ( packetsPerTransaction & 0xFF ) ); + return success; +} + +bool ConfigureSyncChannel( const char *device, uint32_t syncBlockWidth, uint32_t amounOfSyncFrames ) +{ + char tempBuffer[128]; + bool success; + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_packets_per_xact", device ); /// Setting the amount of frames in one USB frame + success = WriteIntegerToFile( tempBuffer, amounOfSyncFrames ); + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_subbuffer_size", device ); /// Setting the blockwidth of a single frame + success = WriteIntegerToFile( tempBuffer, syncBlockWidth ); + return success; +} + +bool LinkToCharacterDevice( const char *linkName, const char *deviceName ) +{ + bool success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/cdev/add_link", linkName ); + if( success ) + { + success = WaitForDevice( deviceName ); + } + if( success ) + { + chmod( deviceName, ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) ); + } + return success; +} + +bool LinkToAudioDevice( const char *linkName, uint16_t subBufferSize ) +{ + char tempBuffer[128]; + uint8_t amountOfChannels; + uint8_t bitDepth; + if( !GetAlsaConfiguration( subBufferSize, &amountOfChannels, &bitDepth ) ) + return false; + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s.%dx%d", linkName, amountOfChannels, bitDepth ); /// Add the channel information behind the Link Name + + //Be compatible to all versions of MOST Linux Driver. The name was changed of Sound AIM. + bool success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/sound/add_link", tempBuffer ); + if( !success ) + success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/audio/add_link", tempBuffer ); + return success; +} + +bool LinkToVideoForLinuxDevice( const char *linkName ) +{ + bool success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/v4l/add_link", linkName ); + return success; +} + +const char *GetErrnoString() +{ + switch( errno ) + { + case 0: + return "Nothing stored in errno"; + case 1: + return "Operation not permitted"; + case 2: + return "No such file or directory"; + case 3: + return "No such process"; + case 4: + return "Interrupted system call"; + case 5: + return "I/O error"; + case 6: + return "No such device or address"; + case 7: + return "Argument list too long"; + case 8: + return "Exec format error"; + case 9: + return "Bad file number"; + case 10: + return "No child processes"; + case 11: + return "Try again"; + case 12: + return "Out of memory"; + case 13: + return "Permission denied"; + case 14: + return "Bad address"; + case 15: + return "Block device required"; + case 16: + return "Device or resource busy"; + case 17: + return "File exists"; + case 18: + return "Cross-device link"; + case 19: + return "No such device"; + case 20: + return "Not a directory"; + case 21: + return "Is a directory"; + case 22: + return "Invalid argument"; + case 23: + return "File table overflow"; + case 24: + return "Too many open files"; + case 25: + return "Not a typewriter"; + case 26: + return "Text file busy"; + case 27: + return "File too large"; + case 28: + return "No space left on device"; + case 29: + return "Illegal seek"; + case 30: + return "Read-only file system"; + case 31: + return "Too many links"; + case 32: + return "Broken pipe"; + case 33: + return "Math argument out of domain of func"; + case 34: + return "Math result not representable"; + default: + break; + } + return "Unknown"; +} diff --git a/Src/Network/base/.svn/text-base/DriverConfiguration.h.svn-base b/Src/Network/base/.svn/text-base/DriverConfiguration.h.svn-base new file mode 100644 index 0000000..b2fd44a --- /dev/null +++ b/Src/Network/base/.svn/text-base/DriverConfiguration.h.svn-base @@ -0,0 +1,239 @@ +/* + * 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 component provides helper tools to deal with USB endpoints. + */ +/*----------------------------------------------------------*/ +#ifndef DRIVERCONFIGURATION_H +#define DRIVERCONFIGURATION_H + +#include <stdint.h> +#include <stdbool.h> +#include "Types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + /*----------------------------------------------------------*/ + /*! \brief Checks if the given USB device instance exists. + * + * \param deviceInstance - The device instance of the USB INIC, starting at 0 for the first instance. + * + * \return true: Device exists. + * \return false: Device does not exist. + */ + /*----------------------------------------------------------*/ + bool ExistsUsbDeviceInstance( uint8_t deviceInstance ); + + /*----------------------------------------------------------*/ + /*! \brief Checks if the given MLB device instance exists. + * + * \param deviceInstance - The device instance of the MLB INIC, starting at 0 for the first instance. + * + * \return true: Device exists. + * \return false: Device does not exist. + */ + /*----------------------------------------------------------*/ + bool ExistsMlbDeviceInstance( uint8_t deviceInstance ); + + /*----------------------------------------------------------*/ + /*! \brief Checks if the given I2C device instance exists. + * + * \param deviceInstance - The device instance of the I2C INIC, starting at 0 for the first instance. + * + * \return true: Device exists. + * \return false: Device does not exist. + */ + /*----------------------------------------------------------*/ + bool ExistsI2CDeviceInstance( uint8_t deviceInstance ); + + /*----------------------------------------------------------*/ + /*! \brief Retreives the Linux character device names for the given USB device instance and the endpoint address. + * + * \note If the given buffer is too small to hold the whole path, the string is truncated and not useable! + * + * \param deviceInstance - The device instance of the USB INIC, starting at 0 for the first instance. + * \param endpointAddress - The USB endpoint address, RX endpoints starting with upper bit set (0x8X). + * \param deviceName - [in,out] Given buffer will be filled with device name (starting with /dev/). + * \param deviceNameLength - The length of the given deviceName buffer in bytes. + * \param systemName - [in,out] Given buffer will be filled with system name (starting with /sys/). + * \param systemNameLength - The length of the given systemName buffer in bytes. + * \param linkName - [in,out] Given buffer will be filled with the string needed to register this device to an AIM + * \param linkNameLength - The length of the given linkName buffer in bytes. + * + * \return true: Operation was successful. + * \return false: Operation failed, device or endpoint does not exist. + */ + /*----------------------------------------------------------*/ + bool GetUsbDeviceNames( uint8_t deviceInstance, uint8_t endpointAddress, char *deviceName, + uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, + uint16_t linkNameLength ); + + + /*----------------------------------------------------------*/ + /*! \brief Retreives the Linux character device names for the given MLB device instance and the endpoint address. + * + * \note If the given buffer is too small to hold the whole path, the string is truncated and not useable! + * + * \param deviceInstance - The device instance of the USB INIC, starting at 0 for the first instance. + * \param mlbChannelAddress - The MLB channel address + * \param deviceName - [in,out] Given buffer will be filled with device name (starting with /dev/). + * \param deviceNameLength - The length of the given deviceName buffer in bytes. + * \param systemName - [in,out] Given buffer will be filled with system name (starting with /sys/). + * \param systemNameLength - The length of the given systemName buffer in bytes. + * \param linkName - [in,out] Given buffer will be filled with the string needed to register this device to an AIM + * \param linkNameLength - The length of the given linkName buffer in bytes. + * + * \return true: Operation was successful. + * \return false: Operation failed, device or endpoint does not exist. + */ + /*----------------------------------------------------------*/ + bool GetMlbDeviceNames( uint8_t deviceInstance, uint8_t mlbChannelAddress, char *deviceName, + uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, + uint16_t linkNameLength ); + + + /*----------------------------------------------------------*/ + /*! \brief Retreives the Linux character device names for the given I2C device instance and the endpoint address. + * + * \note If the given buffer is too small to hold the whole path, the string is truncated and not useable! + * + * \param deviceInstance - The device instance of the I2C INIC, starting at 0 for the first instance. + * \param isTx - true, if the names for transmission path should be retrieved, otherwise for the reception path. + * \param deviceName - [in,out] Given buffer will be filled with device name (starting with /dev/). + * \param deviceNameLength - The length of the given deviceName buffer in bytes. + * \param systemName - [in,out] Given buffer will be filled with system name (starting with /sys/). + * \param systemNameLength - The length of the given systemName buffer in bytes. + * \param linkName - [in,out] Given buffer will be filled with the string needed to register this device to an AIM + * \param linkNameLength - The length of the given linkName buffer in bytes. + * + * \return true: Operation was successful. + * \return false: Operation failed, device or endpoint does not exist. + */ + /*----------------------------------------------------------*/ + bool GetI2CDeviceNames( uint8_t deviceInstance, bool isTx, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ); + + /*----------------------------------------------------------*/ + /*! \brief Closes the MOST channel. + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool CloseMostChannel( const char *device ); + + /*----------------------------------------------------------*/ + /*! \brief Configures the MOST channel. + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * \param mostType - The MOST data type (control, asynchron, synchron, isochron). + * \param direction - The direction of the stream (directionRX, directionTX). + * \param numBuf - The amount of buffers. + * \param bufSize - The size of each buffer in bytes. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool ConfigureMostChannel( const char *device, EPDataType_t mostType, EPDirection_t direction, uint32_t numBuf, + uint32_t bufSize ); + + /*----------------------------------------------------------*/ + /*! \brief Configures the isochronous channel of a device. + * \note This function has to be called before ConfigureMostChannel! + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * \param subbufferSize - The amount of bytes for a single subbuffer (eg. 188 or 196 bytes). + * \param packetsPerTransaction - The amount of ischronous packets per transaction. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool ConfigureIsocChannel( const char *device, uint32_t subbufferSize, uint32_t packetsPerTransaction ); + + /*----------------------------------------------------------*/ + /*! \brief Configures the Synchronous channel of a device. + * \note This function has to be called before ConfigureMostChannel! + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * \param syncBlockWidth - The bandwidth of a single synchronous frame. Ignored if not sync channel. + * \param amounOfSyncFrames - The amount of synchronous frames per USB packet. Ignored if not sync channel. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool ConfigureSyncChannel( const char *device, uint32_t syncBlockWidth, uint32_t amounOfSyncFrames ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a character device for the given device's link name. + * + * \param linkName - [in] Link name, which is needed to register this device to an AIM. + * \param deviceName - [in,out] Device name (starting with /dev/). + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool LinkToCharacterDevice( const char *linkName, const char *deviceName ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a audio device (ALSA) for the given device's link name. + * + * \param linkName - [in] Link name, which is needed to register this device to an AIM. + * \param subBufferSize - [in] The amount of bytes for all channels of this connection on the MOST. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool LinkToAudioDevice( const char *linkName, uint16_t subBufferSize ); + + /*----------------------------------------------------------*/ + /*! \brief Creates a Video for Linux device (V4L) for the given device's link name. + * + * \param linkName - [in] Link name, which is needed to register this device to an AIM. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool LinkToVideoForLinuxDevice( const char *linkName ); + + + /*----------------------------------------------------------*/ + /*! \brief Parsed the global errno variable and generate a human readable error description out of it. + * + * \return Zero terminated error description string. + */ + /*----------------------------------------------------------*/ + const char *GetErrnoString(); + +#ifdef __cplusplus +} +#endif + +#endif //DRIVERCONFIGURATION_H diff --git a/Src/Network/base/Board.c b/Src/Network/base/Board.c new file mode 100644 index 0000000..50daf0c --- /dev/null +++ b/Src/Network/base/Board.c @@ -0,0 +1,51 @@ +/* + * 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 Base Board initialisation */ +/*----------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include "Board.h" +#include "Console.h" + +uint32_t GetTickCount( void ) +{ + struct timespec currentTime; + if (clock_gettime(CLOCK_MONOTONIC_RAW, ¤tTime)) + { + ConsolePrintf( PRIO_ERROR, RED"GetTickCount failed!!"RESETCOLOR"\n" ); + return 0; + } + return ( currentTime.tv_sec * 1000 ) + ( currentTime.tv_nsec / 1000000 ); +} + +uint16_t GetTickCountWord() +{ + return ( uint16_t )( GetTickCount() & UINT16_MAX ); +} diff --git a/Src/Network/base/Board.h b/Src/Network/base/Board.h new file mode 100644 index 0000000..585a862 --- /dev/null +++ b/Src/Network/base/Board.h @@ -0,0 +1,63 @@ +/* + * 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 component abstracts platform specific functionalities. + */ +/*----------------------------------------------------------*/ +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + + /*----------------------------------------------------------*/ + /*! \brief reads the ms tick counter. + * + * \return value of the ms counter. + */ + /*----------------------------------------------------------*/ + uint32_t GetTickCount( void ); + + + + + /*----------------------------------------------------------*/ + /*! \brief reads the ms tick counter + * + * \return value of the ms counter as word + */ + /*----------------------------------------------------------*/ + uint16_t GetTickCountWord( void ); + + +#ifdef __cplusplus +} +#endif + +#endif // _BOARD_H_ diff --git a/Src/Network/base/DriverConfiguration.c b/Src/Network/base/DriverConfiguration.c new file mode 100644 index 0000000..7a98d25 --- /dev/null +++ b/Src/Network/base/DriverConfiguration.c @@ -0,0 +1,608 @@ +/* + * 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. + * + */ + +#include <dirent.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <errno.h> +#include "DriverConfiguration.h" +#include "Console.h" + +static bool WriteCharactersToFile( const char *pFileName, const char *pString ) +{ + bool success = false; + FILE *fh = fopen( pFileName, "a" ); + if( NULL != fh ) + { + int result = fputs( pString, fh ); + if( result >= 0 ) + fputc( '\n', fh ); + if( result >= 0 ) + success = true; + fclose( fh ); + } + if( success ) + ConsolePrintf( PRIO_MEDIUM, "*** configured device: '%s = %s', success:%d\n", pFileName, pString, success ); + else + ConsolePrintf( PRIO_ERROR, RED"DriverConfiguration.WriteCharactersToFile failed for file '%s', errno:'%s'"RESETCOLOR"\n", + pFileName, GetErrnoString() ); + return success; +} + +static bool WriteIntegerToFile( const char *pFileName, int intValue ) +{ + char tempBuffer[16]; + snprintf( tempBuffer, sizeof( tempBuffer ), "%d", intValue ); + return WriteCharactersToFile( pFileName, tempBuffer ); +} + +static bool ReadFromFile( const char *pFileName, char *pString, uint16_t bufferLen ) +{ + bool success = false; + if( NULL == pString || 0 == bufferLen ) + return success; + FILE *fh = fopen( pFileName, "r" ); + if( NULL != fh ) + { + success = ( NULL != fgets( pString, bufferLen, fh ) ); + fclose( fh ); + } + if( !success ) + ConsolePrintf( PRIO_ERROR, RED"DriverConfiguration.ReadFromFile failed for file '%s', errno:'%s'"RESETCOLOR"\n", + pFileName, GetErrnoString() ); + return success; +} + +static bool ExistsDevice( const char *pDeviceName ) +{ + struct stat buffer; + return ( stat( pDeviceName, &buffer ) == 0 ); +} + +static bool WaitForDevice( const char *pDeviceName ) +{ + int timeout; + bool deviceExists = false; + for( timeout = 0; timeout < 40; timeout++ ) + { + deviceExists = ExistsDevice( pDeviceName ); + if( deviceExists ) + { + break; + } + else + { + usleep( 2500 ); + } + } + if( !deviceExists ) + ConsolePrintf( PRIO_ERROR, RED"Waiting for device '%s' to appear, timed out"RESETCOLOR"\n", + pDeviceName ); + return deviceExists; +} + +static bool GetDeviceDescription( uint8_t deviceInstance, char *deviceString, uint32_t stringLen ) +{ + bool descriptionFound = false; + char descriptionPath[64]; + char descriptionValue[32]; + + if( NULL == deviceString ) + return descriptionFound; + + snprintf( descriptionPath, sizeof( descriptionPath ), + "/sys/devices/virtual/most/mostcore/devices/mdev%d/description", deviceInstance ); + + if( !ExistsDevice( descriptionPath ) ) + return descriptionFound; + + descriptionFound = ReadFromFile( descriptionPath, descriptionValue, sizeof( descriptionValue ) ); + if( descriptionFound ) + { + strncpy( deviceString, descriptionValue, stringLen ); + } + return descriptionFound; +} + +static bool ExistsDeviceWithType( uint8_t deviceInstance, const char *deviceString, uint32_t stringLen ) +{ + bool deviceFound = false; + char interfacePath[64]; + char interfaceValue[32]; + + if( NULL == deviceString ) + return deviceFound; + + snprintf( interfacePath, sizeof( interfacePath ), "/sys/devices/virtual/most/mostcore/devices/mdev%d/interface", + deviceInstance ); + + if( !ExistsDevice( interfacePath ) ) + return deviceFound; + + deviceFound = ReadFromFile( interfacePath, interfaceValue, sizeof( interfaceValue ) ); + if( deviceFound ) + { + deviceFound = ( 0 == strncmp( interfaceValue, deviceString, stringLen ) ); + } + return deviceFound; +} + +static bool GetAlsaConfiguration( uint16_t subBufferSize, uint8_t *amountOfChannels, uint8_t *bitDepth ) +{ + if( NULL == amountOfChannels || NULL == bitDepth ) + { + ConsolePrintf( PRIO_ERROR, RED"GetAlsaConfiguration was called with invalid parameters"RESETCOLOR"\n" ); + return false; + } + switch( subBufferSize ) + { + case 2: + *amountOfChannels = 1; + *bitDepth = 16; + break; + case 4: + *amountOfChannels = 2; + *bitDepth = 16; + break; + case 6: + *amountOfChannels = 2; + *bitDepth = 24; + break; + case 8: + *amountOfChannels = 2; + *bitDepth = 32; + break; + case 12: + *amountOfChannels = 6; + *bitDepth = 16; + break; + case 18: + *amountOfChannels = 6; + *bitDepth = 24; + break; + case 16: + *amountOfChannels = 8; + *bitDepth = 16; + break; + case 24: + *amountOfChannels = 8; + *bitDepth = 24; + break; + default: + ConsolePrintf( PRIO_ERROR, RED"Configure ALSA device was called"\ + " with unknown sub-buffer size: %d"RESETCOLOR"\n", subBufferSize ); + return false; + } + return true; +} + +bool ExistsUsbDeviceInstance( uint8_t deviceInstance ) +{ + uint32_t i; + bool found = false; + uint8_t curDevInst = 0; + char lastDescr[64]; + lastDescr[0] = '\0'; + for( i = 0; i < 12; i++ ) + { + uint32_t curDescrLen; + char curDescr[64]; + if( !ExistsDeviceWithType( i, "usb", 3 ) ) + continue; + + if( !GetDeviceDescription( i, curDescr, sizeof( curDescr ) ) ) + continue; + + curDescrLen = strnlen( curDescr, sizeof( curDescr ) ); + if( curDescrLen <= 2 ) + continue; + + //Cut away the last two characters, as they are different for the 3 interfaces of INIC + curDescrLen -= 2; + + if( 0 == strncmp( curDescr, lastDescr, curDescrLen ) ) + continue; + + strncpy( lastDescr, curDescr, curDescrLen ); + lastDescr[curDescrLen] = '\0'; + + if( curDevInst++ != deviceInstance ) + continue; + + found = true; + break; + } + return found; +} + +bool ExistsMlbDeviceInstance( uint8_t deviceInstance ) +{ + return ExistsDeviceWithType( deviceInstance, "mlb", 3 ); +} + +bool ExistsI2CDeviceInstance( uint8_t deviceInstance ) +{ + return ExistsDeviceWithType( deviceInstance, "i2c", 3 ); +} + +bool GetUsbDeviceNames( uint8_t deviceInstance, uint8_t endpointAddress, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) +{ + uint32_t i; + bool systemFound = false; + uint8_t curDevInst = 0; + char lastDescr[64]; + lastDescr[0] = '\0'; + char endpointBuffer[16]; + char systemSourceDir[64]; + DIR *d; + struct dirent *dir; + + if( NULL == deviceName || NULL == systemName || NULL == linkName ) + return false; + + deviceName[0] = '\0'; + systemName[0] = '\0'; + + for( i = 0; !systemFound && i < 12; i++ ) + { + uint32_t curDescrLen; + char curDescr[64]; + if( !ExistsDeviceWithType( i, "usb", 3 ) ) + continue; + + if( !GetDeviceDescription( i, curDescr, sizeof( curDescr ) ) ) + continue; + + curDescrLen = strnlen( curDescr, sizeof( curDescr ) ); + if( curDescrLen <= 2 ) + continue; + + //Cut away the last two characters, as they are different for the 3 interfaces of INIC + curDescrLen -= 2; + + if( ( '\0' != lastDescr[0] ) + && ( 0 != strncmp( curDescr, lastDescr, curDescrLen ) ) ) + { + ++curDevInst; + } + + strncpy( lastDescr, curDescr, curDescrLen ); + lastDescr[curDescrLen] = '\0'; + + if( curDevInst < deviceInstance ) + continue; + else if( curDevInst > deviceInstance ) + break; + + snprintf( endpointBuffer, sizeof( endpointBuffer ), "ep%02x", endpointAddress ); + snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", i ); + d = opendir( systemSourceDir ); + if( d ) + { + while( ( dir = readdir( d ) ) != NULL ) + { + if( strstr( dir->d_name, endpointBuffer ) ) + { + snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); + snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); + snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", i, dir->d_name, deviceInstance, + dir->d_name ); + systemFound = true; + break; + } + } + closedir( d ); + } + } + return systemFound; +} + +bool GetMlbDeviceNames( uint8_t deviceInstance, uint8_t mlbChannelAddress, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) +{ + bool systemFound = false; + char channelBuffer[16]; + char systemSourceDir[64]; + DIR *d; + struct dirent *dir; + + if( NULL == deviceName || NULL == systemName || NULL == linkName ) + return false; + + deviceName[0] = '\0'; + systemName[0] = '\0'; + + snprintf( channelBuffer, sizeof( channelBuffer ), "ca%d", mlbChannelAddress ); + snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", + deviceInstance ); + d = opendir( systemSourceDir ); + if( d ) + { + while( ( dir = readdir( d ) ) != NULL ) + { + if( strstr( dir->d_name, channelBuffer ) ) + { + snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); + snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); + snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", deviceInstance, dir->d_name, deviceInstance, + dir->d_name ); + systemFound = true; + break; + } + } + closedir( d ); + } + return systemFound; +} + +bool GetI2CDeviceNames( uint8_t deviceInstance, bool isTx, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) +{ + bool systemFound = false; + char systemSourceDir[64]; + DIR *d; + struct dirent *dir; + + if( NULL == deviceName || NULL == systemName || NULL == linkName ) + return false; + + deviceName[0] = '\0'; + systemName[0] = '\0'; + + snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", + deviceInstance ); + d = opendir( systemSourceDir ); + if( d ) + { + while( ( dir = readdir( d ) ) != NULL ) + { + if( strstr( dir->d_name, ( isTx ? "tx" : "rx" ) ) ) + { + snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); + snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); + snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", deviceInstance, dir->d_name, deviceInstance, + dir->d_name ); + systemFound = true; + break; + } + } + closedir( d ); + } + return systemFound; +} + +bool CloseMostChannel( const char *device ) +{ + return true; +} + +bool ConfigureMostChannel( const char *device, EPDataType_t mostType, EPDirection_t direction, uint32_t numBuf, + uint32_t bufSize ) +{ + static const char *controlType = "control"; + static const char *asyncType = "async"; + static const char *syncType = "sync"; + static const char *isocType = "isoc_avp"; + static const char *rxDirection = "dir_rx"; + static const char *txDirection = "dir_tx"; + bool success = true; + char tempBuffer[128]; + const char *typeString = NULL; + const char *directionString = NULL; + + switch( mostType ) + { + case EP_Control: + typeString = controlType; + break; + case EP_Asynchron: + typeString = asyncType; + break; + case EP_Synchron: + typeString = syncType; + break; + case EP_Isochron: + typeString = isocType; + break; + default: + return false; + } + + switch( direction ) + { + case EPDIR_IN: + directionString = txDirection; + break; + case EPDIR_OUT: + directionString = rxDirection; + break; + default: + return false; + } + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_datatype", device ); /// Setting data type + success = WriteCharactersToFile( tempBuffer, typeString ); + if( success ) + { + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_direction", device ); /// Setting direction + success = WriteCharactersToFile( tempBuffer, directionString ); + } + if( success ) + { + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_number_of_buffers", device ); /// Setting amount of buffers + success = WriteIntegerToFile( tempBuffer, numBuf ); + } + if( success ) + { + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_buffer_size", device ); /// Setting amount of buffers + success = WriteIntegerToFile( tempBuffer, bufSize ); + } + return success; +} + +bool ConfigureIsocChannel( const char *device, uint32_t subbufferSize, uint32_t packetsPerTransaction ) +{ + char tempBuffer[128]; + bool success; + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_subbuffer_size", device ); /// Setting the subbuffer size in bytes + success = WriteIntegerToFile( tempBuffer, subbufferSize ); + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_packets_per_xact", device ); /// Setting the packets per transaction + success = WriteIntegerToFile( tempBuffer, ( packetsPerTransaction & 0xFF ) ); + return success; +} + +bool ConfigureSyncChannel( const char *device, uint32_t syncBlockWidth, uint32_t amounOfSyncFrames ) +{ + char tempBuffer[128]; + bool success; + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_packets_per_xact", device ); /// Setting the amount of frames in one USB frame + success = WriteIntegerToFile( tempBuffer, amounOfSyncFrames ); + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_subbuffer_size", device ); /// Setting the blockwidth of a single frame + success = WriteIntegerToFile( tempBuffer, syncBlockWidth ); + return success; +} + +bool LinkToCharacterDevice( const char *linkName, const char *deviceName ) +{ + bool success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/cdev/add_link", linkName ); + if( success ) + { + success = WaitForDevice( deviceName ); + } + if( success ) + { + chmod( deviceName, ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) ); + } + return success; +} + +bool LinkToAudioDevice( const char *linkName, uint16_t subBufferSize ) +{ + char tempBuffer[128]; + uint8_t amountOfChannels; + uint8_t bitDepth; + if( !GetAlsaConfiguration( subBufferSize, &amountOfChannels, &bitDepth ) ) + return false; + + snprintf( tempBuffer, sizeof( tempBuffer ), "%s.%dx%d", linkName, amountOfChannels, bitDepth ); /// Add the channel information behind the Link Name + + //Be compatible to all versions of MOST Linux Driver. The name was changed of Sound AIM. + bool success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/sound/add_link", tempBuffer ); + if( !success ) + success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/audio/add_link", tempBuffer ); + return success; +} + +bool LinkToVideoForLinuxDevice( const char *linkName ) +{ + bool success = + WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/v4l/add_link", linkName ); + return success; +} + +const char *GetErrnoString() +{ + switch( errno ) + { + case 0: + return "Nothing stored in errno"; + case 1: + return "Operation not permitted"; + case 2: + return "No such file or directory"; + case 3: + return "No such process"; + case 4: + return "Interrupted system call"; + case 5: + return "I/O error"; + case 6: + return "No such device or address"; + case 7: + return "Argument list too long"; + case 8: + return "Exec format error"; + case 9: + return "Bad file number"; + case 10: + return "No child processes"; + case 11: + return "Try again"; + case 12: + return "Out of memory"; + case 13: + return "Permission denied"; + case 14: + return "Bad address"; + case 15: + return "Block device required"; + case 16: + return "Device or resource busy"; + case 17: + return "File exists"; + case 18: + return "Cross-device link"; + case 19: + return "No such device"; + case 20: + return "Not a directory"; + case 21: + return "Is a directory"; + case 22: + return "Invalid argument"; + case 23: + return "File table overflow"; + case 24: + return "Too many open files"; + case 25: + return "Not a typewriter"; + case 26: + return "Text file busy"; + case 27: + return "File too large"; + case 28: + return "No space left on device"; + case 29: + return "Illegal seek"; + case 30: + return "Read-only file system"; + case 31: + return "Too many links"; + case 32: + return "Broken pipe"; + case 33: + return "Math argument out of domain of func"; + case 34: + return "Math result not representable"; + default: + break; + } + return "Unknown"; +} diff --git a/Src/Network/base/DriverConfiguration.h b/Src/Network/base/DriverConfiguration.h new file mode 100644 index 0000000..b2fd44a --- /dev/null +++ b/Src/Network/base/DriverConfiguration.h @@ -0,0 +1,239 @@ +/* + * 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 component provides helper tools to deal with USB endpoints. + */ +/*----------------------------------------------------------*/ +#ifndef DRIVERCONFIGURATION_H +#define DRIVERCONFIGURATION_H + +#include <stdint.h> +#include <stdbool.h> +#include "Types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + /*----------------------------------------------------------*/ + /*! \brief Checks if the given USB device instance exists. + * + * \param deviceInstance - The device instance of the USB INIC, starting at 0 for the first instance. + * + * \return true: Device exists. + * \return false: Device does not exist. + */ + /*----------------------------------------------------------*/ + bool ExistsUsbDeviceInstance( uint8_t deviceInstance ); + + /*----------------------------------------------------------*/ + /*! \brief Checks if the given MLB device instance exists. + * + * \param deviceInstance - The device instance of the MLB INIC, starting at 0 for the first instance. + * + * \return true: Device exists. + * \return false: Device does not exist. + */ + /*----------------------------------------------------------*/ + bool ExistsMlbDeviceInstance( uint8_t deviceInstance ); + + /*----------------------------------------------------------*/ + /*! \brief Checks if the given I2C device instance exists. + * + * \param deviceInstance - The device instance of the I2C INIC, starting at 0 for the first instance. + * + * \return true: Device exists. + * \return false: Device does not exist. + */ + /*----------------------------------------------------------*/ + bool ExistsI2CDeviceInstance( uint8_t deviceInstance ); + + /*----------------------------------------------------------*/ + /*! \brief Retreives the Linux character device names for the given USB device instance and the endpoint address. + * + * \note If the given buffer is too small to hold the whole path, the string is truncated and not useable! + * + * \param deviceInstance - The device instance of the USB INIC, starting at 0 for the first instance. + * \param endpointAddress - The USB endpoint address, RX endpoints starting with upper bit set (0x8X). + * \param deviceName - [in,out] Given buffer will be filled with device name (starting with /dev/). + * \param deviceNameLength - The length of the given deviceName buffer in bytes. + * \param systemName - [in,out] Given buffer will be filled with system name (starting with /sys/). + * \param systemNameLength - The length of the given systemName buffer in bytes. + * \param linkName - [in,out] Given buffer will be filled with the string needed to register this device to an AIM + * \param linkNameLength - The length of the given linkName buffer in bytes. + * + * \return true: Operation was successful. + * \return false: Operation failed, device or endpoint does not exist. + */ + /*----------------------------------------------------------*/ + bool GetUsbDeviceNames( uint8_t deviceInstance, uint8_t endpointAddress, char *deviceName, + uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, + uint16_t linkNameLength ); + + + /*----------------------------------------------------------*/ + /*! \brief Retreives the Linux character device names for the given MLB device instance and the endpoint address. + * + * \note If the given buffer is too small to hold the whole path, the string is truncated and not useable! + * + * \param deviceInstance - The device instance of the USB INIC, starting at 0 for the first instance. + * \param mlbChannelAddress - The MLB channel address + * \param deviceName - [in,out] Given buffer will be filled with device name (starting with /dev/). + * \param deviceNameLength - The length of the given deviceName buffer in bytes. + * \param systemName - [in,out] Given buffer will be filled with system name (starting with /sys/). + * \param systemNameLength - The length of the given systemName buffer in bytes. + * \param linkName - [in,out] Given buffer will be filled with the string needed to register this device to an AIM + * \param linkNameLength - The length of the given linkName buffer in bytes. + * + * \return true: Operation was successful. + * \return false: Operation failed, device or endpoint does not exist. + */ + /*----------------------------------------------------------*/ + bool GetMlbDeviceNames( uint8_t deviceInstance, uint8_t mlbChannelAddress, char *deviceName, + uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, + uint16_t linkNameLength ); + + + /*----------------------------------------------------------*/ + /*! \brief Retreives the Linux character device names for the given I2C device instance and the endpoint address. + * + * \note If the given buffer is too small to hold the whole path, the string is truncated and not useable! + * + * \param deviceInstance - The device instance of the I2C INIC, starting at 0 for the first instance. + * \param isTx - true, if the names for transmission path should be retrieved, otherwise for the reception path. + * \param deviceName - [in,out] Given buffer will be filled with device name (starting with /dev/). + * \param deviceNameLength - The length of the given deviceName buffer in bytes. + * \param systemName - [in,out] Given buffer will be filled with system name (starting with /sys/). + * \param systemNameLength - The length of the given systemName buffer in bytes. + * \param linkName - [in,out] Given buffer will be filled with the string needed to register this device to an AIM + * \param linkNameLength - The length of the given linkName buffer in bytes. + * + * \return true: Operation was successful. + * \return false: Operation failed, device or endpoint does not exist. + */ + /*----------------------------------------------------------*/ + bool GetI2CDeviceNames( uint8_t deviceInstance, bool isTx, char *deviceName, uint16_t deviceNameLength, + char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ); + + /*----------------------------------------------------------*/ + /*! \brief Closes the MOST channel. + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool CloseMostChannel( const char *device ); + + /*----------------------------------------------------------*/ + /*! \brief Configures the MOST channel. + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * \param mostType - The MOST data type (control, asynchron, synchron, isochron). + * \param direction - The direction of the stream (directionRX, directionTX). + * \param numBuf - The amount of buffers. + * \param bufSize - The size of each buffer in bytes. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool ConfigureMostChannel( const char *device, EPDataType_t mostType, EPDirection_t direction, uint32_t numBuf, + uint32_t bufSize ); + + /*----------------------------------------------------------*/ + /*! \brief Configures the isochronous channel of a device. + * \note This function has to be called before ConfigureMostChannel! + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * \param subbufferSize - The amount of bytes for a single subbuffer (eg. 188 or 196 bytes). + * \param packetsPerTransaction - The amount of ischronous packets per transaction. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool ConfigureIsocChannel( const char *device, uint32_t subbufferSize, uint32_t packetsPerTransaction ); + + /*----------------------------------------------------------*/ + /*! \brief Configures the Synchronous channel of a device. + * \note This function has to be called before ConfigureMostChannel! + * + * \param device - The system path to configure the MOST device (starting with "/sys/"). + * \param syncBlockWidth - The bandwidth of a single synchronous frame. Ignored if not sync channel. + * \param amounOfSyncFrames - The amount of synchronous frames per USB packet. Ignored if not sync channel. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool ConfigureSyncChannel( const char *device, uint32_t syncBlockWidth, uint32_t amounOfSyncFrames ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a character device for the given device's link name. + * + * \param linkName - [in] Link name, which is needed to register this device to an AIM. + * \param deviceName - [in,out] Device name (starting with /dev/). + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool LinkToCharacterDevice( const char *linkName, const char *deviceName ); + + + /*----------------------------------------------------------*/ + /*! \brief Creates a audio device (ALSA) for the given device's link name. + * + * \param linkName - [in] Link name, which is needed to register this device to an AIM. + * \param subBufferSize - [in] The amount of bytes for all channels of this connection on the MOST. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool LinkToAudioDevice( const char *linkName, uint16_t subBufferSize ); + + /*----------------------------------------------------------*/ + /*! \brief Creates a Video for Linux device (V4L) for the given device's link name. + * + * \param linkName - [in] Link name, which is needed to register this device to an AIM. + * + * \return True if no error + */ + /*----------------------------------------------------------*/ + bool LinkToVideoForLinuxDevice( const char *linkName ); + + + /*----------------------------------------------------------*/ + /*! \brief Parsed the global errno variable and generate a human readable error description out of it. + * + * \return Zero terminated error description string. + */ + /*----------------------------------------------------------*/ + const char *GetErrnoString(); + +#ifdef __cplusplus +} +#endif + +#endif //DRIVERCONFIGURATION_H |