blob: 79167f910aeda432777eec7c2db2d15a6bf6f1e7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 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:
* Waldemar Eisenmenger, Alois Zoitl - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "sysfsprocint.h"
#include "../../arch/devlog.h"
#include <extevhandlerhelper.h>
#include <criticalregion.h>
#include <string>
using namespace std::literals::string_literals;
const CIEC_STRING CSysFsProcessInterface::scmOK("OK"_STRING);
const CIEC_STRING CSysFsProcessInterface::scmPinInUse("Pin already in use by other FB"_STRING);
const CIEC_STRING CSysFsProcessInterface::scmNotInitialised("FB not initialized"_STRING);
const CIEC_STRING CSysFsProcessInterface::scmError("Error"_STRING);
const CIEC_STRING CSysFsProcessInterface::scmCouldNotRead("Could not read"_STRING);
const CIEC_STRING CSysFsProcessInterface::scmCouldNotWrite("Could not write"_STRING);
CSysFsProcessInterface::CSysFsProcessInterface(forte::core::CFBContainer &paContainer, const SFBInterfaceSpec *paInterfaceSpec,
const CStringDictionary::TStringId paInstanceNameId) :
CProcessInterfaceBase(paContainer, paInterfaceSpec, paInstanceNameId) {
mFile.rdbuf()->pubsetbuf(nullptr, 0); //disable buffer to avoid latency
STATUS() = scmNotInitialised;
}
CSysFsProcessInterface::~CSysFsProcessInterface() {
unexportIO(); //Will unexport everything, so next time FORTE starts it won't fail to initialize.
}
bool CSysFsProcessInterface::setDirection(bool paIsInput) {
bool retVal = false;
std::string fileName = "/sys/class/gpio/gpio"s + static_cast<std::string>(PARAMS()) + "/direction"s;
std::ofstream mDirectionFile;
mDirectionFile.open(fileName.c_str());
if(mDirectionFile.is_open()) {
if(paIsInput) {
mDirectionFile << "in";
} else {
mDirectionFile << "out";
}
if(!mDirectionFile.fail()){
retVal = true;
} else{
DEVLOG_ERROR("[CSysFsProcessInterface::setDirection] Error writing to file %s.\n", fileName.c_str());
}
} else {
DEVLOG_ERROR("[CSysFsProcessInterface::setDirection] Opening file %s failed.\n", fileName.c_str());
}
return retVal;
}
bool CSysFsProcessInterface::exportGPIO() {
bool retVal = false;
std::string fileName = "/sys/class/gpio/export";
std::ofstream mExportFile;
mExportFile.open(fileName.c_str());
if(mExportFile.is_open()) {
mExportFile << PARAMS().c_str();
if(!mExportFile.fail()) {
retVal = true;
} else {
DEVLOG_ERROR("[CSysFsProcessInterface::exportGPIO] Error writing to file %s.\n", fileName.c_str());
}
mExportFile.close();
retVal = true;
} else {
DEVLOG_ERROR("[CSysFsProcessInterface::exportGPIO] Opening file %s failed.\n", fileName.c_str());
}
return retVal;
}
bool CSysFsProcessInterface::valueGPIO(bool paIsInput) {
bool retVal = false;
std::string fileName = "/sys/class/gpio/gpio"s + static_cast<std::string>(PARAMS()) + "/value"s;
if(paIsInput) {
mFile.open(fileName.c_str(), std::fstream::in);
} else {
mFile.open(fileName.c_str(), std::fstream::out);
}
if(mFile.is_open()){
retVal = true;
}else{
DEVLOG_ERROR("[CSysFsProcessInterface::valueGPIO] Opening file %s failed.\n", fileName.c_str());
}
return retVal;
}
bool CSysFsProcessInterface::initialise(bool paIsInput, CEventChainExecutionThread *const) {
bool retVal = false;
if(CSysFsProcessInterface::exportGPIO()) {
CThread::sleepThread(250);
if(CSysFsProcessInterface::setDirection(paIsInput)) {
CThread::sleepThread(250);
if(CSysFsProcessInterface::valueGPIO(paIsInput)) {
if(paIsInput) {
getExtEvHandler<CSysFsProcessInterface::CIOHandler>(*this).registerIXFB(this);
if(!getExtEvHandler<CSysFsProcessInterface::CIOHandler>(*this).isAlive()) {
getExtEvHandler<CSysFsProcessInterface::CIOHandler>(*this).start();
}
}
DEVLOG_DEBUG("[CSysFsProcessInterface::initialise] Pin with PARAM() %s was properly initialized.\n", PARAMS().getValue());
STATUS() = scmOK;
retVal = true;
}
}
}
return retVal;
}
bool CSysFsProcessInterface::unexportIO() {
bool retVal = false;
std::string fileName = "/sys/class/gpio/unexport"s;
std::ofstream mUnExport;
mFile.close();
mUnExport.open(fileName.c_str(), std::fstream::out);
if(mUnExport.is_open()) {
mUnExport << PARAMS().c_str();
if(!mUnExport.fail()) {
retVal = true;
STATUS() = scmOK;
} else {
STATUS() = scmError;
DEVLOG_ERROR("[CSysFsProcessInterface::deinitialise] Error writing PARAMS() to file %s.\n", fileName.c_str());
}
} else {
STATUS() = scmError;
DEVLOG_ERROR("[CSysFsProcessInterface::deinitialise] Opening file %s failed.\n", fileName.c_str());
}
return retVal;
}
bool CSysFsProcessInterface::deinitialise() {
getExtEvHandler<CSysFsProcessInterface::CIOHandler>(*this).unregisterIXFB(this);
return unexportIO();
}
bool CSysFsProcessInterface::readPin() {
return true;
}
bool CSysFsProcessInterface::checkInputData() {
bool retVal = false;
if(mFile.is_open()) {
char binData = 0;
mFile.clear();
mFile.seekg(0, std::ios::beg);
mFile.read(&binData, 1);
if(mFile.fail()) {
STATUS() = scmCouldNotRead;
} else {
bool newData = '0' != binData;
if(newData != IN_X()) {
IN_X() = CIEC_BOOL(newData);
retVal = true;
}
}
} else {
STATUS() = scmNotInitialised;
}
return retVal;
}
bool CSysFsProcessInterface::writePin() {
bool retVal = false;
if(mFile.is_open()) {
mFile.clear();
mFile.seekp(0, std::ios::beg);
unsigned int val = (false != OUT_X()) ? 1 : 0; //if true set the led to full glowing
mFile << val;
if(!mFile.fail()) {
STATUS() = scmOK;
retVal = true;
} else {
DEVLOG_ERROR("[CSysFsProcessInterface::writePin] Could not write %u to output file\n", val);
STATUS() = scmCouldNotWrite;
}
} else {
DEVLOG_ERROR("[CSysFsProcessInterface::writePin] Cannot write to output since the FB was not properly initialized\n");
STATUS() = scmNotInitialised;
}
return retVal;
}
DEFINE_HANDLER(CSysFsProcessInterface::CIOHandler);
CSysFsProcessInterface::CIOHandler::CIOHandler(CDeviceExecution& paDeviceExecution) :
CExternalEventHandler(paDeviceExecution) {
}
CSysFsProcessInterface::CIOHandler::~CIOHandler() {
CCriticalRegion readList(mReadFBListSync);
mReadFBList.clearAll();
end();
}
void CSysFsProcessInterface::CIOHandler::registerIXFB(CSysFsProcessInterface *paFB) {
CCriticalRegion readList(mReadFBListSync);
mReadFBList.pushBack(paFB);
}
void CSysFsProcessInterface::CIOHandler::unregisterIXFB(CSysFsProcessInterface *paFB) {
CCriticalRegion readList(mReadFBListSync);
TReadFBContainer::Iterator itRunner(mReadFBList.begin());
TReadFBContainer::Iterator itRefNode(mReadFBList.end());
TReadFBContainer::Iterator itEnd(mReadFBList.end());
while(itRunner != itEnd) {
if(*itRunner == paFB) {
if(itRefNode == itEnd) {
mReadFBList.popFront();
} else {
mReadFBList.eraseAfter(itRefNode);
}
break;
}
itRefNode = itRunner;
++itRunner;
}
}
void CSysFsProcessInterface::CIOHandler::run() {
while(isAlive()) {
CThread::sleepThread(10);
updateReadData();
}
}
void CSysFsProcessInterface::CIOHandler::updateReadData() {
CCriticalRegion readList(mReadFBListSync);
TReadFBContainer::Iterator itEnd(mReadFBList.end());
for(TReadFBContainer::Iterator itRunner = mReadFBList.begin(); itRunner != itEnd; ++itRunner) {
if((*itRunner)->checkInputData()) {
startNewEventChain(*itRunner);
}
}
}
void CSysFsProcessInterface::CIOHandler::enableHandler() {
//do nothing
}
void CSysFsProcessInterface::CIOHandler::disableHandler() {
end();
}
void CSysFsProcessInterface::CIOHandler::setPriority(int) {
//do nothing
}
int CSysFsProcessInterface::CIOHandler::getPriority() const {
return 0;
}