Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First version of a CVS reader block #223

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/modules/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ forte_add_module(UTILS OFF "FORTE UTILITY FBs")
#############################################################################

forte_add_sourcefile_hcpp(E_STOPWATCH_fbt GetInstancePath_fbt GetInstancePathAndName_fbt)
forte_add_sourcefile_hcpp(OUT_ANY_CONSOLE_fbt GEN_F_MUX_fbt GEN_CSV_WRITER_fbt)
forte_add_sourcefile_hcpp(OUT_ANY_CONSOLE_fbt GEN_F_MUX_fbt GEN_CSV_WRITER_fbt GEN_CSV_READER_fbt)
forte_add_sourcefile_hcpp(GEN_ARRAY2VALUES_fbt GEN_VALUES2ARRAY_fbt GEN_ARRAY2ARRAY_fbt GET_AT_INDEX_fbt SET_AT_INDEX_fbt)
forte_add_sourcefile_hcpp(FB_RANDOM_fbt GET_STRUCT_VALUE_fbt SET_STRUCT_VALUE_fbt)

Expand Down
189 changes: 189 additions & 0 deletions src/modules/utils/GEN_CSV_READER_fbt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*******************************************************************************
* Copyright (c) 2012, 2024 ACIN, fortiss GmbH, Johannes Kepler University Linz,
* Martin Erich Jobst
*
* 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:
* Alois Zoitl, Monika Wenger, Martin Jobst - copy and modified from
* GEN_CSV_READER
*******************************************************************************/
#include "GEN_CSV_READER_fbt.h"
#ifdef FORTE_ENABLE_GENERATED_SOURCE_CPP
#include "GEN_CSV_READER_fbt_gen.cpp"
#endif
#include <errno.h>
#include "devlog.h"
#include "resource.h"
#include "criticalregion.h"

DEFINE_GENERIC_FIRMWARE_FB(GEN_CSV_READER, g_nStringIdGEN_CSV_READER);

const CStringDictionary::TStringId GEN_CSV_READER::scmDataInputNames[] = { g_nStringIdQI, g_nStringIdFILE_NAME };

const CStringDictionary::TStringId GEN_CSV_READER::scmDataInputTypeIds[] = { g_nStringIdBOOL, g_nStringIdSTRING };

const CStringDictionary::TStringId GEN_CSV_READER::scmEventInputNames[] = { g_nStringIdINIT, g_nStringIdREQ };

const CStringDictionary::TStringId GEN_CSV_READER::scmEventOutputNames[] = { g_nStringIdINITO, g_nStringIdCNF };

const CIEC_STRING GEN_CSV_READER::scmOK = "OK"_STRING;
const CIEC_STRING GEN_CSV_READER::scmFileAlreadyOpened = "File already opened"_STRING;
const CIEC_STRING GEN_CSV_READER::scmFileNotOpened = "File not opened"_STRING;

void GEN_CSV_READER::executeEvent(TEventID paEIID, CEventChainExecutionThread *const paECET) {
if(scmEventINITID == paEIID) {
if(QI()) {
openCSVFile();
} else {
closeCSVFile();
}
sendOutputEvent(scmEventINITOID, paECET);
} else if(scmEventREQID == paEIID) {
QO() = QI();
if(QI()) {
readCSVFileLine();
}
sendOutputEvent(scmEventCNFID, paECET);
}
}

GEN_CSV_READER::GEN_CSV_READER(const CStringDictionary::TStringId paInstanceNameId, forte::core::CFBContainer &paContainer) :
CGenFunctionBlock<CFunctionBlock>(paContainer, paInstanceNameId), mDataOutputNames(nullptr), mDataOutputTypeIds(nullptr) {
}

GEN_CSV_READER::~GEN_CSV_READER(){
delete[] mDataOutputNames;
delete[] mDataOutputTypeIds;
closeCSVFile();
}

void GEN_CSV_READER::readInputData(TEventID paEI) {
switch(paEI) {
case scmEventINITID: {
readData(0, *mDIs[0], mDIConns[0]);
readData(1, *mDIs[1], mDIConns[1]);
break;
}
case scmEventREQID: {
readData(0, *mDIs[0], mDIConns[0]);
break;
}
default:
break;
}
}

