| /******************************************************************************* |
| * Copyright (c) 2016 - 2018 Johannes Messmer (admin@jomess.com), fortiss GmbH |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Johannes Messmer - initial API and implementation and/or initial documentation |
| * Jose Cabral - Cleaning of namespaces |
| *******************************************************************************/ |
| |
| #include "slave.h" |
| #include <handler/bus.h> |
| #include <io/mapper/io_mapper.h> |
| #include <processinterface.h> |
| #include "criticalregion.h" |
| |
| const int EmbrickSlaveHandler::scmMaxUpdateErrors = 50; |
| |
| EmbrickSlaveHandler::EmbrickSlaveHandler(EmbrickBusHandler* paBus, int paAddress, EmbrickSlaveInitPackage paInit) : |
| mDelegate(0), mAddress(paAddress), mType((SlaveType) paInit.mDeviceId), mBus(paBus), mDataSendLength(paInit.mDataSendLength), |
| mDataReceiveLength(paInit.mDataReceiveLength), mStatus(NotInitialized), mOldStatus(NotInitialized) { |
| mUpdateSendImage = new unsigned char[mDataSendLength]; |
| mUpdateReceiveImage = new unsigned char[mDataReceiveLength]; |
| mUpdateReceiveImageOld = new unsigned char[mDataReceiveLength]; |
| |
| memset(mUpdateSendImage, 0, mDataSendLength); |
| memset(mUpdateReceiveImage, 0, mDataReceiveLength); |
| memset(mUpdateReceiveImageOld, 0, mDataReceiveLength); |
| |
| mUpdateErrorCounter = 0; |
| |
| // Default config |
| mConfig.mUpdateInterval = 25; |
| } |
| |
| EmbrickSlaveHandler::~EmbrickSlaveHandler() { |
| dropHandles(); |
| |
| delete mUpdateSendImage; |
| delete mUpdateReceiveImage; |
| delete mUpdateReceiveImageOld; |
| |
| if(mDelegate != 0) { |
| mDelegate->onSlaveDestroy(); |
| } |
| } |
| |
| void EmbrickSlaveHandler::setConfig(Config paConfig) { |
| if(paConfig.mUpdateInterval < 20) { |
| DEVLOG_WARNING("embrick[EmbrickSlaveHandler]: Configured UpdateInterval not in range (>= 20). Set to 25.\n"); |
| paConfig.mUpdateInterval = 25; |
| } |
| |
| this->mConfig = paConfig; |
| } |
| |
| EmbrickSlaveHandler* EmbrickSlaveHandler::sendInit(EmbrickBusHandler* paBus, int paAddress) { |
| EmbrickMasterInitPackage masterInit; |
| masterInit.mSlaveAddress = (unsigned char) paAddress; |
| masterInit.mSyncGapMultiplicator = SyncGapMultiplicator; |
| |
| unsigned char sendBuffer[sizeof(EmbrickMasterInitPackage)]; |
| unsigned char receiveBuffer[sizeof(EmbrickSlaveInitPackage)]; |
| |
| masterInit.toBuffer(sendBuffer); |
| |
| // Send init via broadcast. Due to the sequential slave select activation, only one slave will respond. |
| if(!paBus->broadcast(EmbrickBusHandler::Init, sendBuffer, sizeof(EmbrickMasterInitPackage), receiveBuffer, sizeof(EmbrickSlaveInitPackage))) { |
| return 0; |
| } |
| |
| EmbrickSlaveInitPackage initPackage = EmbrickSlaveInitPackage::fromBuffer(receiveBuffer); |
| |
| // Alter the value of data receive length -> the status byte is handled in the BusHandler |
| initPackage.mDataReceiveLength--; |
| |
| DEVLOG_INFO("emBrick[EmbrickSlaveHandler]: ID - %d, ReceiveLength - %d, SendLength - %d, Producer - %d \n", initPackage.mDeviceId, |
| initPackage.mDataReceiveLength, initPackage.mDataSendLength, initPackage.mProducerId); |
| |
| // Return slave instance |
| return new EmbrickSlaveHandler(paBus, paAddress, initPackage); |
| } |
| |
| int EmbrickSlaveHandler::update() { |
| // Send update request to bus |
| if(!mBus->transfer(mAddress, EmbrickBusHandler::Data, mUpdateSendImage, mDataSendLength, mUpdateReceiveImage, mDataReceiveLength, &mStatus, &mUpdateMutex)) { |
| mUpdateErrorCounter++; |
| if(mUpdateErrorCounter % 10 == 0) { |
| DEVLOG_WARNING("emBrick[EmbrickSlaveHandler]: Slave %d reached transfer error threshold - %d out of %d\n", mAddress, mUpdateErrorCounter, |
| scmMaxUpdateErrors); |
| } |
| return mUpdateErrorCounter <= scmMaxUpdateErrors ? 0 : -1; |
| } |
| |
| // forte::core::IO::IOHandle the received image |
| { |
| CCriticalRegion criticalRegion(mHandleMutex); |
| TSlaveHandleList::Iterator itEnd = mInputs.end(); |
| for(TSlaveHandleList::Iterator it = mInputs.begin(); it != itEnd; ++it) { |
| if((*it)->hasObserver() && !(*it)->equal(mUpdateReceiveImageOld)) { |
| // Inform Process Interface about change |
| (*it)->onChange(); |
| } |
| } |
| } |
| |
| // Clone current image to old image |
| memcpy(mUpdateReceiveImageOld, mUpdateReceiveImage, mDataReceiveLength); |
| |
| // Reset error counter |
| if(mUpdateErrorCounter > 0) { |
| mUpdateErrorCounter = 0; |
| } |
| |
| // Check status |
| if(mDelegate != 0 && mOldStatus != mStatus) { |
| mDelegate->onSlaveStatus(mStatus, mOldStatus); |
| mOldStatus = mStatus; |
| } |
| |
| return 1; |
| } |
| |
| void EmbrickSlaveHandler::forceUpdate() { |
| return mBus->forceUpdate(index()); |
| } |
| |
| void EmbrickSlaveHandler::dropHandles() { |
| CCriticalRegion criticalRegion(mHandleMutex); |
| |
| forte::core::io::IOMapper& mapper = forte::core::io::IOMapper::getInstance(); |
| |
| TSlaveHandleList::Iterator itEnd = mInputs.end(); |
| for(TSlaveHandleList::Iterator it = mInputs.begin(); it != itEnd; ++it) { |
| mapper.deregisterHandle(*it); |
| delete *it; |
| } |
| itEnd = mOutputs.end(); |
| for(TSlaveHandleList::Iterator it = mOutputs.begin(); it != itEnd; ++it) { |
| mapper.deregisterHandle(*it); |
| delete *it; |
| } |
| |
| mInputs.clearAll(); |
| mOutputs.clearAll(); |
| |
| } |
| |
| void EmbrickSlaveHandler::addHandle(TSlaveHandleList* paList, EmbrickSlaveHandle* paHandle) { |
| CCriticalRegion criticalRegion(mHandleMutex); |
| paList->pushBack(paHandle); |
| |
| // TODO Maybe send indication event after connecting |
| } |
| |
| EmbrickSlaveHandle* EmbrickSlaveHandler::getHandle(TSlaveHandleList* paList, int paIndex) { |
| TSlaveHandleList::Iterator itEnd = paList->end(); |
| int i = 0; |
| for(TSlaveHandleList::Iterator it = paList->begin(); it != itEnd; ++it, i++) { |
| if(paIndex == i) { |
| return *it; |
| } |
| } |
| return nullptr; |
| } |
| |