| /******************************************************************************* |
| * 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 |
| *******************************************************************************/ |
| |
| #ifndef SRC_MODULES_EMBRICK_BUSCONTROLLER_H_ |
| #define SRC_MODULES_EMBRICK_BUSCONTROLLER_H_ |
| |
| #include <extevhan.h> |
| #include <devlog.h> |
| #include <sys/time.h> |
| #include <stdio.h> |
| #include <math.h> |
| #include <timerha.h> |
| #include <string> |
| #include <pthread.h> |
| #include <fortelist.h> |
| #include "spi.h" |
| #include "pin.h" |
| #include <slave/slave.h> |
| #include <forte_sync.h> |
| #include <forte_sem.h> |
| #include <forte_thread.h> |
| |
| #include <io/device/io_controller_multi.h> |
| |
| const unsigned int TransferBufferLength = 150; |
| const unsigned int SyncGapMultiplicator = 15; |
| const unsigned int SyncGapDuration = (SyncGapMultiplicator - 1) * 36 + 10; |
| |
| class EmbrickBusHandler : public forte::core::io::IODeviceMultiController { |
| friend class EmbrickSlaveHandler; |
| |
| public: |
| explicit EmbrickBusHandler(CDeviceExecution& paDeviceExecution); |
| |
| enum Command { |
| /** |
| * Initializes the slave and assigns an individual address to it. |
| * The slave provides hardware specifications and length information for the data exchange. |
| * The master sends configuration parameter to synchronize transfer timings. |
| */ |
| Init = 2, |
| |
| /** |
| * It enables the slave select signal of the addressed slave. |
| * The subsequent slave waits for initialization. |
| */ |
| SelectNextSlave = 3, |
| |
| /** |
| * It sets and gets the current state, called process image, of the slave. |
| * The amount of exchanged data bytes depends on the functionality of the slave. |
| * If a slave, for example, has 8 digital outputs, the master sends 1 Byte (1 Bit for each digital output) to set the slave state. |
| * Likewise if a slave reads 8 analog values, the slave sends 16 Bytes (2 Bytes for each value) to the master. |
| * The structure of the process image is specified in the emBRICK products manual. |
| * The Data command should be performed at least 20 times per second. |
| */ |
| Data = 10, |
| }; |
| |
| struct Config : forte::core::io::IODeviceController::Config { |
| unsigned int mBusInterface; //!< Selects the SPI interface for the brickBUS. The default value is 1 (selects SPI1). |
| unsigned int mBusSelectPin; //!< Sets the pin, which is connect to the slave select pin of the brickBUS. |
| unsigned long mBusInitSpeed; //!< Sets the SPI speed for the brickBUS during the initialization of the slaves. The default value is 300000 Hz. |
| unsigned long mBusLoopSpeed; //!< Sets the maximal SPI speed for the brickBUS during the runtime updates of the slaves. The default value is 700000 Hz. |
| }; |
| |
| enum HandleType { |
| Bit, |
| Analog, |
| Analog10 |
| }; |
| |
| class HandleDescriptor : public forte::core::io::IODeviceMultiController::HandleDescriptor { |
| public: |
| HandleType mType; |
| uint8_t mOffset; |
| uint8_t mPosition; |
| |
| HandleDescriptor(std::string const &paId, forte::core::io::IOMapper::Direction paDirection, int paSlaveIndex, HandleType paType, uint8_t paOffset, |
| uint8_t paPosition) : |
| forte::core::io::IODeviceMultiController::HandleDescriptor(paId, paDirection, paSlaveIndex), mType(paType), mOffset(paOffset), mPosition(paPosition) { |
| |
| } |
| }; |
| |
| void setConfig(struct forte::core::io::IODeviceController::Config* paConfig); |
| |
| EmbrickSlaveHandler* getSlave(int paIndex); |
| void forceUpdate(int paIndex); |
| |
| void addSlaveHandle(int paIndex, forte::core::io::IOHandle* paHandle); |
| void dropSlaveHandles(int paIndex); |
| protected: |
| const char* init(); |
| void deInit(); |
| |
| forte::core::io::IOHandle* initHandle(forte::core::io::IODeviceController::HandleDescriptor *paHandleDescriptor); |
| |
| void prepareLoop(); |
| virtual void runLoop(); |
| void cleanLoop(); |
| |
| bool transfer(unsigned int paTarget, Command paCmd, unsigned char* paDataSend = |
| nullptr, int paDataSendLength = 0, unsigned char* paDataReceive = nullptr, int paDataReceiveLength = 0, EmbrickSlaveHandler::SlaveStatus* paStatus = nullptr, |
| CSyncObject *paSyncMutex = nullptr); |
| bool broadcast(Command paCmd, unsigned char* paDataSend = |
| nullptr, int paDataSendLength = 0, unsigned char* paDataReceive = nullptr, int paDataReceiveLength = 0) { |
| return transfer(0, paCmd, paDataSend, paDataSendLength, paDataReceive, paDataReceiveLength); |
| } |
| |
| // Config |
| struct Config mConfig; |
| |
| // Timing variables |
| struct timespec mLastLoop; |
| struct timespec mNextLoop; |
| uint64_t mLastTransfer; |
| |
| // Handlers |
| EmbrickSPIHandler *mSpi; |
| EmbrickPinHandler *mSlaveSelect; |
| |
| // Slaves |
| typedef CSinglyLinkedList<EmbrickSlaveHandler *> TSlaveList; |
| TSlaveList *mSlaves; |
| int mSlaveCount; |
| |
| // Sync |
| bool mLoopActive; |
| CSemaphore mForceLoop; |
| CSyncObject mSyncObject; |
| |
| // Error |
| bool checkHandlerError(); |
| |
| // Scheduling |
| struct SEntry { |
| EmbrickSlaveHandler* mSlave; |
| struct timespec mNextDeadline; |
| uint16_t mLastDuration; |
| bool mForced; |
| bool mDelayed; |
| }; |
| struct SEntry **mSList; |
| SEntry *mSNext; |
| |
| private: |
| bool isSlaveAvailable(int paIndex); |
| bool checkSlaveType(int paIndex, int paType); |
| |
| uint64_t micros(); |
| unsigned long millis(); |
| time_t mInitTime; |
| void microsleep(uint64_t paMicroseconds); |
| void addTime(struct timespec& paTs, unsigned long paMicroseconds); |
| |
| unsigned char calcChecksum(unsigned char * paData, int paDataLen); |
| |
| unsigned char mSendBuffer[TransferBufferLength]; |
| unsigned char mRecvBuffer[TransferBufferLength]; |
| |
| static const unsigned char scmChecksumConstant = 0x55; |
| |
| static const char * const scmSlaveUpdateFailed; |
| static const char * const scmNoSlavesFound; |
| }; |
| |
| #endif /* SRC_MODULES_EMBRICK_BUSCONTROLLER_H_ */ |