| /******************************************************************************* | |
| * Copyright (c) 2012 -2014 AIT, ACIN, fortiss GmbH | |
| * All rights reserved. This program and the accompanying materials | |
| * are made available under the terms of the Eclipse Public License v1.0 | |
| * which accompanies this distribution, and is available at | |
| * http://www.eclipse.org/legal/epl-v10.html | |
| * | |
| * Contributors: | |
| * Filip Andren, Patrick Smejkal, Alois Zoitl, Martin Melik-Merkumians - initial API and implementation and/or initial documentation | |
| *******************************************************************************/ | |
| #include "modbuslayer.h" | |
| #include "commfb.h" | |
| #include "modbusclientconnection.h" | |
| using namespace forte::com_infra; | |
| CModbusComLayer::CModbusComLayer(CComLayer* pa_poUpperLayer, CBaseCommFB* pa_poComFB) : | |
| CComLayer(pa_poUpperLayer, pa_poComFB), m_pModbusConnection(0), m_unBufFillSize(0){ | |
| m_eConnectionState = e_Disconnected; | |
| } | |
| CModbusComLayer::~CModbusComLayer(){ | |
| } | |
| EComResponse CModbusComLayer::sendData(void *pa_pvData, unsigned int pa_unSize){ | |
| EComResponse eRetVal = e_ProcessDataOk; | |
| if(m_eConnectionState == e_Connected){ | |
| switch (m_poFb->getComServiceType()){ | |
| case e_Server: | |
| // todo | |
| break; | |
| case e_Client: { | |
| TForteUInt16 *convertedData = new TForteUInt16[pa_unSize * 4]; | |
| unsigned int sendLength = convertDataInput(pa_pvData, pa_unSize, convertedData); | |
| if(sendLength > 0){ | |
| m_pModbusConnection->writeData(convertedData, sendLength); | |
| } | |
| delete[] convertedData; | |
| break; | |
| } | |
| case e_Publisher: | |
| // todo | |
| break; | |
| case e_Subscriber: | |
| //do nothing as subscribers do not send data | |
| break; | |
| } | |
| } | |
| return eRetVal; | |
| } | |
| unsigned int CModbusComLayer::convertDataInput(void *pa_poInData, unsigned int pa_nDataSize, TForteUInt16 *pa_poConvertedData){ | |
| unsigned int outLength = 0; | |
| CIEC_ANY *apoSDs = static_cast<CIEC_ANY*>(pa_poInData); | |
| unsigned int nrSDs = pa_nDataSize; | |
| for(unsigned int i = 0; i < nrSDs; i++){ | |
| CIEC_ANY *anyVal = &apoSDs[i]; | |
| switch (apoSDs[i].getDataTypeID()){ | |
| case CIEC_ANY::e_BOOL: // 8bit data types | |
| { | |
| TForteUInt16 out = (bool) *(CIEC_BOOL*) anyVal; | |
| *(TForteUInt16*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteUInt16) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_SINT: { | |
| TForteInt16 out = (TForteInt8) *(CIEC_SINT*) anyVal; | |
| *(TForteInt16*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteInt16) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_USINT: { | |
| TForteUInt16 out = (TForteUInt8) *(CIEC_USINT*) anyVal; | |
| *(TForteUInt16*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteUInt16) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_BYTE: { | |
| TForteUInt16 out = (TForteByte) *(CIEC_BYTE*) anyVal; | |
| *(TForteUInt16*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteUInt16) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_INT: // 16bit data types | |
| { | |
| TForteInt16 out = (TForteInt16) *(CIEC_INT*) anyVal; | |
| *(TForteInt16*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteInt16) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_UINT: { | |
| TForteUInt16 out = (TForteUInt16) *(CIEC_UINT*) anyVal; | |
| *(TForteUInt16*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteUInt16) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_WORD: { | |
| TForteWord out = (TForteWord) *(CIEC_WORD*) anyVal; | |
| *(TForteWord*) (&pa_poConvertedData[outLength]) = out; | |
| outLength += sizeof(TForteWord) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_DINT: // 32bit data types | |
| { | |
| TForteInt32 out = (TForteInt32) *static_cast<CIEC_DINT*>(anyVal); | |
| *(TForteInt32*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteInt32>((TForteByte*) &out, sizeof(TForteInt32)); | |
| outLength += sizeof(TForteInt32) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_UDINT: { | |
| TForteUInt32 out = (TForteUInt32) *(CIEC_UDINT*) anyVal; | |
| *(TForteUInt32*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteUInt32>((TForteByte*) &out, sizeof(TForteUInt32)); | |
| outLength += sizeof(TForteUInt32) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_DWORD: { | |
| TForteDWord out = (TForteDWord) *(CIEC_DWORD*) anyVal; | |
| *(TForteDWord*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteDWord>((TForteByte*) &out, sizeof(TForteDWord)); | |
| outLength += sizeof(TForteDWord) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_REAL: { | |
| TForteFloat out = (TForteFloat) *(CIEC_REAL*) anyVal; | |
| *(TForteFloat*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteFloat>((TForteByte*) &out, sizeof(TForteFloat)); | |
| outLength += sizeof(TForteFloat) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_LINT: // 64bit data types | |
| { | |
| TForteInt64 out = (TForteInt64) *(CIEC_LINT*) anyVal; | |
| *(TForteInt64*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteInt64>((TForteByte*) &out, sizeof(TForteInt64)); | |
| outLength += sizeof(TForteInt64) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_ULINT: { | |
| TForteUInt64 out = (TForteUInt64) *(CIEC_ULINT*) anyVal; | |
| *(TForteUInt64*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteUInt64>((TForteByte*) &out, sizeof(TForteUInt64)); | |
| outLength += sizeof(TForteUInt64) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_LWORD: { | |
| TForteLWord out = (TForteLWord) *(CIEC_LWORD*) anyVal; | |
| *(TForteLWord*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteLWord>((TForteByte*) &out, sizeof(TForteLWord)); | |
| outLength += sizeof(TForteLWord) / 2; | |
| break; | |
| } | |
| case CIEC_ANY::e_LREAL: { | |
| TForteDFloat out = (TForteDFloat) *(CIEC_LREAL*) anyVal; | |
| *(TForteDFloat*) (&pa_poConvertedData[outLength]) = convertFBOutput<TForteDFloat>((TForteByte*) &out, sizeof(TForteDFloat)); | |
| outLength += sizeof(TForteDFloat) / 2; | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| return outLength; | |
| } | |
| EComResponse CModbusComLayer::processInterrupt(){ | |
| if(e_ProcessDataOk == m_eInterruptResp){ | |
| switch (m_eConnectionState){ | |
| case e_Connected: { | |
| CIEC_ANY *apoRDs = m_poFb->getRDs(); | |
| unsigned int nrRDs = m_poFb->getNumRD(); | |
| unsigned int dataIndex = 0; | |
| for(unsigned int i = 0; i < nrRDs; i++){ | |
| switch (apoRDs[i].getDataTypeID()){ | |
| case CIEC_ANY::e_BOOL: | |
| apoRDs[i].setValue(CIEC_BOOL(convertFBOutput<bool>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(bool); | |
| break; | |
| case CIEC_ANY::e_SINT: | |
| apoRDs[i].setValue(CIEC_SINT(convertFBOutput<TForteInt8>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteInt8); | |
| break; | |
| case CIEC_ANY::e_INT: | |
| apoRDs[i].setValue(CIEC_INT(convertFBOutput<TForteInt16>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteInt16); | |
| break; | |
| case CIEC_ANY::e_DINT: | |
| apoRDs[i].setValue(CIEC_DINT(convertFBOutput<TForteInt32>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteInt32); | |
| break; | |
| case CIEC_ANY::e_LINT: | |
| apoRDs[i].setValue(CIEC_LINT(convertFBOutput<TForteInt64>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteInt64); | |
| break; | |
| case CIEC_ANY::e_USINT: | |
| apoRDs[i].setValue(CIEC_USINT(convertFBOutput<TForteUInt8>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteUInt8); | |
| break; | |
| case CIEC_ANY::e_UINT: | |
| apoRDs[i].setValue(CIEC_UINT(convertFBOutput<TForteUInt16>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteUInt16); | |
| break; | |
| case CIEC_ANY::e_UDINT: | |
| apoRDs[i].setValue(CIEC_UDINT(convertFBOutput<TForteUInt32>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteUInt32); | |
| break; | |
| case CIEC_ANY::e_ULINT: | |
| apoRDs[i].setValue(CIEC_ULINT(convertFBOutput<TForteUInt64>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteUInt64); | |
| break; | |
| case CIEC_ANY::e_BYTE: | |
| apoRDs[i].setValue(CIEC_BYTE(convertFBOutput<TForteByte>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteByte); | |
| break; | |
| case CIEC_ANY::e_WORD: | |
| apoRDs[i].setValue(CIEC_WORD(convertFBOutput<TForteWord>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteWord); | |
| break; | |
| case CIEC_ANY::e_DWORD: | |
| apoRDs[i].setValue(CIEC_DWORD(convertFBOutput<TForteDWord>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteDWord); | |
| break; | |
| case CIEC_ANY::e_LWORD: | |
| apoRDs[i].setValue(CIEC_LWORD(convertFBOutput<TForteLWord>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteLWord); | |
| break; | |
| case CIEC_ANY::e_REAL: | |
| apoRDs[i].setValue(CIEC_REAL(convertFBOutput<TForteFloat>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteFloat); | |
| break; | |
| case CIEC_ANY::e_LREAL: | |
| apoRDs[i].setValue(CIEC_LREAL(convertFBOutput<TForteDFloat>(&m_acRecvBuffer[dataIndex], m_unBufFillSize - dataIndex))); | |
| dataIndex += sizeof(TForteDFloat); | |
| break; | |
| default: | |
| // TODO | |
| break; | |
| } | |
| } | |
| break; | |
| } | |
| case e_Disconnected: | |
| case e_Listening: | |
| case e_ConnectedAndListening: | |
| default: | |
| break; | |
| } | |
| } | |
| else{ | |
| if(e_InitTerminated == m_eInterruptResp){ | |
| // todo: Move server into listening mode again, etc. | |
| } | |
| } | |
| return m_eInterruptResp; | |
| } | |
| EComResponse CModbusComLayer::recvData(const void *, unsigned int){ | |
| m_eInterruptResp = e_Nothing; | |
| switch (m_eConnectionState){ | |
| case e_Listening: | |
| //TODO accept incoming connection | |
| break; | |
| case e_Connected: { | |
| int nRetVal = 0; | |
| switch (m_poFb->getComServiceType()){ | |
| case e_Server: | |
| //TODO | |
| break; | |
| case e_Client: | |
| //TODO check if errors occured during polling in ModbusConnection | |
| nRetVal = m_pModbusConnection->readData(&m_acRecvBuffer[0]); | |
| break; | |
| case e_Publisher: | |
| //do nothing as publisher cannot receive data | |
| break; | |
| case e_Subscriber: | |
| //do nothing since Modbus protocol cannot act as subscriber | |
| break; | |
| } | |
| switch (nRetVal){ | |
| case 0: | |
| //TODO | |
| break; | |
| default: | |
| //we successfully received data | |
| m_unBufFillSize = nRetVal; | |
| m_eInterruptResp = e_ProcessDataOk; | |
| break; | |
| } | |
| m_poFb->interruptCommFB(this); | |
| } | |
| break; | |
| case e_ConnectedAndListening: | |
| case e_Disconnected: | |
| default: | |
| break; | |
| } | |
| return m_eInterruptResp; | |
| } | |
| template<typename T> | |
| T CModbusComLayer::convertFBOutput(TForteByte *pa_acDataArray, unsigned int pa_nDataSize){ | |
| T retVal; | |
| unsigned int currentDataSize = sizeof(T); | |
| if(currentDataSize <= pa_nDataSize){ | |
| if(currentDataSize > 2){ | |
| // A data type with size greater than 16 bits is requested => | |
| // we need to swap order of each 16 bit data package | |
| unsigned int nrUint16s = currentDataSize / 2; | |
| TForteUInt16 *destAr = new TForteUInt16[nrUint16s]; | |
| TForteUInt16 *sourceAr = (TForteUInt16*) pa_acDataArray; | |
| for(unsigned int i = 0; i < nrUint16s; i++) | |
| destAr[i] = sourceAr[nrUint16s - 1 - i]; | |
| retVal = *((T*) destAr); | |
| delete[] destAr; | |
| } | |
| else{ | |
| TForteByte *tempAr = new TForteByte[currentDataSize]; | |
| for(unsigned int j = 0; j < currentDataSize; j++) | |
| tempAr[j] = pa_acDataArray[j]; | |
| retVal = *((T*) tempAr); | |
| delete[] tempAr; | |
| } | |
| } | |
| else | |
| retVal = 0; | |
| return retVal; | |
| } | |
| EComResponse CModbusComLayer::openConnection(char *pa_acLayerParameter){ | |
| EComResponse eRetVal = e_InitInvalidId; | |
| switch (m_poFb->getComServiceType()){ | |
| case e_Server: | |
| //TODO open server connection | |
| m_eConnectionState = e_Listening; | |
| break; | |
| case e_Client: { | |
| STcpParams tcpParams; | |
| SRtuParams rtuParams; | |
| SCommonParams commonParams; | |
| memset(&tcpParams, 0, sizeof(tcpParams)); | |
| memset(&rtuParams, 0, sizeof(rtuParams)); | |
| memset(&commonParams, 0, sizeof(commonParams)); | |
| int errCode = processClientParams(pa_acLayerParameter, &tcpParams, &rtuParams, &commonParams); | |
| if(errCode != 0){ | |
| DEVLOG_ERROR("CModbusComLayer:: Invalid input parameters\n"); | |
| } | |
| else{ | |
| m_pModbusConnection = new CModbusClientConnection(getExtEvHandler<CModbusHandler>()); | |
| if(strlen(tcpParams.m_acIp) > 0){ | |
| m_pModbusConnection->setIPAddress(tcpParams.m_acIp); | |
| m_pModbusConnection->setPort(tcpParams.m_nPort); | |
| } | |
| else if(strlen(rtuParams.m_acDevice) > 0){ | |
| m_pModbusConnection->setDevice(rtuParams.m_acDevice); | |
| m_pModbusConnection->setBaud(rtuParams.m_nBaud); | |
| m_pModbusConnection->setParity(rtuParams.m_cParity); | |
| m_pModbusConnection->setDataBit(rtuParams.m_nDataBit); | |
| m_pModbusConnection->setStopBit(rtuParams.m_nStopBit); | |
| } | |
| m_pModbusConnection->setComCallback(this); | |
| m_pModbusConnection->setResponseTimeout(commonParams.m_nResponseTimeout); | |
| m_pModbusConnection->setByteTimeout(commonParams.m_nByteTimeout); | |
| static_cast<CModbusClientConnection*>(m_pModbusConnection)->setSlaveId(commonParams.m_nSlaveId); | |
| for(unsigned int i = 0; i < commonParams.m_nNrPolls; i++){ | |
| static_cast<CModbusClientConnection*>(m_pModbusConnection)->addNewPoll(commonParams.m_nPollFrequency, commonParams.m_nFuncCode, commonParams.m_nReadStartAddress[i], commonParams.m_nReadNrAddresses[i]); | |
| } | |
| for(unsigned int i = 0; i < commonParams.m_nNrSends; i++){ | |
| static_cast<CModbusClientConnection*>(m_pModbusConnection)->addNewSend(commonParams.m_nSendStartAddress[i], commonParams.m_nSendNrAddresses[i]); | |
| } | |
| if(m_pModbusConnection->connect() < 0){ | |
| return eRetVal; | |
| } | |
| m_eConnectionState = e_Connected; | |
| eRetVal = e_InitOk; | |
| } | |
| } | |
| break; | |
| case e_Publisher: | |
| //do nothing as modbus cannot be publisher | |
| break; | |
| case e_Subscriber: | |
| //do nothing as modbus cannot be subscriber | |
| break; | |
| } | |
| return eRetVal; | |
| } | |
| void CModbusComLayer::closeConnection(){ | |
| //TODO | |
| DEVLOG_INFO("CModbusLayer::closeConnection()\n"); | |
| if(m_pModbusConnection != NULL){ | |
| m_pModbusConnection->disconnect(); | |
| delete m_pModbusConnection; | |
| } | |
| } | |
| int CModbusComLayer::processClientParams(char* pa_acLayerParams, STcpParams* pa_pTcpParams, SRtuParams* pa_pRtuParams, SCommonParams* pa_pCommonParams){ | |
| char *params = new char[strlen(pa_acLayerParams) + 1]; | |
| char *paramsAddress = params; | |
| strcpy(params, pa_acLayerParams); | |
| char *chrStorage; | |
| pa_pTcpParams->m_acIp[0] = '\0'; | |
| pa_pRtuParams->m_acDevice[0] = '\0'; | |
| chrStorage = strchr(params, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| if(strcmp(params, "rtu") == 0 || strcmp(params, "RTU") == 0){ | |
| // get rtu params | |
| params = chrStorage; | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| strcpy(pa_pRtuParams->m_acDevice, params); | |
| pa_pRtuParams->m_nBaud = (int) forte::core::util::strtol(chrStorage, 0, 10); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| pa_pRtuParams->m_cParity = chrStorage[0]; | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| pa_pRtuParams->m_nDataBit = (int) forte::core::util::strtol(chrStorage, 0, 10); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| pa_pRtuParams->m_nStopBit = (int) forte::core::util::strtol(chrStorage, 0, 10); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| } | |
| else{ | |
| if(strcmp(params, "tcp") == 0 || strcmp(params, "TCP") == 0){ | |
| params = chrStorage; | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| } | |
| if(isIp(params)){ | |
| // TCP connection | |
| strcpy(pa_pTcpParams->m_acIp, params); | |
| pa_pTcpParams->m_nPort = (unsigned int) forte::core::util::strtoul(chrStorage, 0, 10); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| } | |
| else{ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| } | |
| // Get common parameters | |
| pa_pCommonParams->m_nPollFrequency = atol(chrStorage); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| pa_pCommonParams->m_nFuncCode = (unsigned int) forte::core::util::strtoul(chrStorage, 0, 10); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| // Search for optional parameter slave id | |
| char *chrSlave = strchr(chrStorage, ':'); | |
| if(chrSlave != NULL){ | |
| chrSlave++; | |
| if(strchr(chrSlave, ':') != NULL){ | |
| pa_pCommonParams->m_nSlaveId = (unsigned int) forte::core::util::strtoul(chrStorage, 0, 10); | |
| chrStorage = chrSlave; | |
| } | |
| else{ | |
| pa_pCommonParams->m_nSlaveId = 0xFF; | |
| } | |
| } | |
| else{ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| char *readAddresses = chrStorage; | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| // Find read addresses | |
| int paramLen = strlen(readAddresses); | |
| int nrPolls = 0; | |
| int strIndex = -1; | |
| while(strIndex < paramLen - 1){ | |
| strIndex = findNextStartAddress(readAddresses, ++strIndex); | |
| if(strIndex < 0){ | |
| break; | |
| } | |
| pa_pCommonParams->m_nReadStartAddress[nrPolls] = (unsigned int) forte::core::util::strtoul(const_cast<char*>(&readAddresses[strIndex]), 0, 10); | |
| strIndex = findNextStopAddress(readAddresses, strIndex); | |
| pa_pCommonParams->m_nReadNrAddresses[nrPolls] = (unsigned int) forte::core::util::strtoul(const_cast<char*>(&readAddresses[strIndex]), 0, 10) - pa_pCommonParams->m_nReadStartAddress[nrPolls] + 1; | |
| nrPolls++; | |
| } | |
| pa_pCommonParams->m_nNrPolls = nrPolls; | |
| char *writeAddresses = chrStorage; | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage != 0){ | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| } | |
| // Find send addresses | |
| paramLen = strlen(writeAddresses); | |
| int nrSends = 0; | |
| strIndex = -1; | |
| while(strIndex < paramLen - 1){ | |
| strIndex = findNextStartAddress(writeAddresses, ++strIndex); | |
| if(strIndex < 0){ | |
| break; | |
| } | |
| pa_pCommonParams->m_nSendStartAddress[nrSends] = (unsigned int) forte::core::util::strtoul(const_cast<char*>(&writeAddresses[strIndex]), 0, 10); | |
| strIndex = findNextStopAddress(writeAddresses, strIndex); | |
| pa_pCommonParams->m_nSendNrAddresses[nrSends] = (unsigned int) forte::core::util::strtoul(const_cast<char*>(&writeAddresses[strIndex]), 0, 10) - pa_pCommonParams->m_nSendStartAddress[nrSends] + 1; | |
| nrSends++; | |
| } | |
| pa_pCommonParams->m_nNrSends = nrSends; | |
| // Find responseTimeout and byteTimeout | |
| do{ | |
| if(chrStorage == 0){ | |
| break; | |
| } | |
| pa_pCommonParams->m_nResponseTimeout = (unsigned int) forte::core::util::strtoul(chrStorage, 0, 10); | |
| chrStorage = strchr(chrStorage, ':'); | |
| if(chrStorage == 0){ | |
| break; | |
| } | |
| *chrStorage = '\0'; | |
| ++chrStorage; | |
| pa_pCommonParams->m_nByteTimeout = (unsigned int) forte::core::util::strtoul(chrStorage, 0, 10); | |
| } while(0); | |
| if(nrPolls == 0 && nrSends == 0){ | |
| delete[] paramsAddress; | |
| return -1; | |
| } | |
| delete[] paramsAddress; | |
| return 0; | |
| } | |
| int CModbusComLayer::findNextStartAddress(const char* pa_acParam, int pa_nStartIndex){ | |
| if(pa_nStartIndex == 0){ | |
| switch (pa_acParam[pa_nStartIndex]){ | |
| case '0': | |
| case '1': | |
| case '2': | |
| case '3': | |
| case '4': | |
| case '5': | |
| case '6': | |
| case '7': | |
| case '8': | |
| case '9': | |
| return pa_nStartIndex; | |
| } | |
| } | |
| int strLength = strlen(&pa_acParam[pa_nStartIndex]); | |
| const char *pch = strchr(&pa_acParam[pa_nStartIndex], ','); | |
| if(pch != NULL){ | |
| if(pch - &pa_acParam[pa_nStartIndex] < strLength - 1) | |
| return pch - &pa_acParam[0] + 1; | |
| } | |
| return -1; | |
| } | |
| int CModbusComLayer::findNextStopAddress(const char* pa_acParam, int pa_nStartIndex){ | |
| int strLength = strlen(&pa_acParam[pa_nStartIndex]); | |
| const char *pchComma = strchr(&pa_acParam[pa_nStartIndex], ','); | |
| const char *pchDot = strchr(&pa_acParam[pa_nStartIndex], '.'); | |
| if(pchComma != NULL && pchDot != NULL){ | |
| if(pchDot < pchComma) | |
| if(pchDot - &pa_acParam[pa_nStartIndex] < strLength - 2) | |
| return pchDot - &pa_acParam[0] + 2; | |
| } | |
| else if(pchDot != NULL) | |
| if(pchDot - &pa_acParam[pa_nStartIndex] < strLength - 2) | |
| return pchDot - &pa_acParam[0] + 2; | |
| return pa_nStartIndex; | |
| } | |
| bool CModbusComLayer::isIp(const char* pa_acIp){ | |
| char* str = new char[strlen(pa_acIp) + 1]; | |
| strcpy(str, pa_acIp); | |
| char* pch; | |
| int nrPeriods = 0; | |
| pch = strtok(str, "."); | |
| while(pch != NULL){ | |
| nrPeriods++; | |
| if(strlen(pch) > 3){ | |
| delete[] str; | |
| return false; | |
| } | |
| for(unsigned int i = 0; i < strlen(pch); i++){ | |
| if(!forte::core::util::isDigit(pch[i])){ | |
| delete[] str; | |
| return false; | |
| } | |
| } | |
| pch = strtok(NULL, "."); | |
| } | |
| if(nrPeriods != 4){ | |
| delete[] str; | |
| return false; | |
| } | |
| delete[] str; | |
| return true; | |
| } |