void GEN_CSV_READER::writeOutputData(TEventID paEO) {
switch(paEO) {
case scmEventINITOID: {
writeData(0, *mDOs[0], mDOConns[0]);
writeData(1, *mDOs[1], mDOConns[1]);
break;
}
case scmEventCNFID: {
writeData(0, *mDOs[0], mDOConns[0]);
writeData(1, *mDOs[1], mDOConns[1]);
for(TPortId i = 2; i < getFBInterfaceSpec().mNumDOs; i++){
writeData(i, *mDOs[i], mDOConns[i]);
}
break;
}
default:
break;
}
}

bool GEN_CSV_READER::createInterfaceSpec(const char *paConfigString, SFBInterfaceSpec &paInterfaceSpec) {
const char *acPos = strrchr(paConfigString, '_');
if(nullptr != acPos){
acPos++;
paInterfaceSpec.mNumDOs = static_cast<TPortId>(forte::core::util::strtoul(acPos, nullptr, 10) + 2); // we have in addition to the SDs a QI and FILE_NAME data inputs

mDataOutputNames = new CStringDictionary::TStringId[paInterfaceSpec.mNumDOs];
mDataOutputTypeIds = new CStringDictionary::TStringId[paInterfaceSpec.mNumDOs];

mDataOutputNames[0] = g_nStringIdQO;
mDataOutputTypeIds[0] = g_nStringIdBOOL;
mDataOutputNames[1] = g_nStringIdSTATUS;
mDataOutputTypeIds[1] = g_nStringIdSTRING;

generateGenericDataPointArrays("RD_", &(mDataOutputTypeIds[2]), &(mDataOutputNames[2]), paInterfaceSpec.mNumDOs - 2);

//create the interface Specification
paInterfaceSpec.mNumEIs = 2;
paInterfaceSpec.mEINames = scmEventInputNames;
paInterfaceSpec.mNumEOs = 2;
paInterfaceSpec.mEONames = scmEventOutputNames;
paInterfaceSpec.mDINames = scmDataInputNames;
paInterfaceSpec.mDIDataTypeNames = scmDataInputTypeIds;
paInterfaceSpec.mNumDOs = 2;
paInterfaceSpec.mDONames = mDataOutputNames;
paInterfaceSpec.mDODataTypeNames = mDataOutputTypeIds;
return true;
}
return false;
}

void GEN_CSV_READER::openCSVFile() {
QO() = false_BOOL;
if(!mCSVFile.is_open()) {
mCSVFile.open(FILE_NAME().getStorage().c_str());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are calling c_str() several times. I would suggest to store the result of the first call and use it later, as FILE_NAME will probably not modified in this function anymore

if(mCSVFile.is_open()) {
QO() = true_BOOL;
STATUS() = scmOK;
DEVLOG_INFO("[GEN_CSV_READER]: File %s successfully opened\n", FILE_NAME().getStorage().c_str());
} else {
const char* errorCode = strerror(errno);
STATUS() = CIEC_STRING(errorCode, strlen(errorCode));
DEVLOG_ERROR("[GEN_CSV_READER]: Couldn't open file %s. Error: %s\n", FILE_NAME().getStorage().c_str(), STATUS().getStorage().c_str());
}
} else {
STATUS() = scmFileAlreadyOpened;
DEVLOG_ERROR("[GEN_CSV_READER]: Can't open file %s since it is already opened\n", FILE_NAME().getStorage().c_str());
}
}

void GEN_CSV_READER::closeCSVFile() {
QO() = CIEC_BOOL(false);
mCSVFile.close();
STATUS() = scmOK;
DEVLOG_INFO("[GEN_CSV_READER]: File %s successfully closed\n", FILE_NAME().getStorage().c_str());
}

