mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-07-02 05:35:11 +00:00
275
sdv_executables/sdv_vss_util/csv_file_reader.cpp
Normal file
275
sdv_executables/sdv_vss_util/csv_file_reader.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "csv_file_reader.h"
|
||||
|
||||
CCSVFileReader::CCSVFileReader(const std::string& ssFileName, const bool bSilent, const bool bVerbose)
|
||||
{
|
||||
m_silent = bSilent;
|
||||
m_verbose = bVerbose;
|
||||
m_vdSignals.clear();
|
||||
m_bsSignals.clear();
|
||||
if (ssFileName.empty())
|
||||
{
|
||||
Help();
|
||||
return;
|
||||
}
|
||||
else if (!ReadCSVVSSFile(ssFileName))
|
||||
{
|
||||
std::cout << "\nError: '" << ssFileName.c_str() << "' file could not be oppened or has no vss definitions." << std::endl;
|
||||
Help();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CCSVFileReader::Help()
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "-----------------------------------------------------------------------------------------------------------" << std::endl;
|
||||
std::cout << "Required: An excel text file in csv format, the separator should be ';'" << std::endl;
|
||||
std::cout << " [required] Cells must not contain spaces." << std::endl;
|
||||
std::cout << " [required] Column 'Device Type' must be either 'VD' or 'BS'." << std::endl;
|
||||
std::cout << " [required] Column 'vss' must contain a character '.' or can be empty." << std::endl;
|
||||
std::cout << " [required] Column signal direction, either 'RX' or 'TX' or empty." << std::endl;
|
||||
std::cout << " [required] Column signal value type must not be empty." << std::endl;
|
||||
std::cout << " [required] Column 'CAN name' must contain a character '.' (for vehicle device signal)." << std::endl;
|
||||
std::cout << " [required] Last column: in case of vehicle device it is 'CAN name'." << std::endl;
|
||||
std::cout << " [required] Last column: in case of basic service it is avss from vehicle device." << std::endl;
|
||||
std::cout << " [recommended] Cells may be empty. In that case either a default string is created or previous entry is used." << std::endl;
|
||||
std::cout << " [recommended] Column Class name should start with uppercase character." << std::endl;
|
||||
std::cout << " [recommended] Column Function name should start with uppercase character." << std::endl;
|
||||
std::cout << " [recommended] Column Signal name should start with lowercase character." << std::endl;
|
||||
std::cout << "Summary can be found in file 'summary.txt'." << std::endl;
|
||||
std::cout << "Columns:" << std::endl;
|
||||
std::cout << "Device Type ';' Class name ';' Function name ';' Signal name ';' Interface (vss) ';' Direction ';' Signal value type ';' 'CAN name' or Interface(vss)" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "e.g." << std::endl;
|
||||
std::cout << "VD ';' FrontWheel ';' SetAverageAngle ';' averageAngle ';' Vehicle.Chassis.Axle.Row.Wheel.AverageAngle ';' RX ';' float ';' CANMsg.Angle" << std::endl;
|
||||
std::cout << "BS ';' VehicleChassisAxle ';' SetAngleStatus ';' angleStatus ';' Vehicle.Chassis.Axle.Row.Wheel ';' TX ';' uint8_t ';' Vehicle.Chassis.Axle.Row.Wheel" << std::endl;
|
||||
std::cout << "-----------------------------------------------------------------------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
bool CCSVFileReader::ReadCSVVSSFile(const std::string& ssFileName)
|
||||
{
|
||||
std::ifstream file(ssFileName);
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << "'" << ssFileName << "' could not be opened." << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string line;
|
||||
uint32_t index = 1;
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||
ReadLine(line, index++, vssVDColumns::column_end);
|
||||
}
|
||||
file.close();
|
||||
|
||||
if ((m_vdSignals.size() == 0) && (m_bsSignals.size() == 0))
|
||||
{
|
||||
if (!m_silent)
|
||||
{
|
||||
std::cout << "No valid signal definitions found." << std::endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCSVFileReader::ReadLine(const std::string& ssLine, const uint32_t index, size_t endColumn)
|
||||
{
|
||||
std::stringstream ss(ssLine);
|
||||
std::string item;
|
||||
std::vector<std::string> parts;
|
||||
while (std::getline(ss, item, ';'))
|
||||
{
|
||||
item = Trim(item);
|
||||
auto cType = GetCTypeFromIDLType(item); // maybe its a IDL type
|
||||
if (MustNotContainSpaces(item) || (cType.size() != 0))
|
||||
{
|
||||
parts.push_back(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_vdSignals.size() != 0) && (m_bsSignals.size() && !m_silent))
|
||||
{
|
||||
std::cout << "Invalid, contains spaces: '" << item << "'" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parts.size() >= endColumn)
|
||||
{
|
||||
ParseColumns(parts, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCSVFileReader::ParseColumns(const std::vector<std::string>& parts, const uint32_t index)
|
||||
{
|
||||
static std::string vss = "";
|
||||
static sdv::core::ESignalDirection signalDirection = sdv::core::ESignalDirection::sigdir_rx;
|
||||
|
||||
if (parts.size() >= vssVDColumns::column_end)
|
||||
{
|
||||
if (parts[vssVDColumns::column_vssDefinition].size() != 0) // if vss is empty use previous one
|
||||
{
|
||||
vss = parts[vssVDColumns::column_vssDefinition];
|
||||
}
|
||||
if (!MustContainDotOrIsEmpty(vss, false)) // vss can be empty
|
||||
{
|
||||
if ((m_vdSignals.size() != 0) && (m_bsSignals.size() && !m_silent))
|
||||
{
|
||||
std::cout << "Invalid, contains no charatcer '.': '" << vss << "', line number " << std::to_string(index)<< std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
vss = ValidateVSSFormatNumbers(vss);
|
||||
|
||||
if (!parts[vssVDColumns::column_direction].compare("RX"))
|
||||
signalDirection = sdv::core::ESignalDirection::sigdir_rx;
|
||||
if (!parts[vssVDColumns::column_direction].compare("TX"))
|
||||
signalDirection = sdv::core::ESignalDirection::sigdir_tx;
|
||||
|
||||
if (!parts[vssVDColumns::column_type].compare("VD"))
|
||||
{
|
||||
if (AddToExistingVDSignal(m_vdSignals, vss, signalDirection, parts, index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SSignalVDDefinition signal;
|
||||
signal.vssDefinition = vss;
|
||||
signal.signalDirection = signalDirection;
|
||||
signal.className = GenerateDefaultIfEmpty(parts[vssVDColumns::column_className], "ClassName", index);
|
||||
|
||||
if (AddFunctionVDDefinition(signal, parts[vssVDColumns::column_functionName], parts[vssVDColumns::column_signalName],
|
||||
parts[vssVDColumns::column_canSignalName], parts[vssVDColumns::column_signalCType], index))
|
||||
{
|
||||
ValidateVDCodeStyle(signal, m_verbose);
|
||||
m_vdSignals.push_back(signal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AddToExistingBSSignal(m_bsSignals, vss, signalDirection, parts, index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string vssOfVehicleDevice = parts[vssVDColumns::column_vdDefinition];
|
||||
vssOfVehicleDevice = ValidateVSSFormatNumbers(vssOfVehicleDevice);
|
||||
|
||||
SSignalBSDefinition signal;
|
||||
signal.vssDefinition = vss;
|
||||
signal.signalDirection = signalDirection;
|
||||
signal.className = GenerateDefaultIfEmpty(parts[vssVDColumns::column_className], "ClassName", index);
|
||||
signal.vssVDDefinition = vssOfVehicleDevice;
|
||||
if (AddFunctionBSDefinition(signal, parts[vssVDColumns::column_functionName], parts[vssVDColumns::column_signalName],
|
||||
parts[vssVDColumns::column_canSignalName], parts[vssVDColumns::column_signalCType], index))
|
||||
{
|
||||
ValidateBSCodeStyle(signal, m_verbose);
|
||||
m_bsSignals.push_back(signal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CCSVFileReader::AddToExistingVDSignal(std::vector <SSignalVDDefinition>& signals, const std::string& vssDefinition,
|
||||
const sdv::core::ESignalDirection& directionX, const std::vector<std::string>& parts, const uint32_t index)
|
||||
{
|
||||
for (auto& signal : signals)
|
||||
{
|
||||
if ((signal.vssDefinition.compare(vssDefinition) == 0) && (signal.signalDirection == directionX))
|
||||
{
|
||||
if ((signal.className != parts[vssVDColumns::column_className]) && !m_silent)
|
||||
{
|
||||
std::cout << "Signal already found, ignore class name '" << parts[vssVDColumns::column_className] << "', line number " << std::to_string(index) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
AddFunctionVDDefinition(signal, parts[vssVDColumns::column_functionName], parts[vssVDColumns::column_signalName],
|
||||
parts[vssVDColumns::column_canSignalName], parts[vssVDColumns::column_signalCType], index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCSVFileReader::AddToExistingBSSignal(std::vector <SSignalBSDefinition>& signals, const std::string& vssDefinition,
|
||||
const sdv::core::ESignalDirection& directionX, const std::vector<std::string>& parts, const uint32_t index)
|
||||
{
|
||||
for (auto& signal : signals)
|
||||
{
|
||||
if ((signal.vssDefinition.compare(vssDefinition) == 0) && (signal.signalDirection == directionX))
|
||||
{
|
||||
if ((signal.className != parts[vssVDColumns::column_className]) && !m_silent)
|
||||
{
|
||||
std::cout << "Signal already found, ignore class name '" << parts[vssVDColumns::column_className] << "', line number " << std::to_string(index) << std::endl;
|
||||
}
|
||||
|
||||
AddFunctionBSDefinition(signal, parts[vssVDColumns::column_functionName], parts[vssVDColumns::column_signalName],
|
||||
parts[vssVDColumns::column_vdDefinition], parts[vssVDColumns::column_signalCType], index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCSVFileReader::AddFunctionVDDefinition(SSignalVDDefinition& signal, const std::string& functionName, const std::string& signalName,
|
||||
const std::string& canSignalName, const std::string& idlType, const uint32_t index)
|
||||
{
|
||||
if (!MustContainDotOrIsEmpty(canSignalName, true)) // can signal must must not be empty
|
||||
{
|
||||
if ((m_vdSignals.size() != 0) && (m_bsSignals.size() && !m_silent))
|
||||
{
|
||||
std::cout << "Invalid, contains no charatcer '.' or is empty: '" << canSignalName << "', line number " << std::to_string(index) << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cType = GetCTypeFromIDLType(idlType);
|
||||
if ((cType.size() == 0) && !m_silent)
|
||||
{
|
||||
std::cout << "Invalid, idl type unknown: '" << idlType << "', line number " << std::to_string(index) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SFunctionVDDefinition func;
|
||||
func.functionName = GenerateDefaultIfEmpty(functionName, "FunctionName", index);
|
||||
func.signalName = GenerateDefaultIfEmpty(signalName, "variableName", index);
|
||||
func.canSignalName = canSignalName;
|
||||
func.idlType = idlType;
|
||||
|
||||
ValidateVDCodeStyle(func, m_verbose);
|
||||
signal.vecFunctions.push_back(func);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool CCSVFileReader::AddFunctionBSDefinition(SSignalBSDefinition& signal, const std::string& functionName, const std::string& signalName,
|
||||
const std::string& canSignalName, const std::string& idlType, const uint32_t index)
|
||||
{
|
||||
if (!MustContainDotOrIsEmpty(canSignalName, true)) // can signal must must not be empty
|
||||
{
|
||||
if ((m_vdSignals.size() != 0) && (m_bsSignals.size() && !m_silent))
|
||||
{
|
||||
std::cout << "Invalid, contains no charatcer '.' or is empty: '" << canSignalName << "', line number " << std::to_string(index) << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cType = GetCTypeFromIDLType(idlType);
|
||||
if ((cType.size() == 0) && !m_silent)
|
||||
{
|
||||
std::cout << "Invalid, idl type unknown: '" << idlType << "', line number " << std::to_string(index) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SFunctionBSDefinition func;
|
||||
func.functionName = GenerateDefaultIfEmpty(functionName, "FunctionName", index);
|
||||
func.signalName = GenerateDefaultIfEmpty(signalName, "variableName", index);
|
||||
func.idlType = idlType;
|
||||
|
||||
ValidateBSCodeStyle(func, m_verbose);
|
||||
signal.vecFunctions.push_back(func);
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user