| /******************************************************************************* | |
| * Copyright (c) 2016 - 2018 Johannes Messmer (admin@jomess.com), 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: | |
| * 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::MaxUpdateErrors = 50; | |
| EmbrickSlaveHandler::EmbrickSlaveHandler(EmbrickBusHandler* bus, int address, EmbrickSlaveInitPackage init) : | |
| delegate(0), address(address), type((SlaveType) init.deviceId), bus(bus), dataSendLength( | |
| init.dataSendLength), dataReceiveLength(init.dataReceiveLength), status( | |
| NotInitialized), oldStatus(NotInitialized) { | |
| updateSendImage = new unsigned char[dataSendLength]; | |
| updateReceiveImage = new unsigned char[dataReceiveLength]; | |
| updateReceiveImageOld = new unsigned char[dataReceiveLength]; | |
| memset(updateSendImage, 0, dataSendLength); | |
| memset(updateReceiveImage, 0, dataReceiveLength); | |
| memset(updateReceiveImageOld, 0, dataReceiveLength); | |
| updateErrorCounter = 0; | |
| // Default config | |
| config.UpdateInterval = 25; | |
| } | |
| EmbrickSlaveHandler::~EmbrickSlaveHandler() { | |
| dropHandles(); | |
| delete updateSendImage; | |
| delete updateReceiveImage; | |
| delete updateReceiveImageOld; | |
| if (delegate != 0) | |
| delegate->onSlaveDestroy(); | |
| } | |
| void EmbrickSlaveHandler::setConfig(Config config) { | |
| if (config.UpdateInterval < 20) { | |
| DEVLOG_WARNING( | |
| "embrick[EmbrickSlaveHandler]: Configured UpdateInterval not in range (>= 20). Set to 25.\n"); | |
| config.UpdateInterval = 25; | |
| } | |
| this->config = config; | |
| } | |
| EmbrickSlaveHandler* EmbrickSlaveHandler::sendInit(EmbrickBusHandler* bus, int address) { | |
| EmbrickMasterInitPackage masterInit; | |
| masterInit.slaveAddress = (unsigned char) address; | |
| masterInit.syncGapMultiplicator = 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 (!bus->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.dataReceiveLength--; | |
| DEVLOG_INFO( | |
| "emBrick[EmbrickSlaveHandler]: ID - %d, ReceiveLength - %d, SendLength - %d, Producer - %d \n", | |
| initPackage.deviceId, initPackage.dataReceiveLength, | |
| initPackage.dataSendLength, initPackage.producerId); | |
| // Return slave instance | |
| return new EmbrickSlaveHandler(bus, address, initPackage); | |
| } | |
| int EmbrickSlaveHandler::update() { | |
| // Send update request to bus | |
| if (!bus->transfer(address, EmbrickBusHandler::Data, updateSendImage, dataSendLength, | |
| updateReceiveImage, dataReceiveLength, &status, &updateMutex)) { | |
| updateErrorCounter++; | |
| if (updateErrorCounter % 10 == 0) | |
| DEVLOG_WARNING( | |
| "emBrick[EmbrickSlaveHandler]: Slave %d reached transfer error threshold - %d out of %d\n", | |
| address, updateErrorCounter, MaxUpdateErrors); | |
| return updateErrorCounter <= MaxUpdateErrors ? 0 : -1; | |
| } | |
| // forte::core::IO::IOHandle the received image | |
| { | |
| CCriticalRegion criticalRegion(handleMutex); | |
| TSlaveHandleList::Iterator itEnd = inputs.end(); | |
| for (TSlaveHandleList::Iterator it = inputs.begin(); it != itEnd; ++it) | |
| if ((*it)->hasObserver() && !(*it)->equal(updateReceiveImageOld)) { | |
| // Inform Process Interface about change | |
| (*it)->onChange(); | |
| } | |
| } | |
| // Clone current image to old image | |
| memcpy(updateReceiveImageOld, updateReceiveImage, dataReceiveLength); | |
| // Reset error counter | |
| if (updateErrorCounter > 0) | |
| updateErrorCounter = 0; | |
| // Check status | |
| if (delegate != 0 && oldStatus != status) { | |
| delegate->onSlaveStatus(status, oldStatus); | |
| oldStatus = status; | |
| } | |
| return 1; | |
| } | |
| void EmbrickSlaveHandler::forceUpdate() { | |
| return bus->forceUpdate(index()); | |
| } | |
| void EmbrickSlaveHandler::dropHandles() { | |
| CCriticalRegion criticalRegion(handleMutex); | |
| forte::core::IO::IOMapper& mapper = forte::core::IO::IOMapper::getInstance(); | |
| TSlaveHandleList::Iterator itEnd = inputs.end(); | |
| for (TSlaveHandleList::Iterator it = inputs.begin(); it != itEnd; ++it) { | |
| mapper.deregisterHandle(*it); | |
| delete *it; | |
| } | |
| itEnd = outputs.end(); | |
| for (TSlaveHandleList::Iterator it = outputs.begin(); it != itEnd; ++it) { | |
| mapper.deregisterHandle(*it); | |
| delete *it; | |
| } | |
| inputs.clearAll(); | |
| outputs.clearAll(); | |
| } | |
| void EmbrickSlaveHandler::addHandle(TSlaveHandleList* list, EmbrickSlaveHandle* handle) { | |
| CCriticalRegion criticalRegion(handleMutex); | |
| list->pushBack(handle); | |
| // TODO Maybe send indication event after connecting | |
| } | |
| EmbrickSlaveHandle* EmbrickSlaveHandler::getHandle(TSlaveHandleList* list, int index) { | |
| TSlaveHandleList::Iterator itEnd = list->end(); | |
| int i = 0; | |
| for (TSlaveHandleList::Iterator it = list->begin(); it != itEnd; ++it, i++) | |
| if (index == i) | |
| return *it; | |
| return NULL; | |
| } | |