void GEN_CSV_READER::readCSVFileLine() {
if(mCSVFile.is_open()) {
std::string line;
if(getline(mCSVFile, line)){
std::size_t oldPos = 0;

for(std::size_t i = 0; i < getNumRD(); i++) {
std::size_t newPos = line.find(';', oldPos);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seeing this, you implicitly assume a German-language CSV file, correct?
English-language (and several others) CSVs use the comma ',' as the separator.
In the current version the use of the CSV Reader is limited to German-language (or others using the semicolon as separator) CSVs. I would suggest to extract the separator to an additional input for the FB, enhancing usability of the FB

if (newPos != std::string::npos){
std::string value = line.substr(oldPos, newPos - oldPos);
getDI(i+2)->unwrap().fromString(value.c_str());
} else if (oldPos < line.length()){
std::string value = line.substr(oldPos);
getDI(i+2)->unwrap().fromString(value.c_str());
} else {
CIEC_ANY *value = CTypeLib::createDataTypeInstance(getDI(i+2)->getTypeNameID(), nullptr);
if (value) { getDI(i+2)->setValue(*value); }
delete value;
}
oldPos = newPos + 1;
}
QO() = true_BOOL;
} else {
QO() = false_BOOL;
STATUS() = "Could not read line!"_STRING;
}
} else {
QO() = false_BOOL;
STATUS() = scmFileNotOpened;
DEVLOG_ERROR("[GEN_CSV_READER]: Can't write to file %s since it is not opened\n", FILE_NAME().getStorage().c_str());
}
}
87 changes: 87 additions & 0 deletions src/modules/utils/GEN_CSV_READER_fbt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2012, 2024 ACIN, fortiss GmbH, Johannes Kepler University Linz,
* Martin Erich Jobst
*
* 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:
* Alois Zoitl, Monika Wenger, Martin Jobst - copy and modified from
* GEN_CSV_WRITER
*******************************************************************************/
#pragma once

#include "genfb.h"
#include <stdio.h>
#include "../../arch/forte_fileio.h"
#include <vector>
#include <fstream>
#include <iostream>

class GEN_CSV_READER : public CGenFunctionBlock<CFunctionBlock> {
DECLARE_GENERIC_FIRMWARE_FB(GEN_CSV_READER)

protected:
CIEC_BOOL &QI(){
return *static_cast<CIEC_BOOL*>(getDI(0));
}

CIEC_STRING &FILE_NAME(){
return *static_cast<CIEC_STRING*>(getDI(1));
}

static const CStringDictionary::TStringId scmDataInputNames[];
static const CStringDictionary::TStringId scmDataInputTypeIds[];

CIEC_BOOL &QO(){
return *static_cast<CIEC_BOOL*>(getDO(0));
}

CIEC_STRING &STATUS(){
return *static_cast<CIEC_STRING*>(getDO(1));
}

TPortId getNumRD() const {
return getFBInterfaceSpec().mNumDOs - 2;
}

static const TEventID scmEventINITID = 0;
static const TEventID scmEventREQID = 1;
static const CStringDictionary::TStringId scmEventInputNames[];

static const TEventID scmEventINITOID = 0;
static const TEventID scmEventCNFID = 1;
static const CStringDictionary::TStringId scmEventOutputNames[];

void executeEvent(TEventID paEIID, CEventChainExecutionThread *const paECET) override;

void readInputData(TEventID paEI) override;
void writeOutputData(TEventID paEO) override;

bool createInterfaceSpec(const char *paConfigString, SFBInterfaceSpec &paInterfaceSpec) override;

public:
GEN_CSV_READER(const CStringDictionary::TStringId paInstanceNameId, forte::core::CFBContainer &paContainer);
~GEN_CSV_READER() override;

private:

void openCSVFile();
void closeCSVFile();
void readCSVFileLine();

std::ifstream mCSVFile;

CStringDictionary::TStringId *mDataOutputNames;
CStringDictionary::TStringId *mDataOutputTypeIds;

static const CIEC_STRING scmOK;
static const CIEC_STRING scmFileAlreadyOpened;
static const CIEC_STRING scmFileNotOpened;

std::vector<char> writeBuffer;

};