Skip to content

Commit

Permalink
Wip support for txth reader
Browse files Browse the repository at this point in the history
Signed-off-by: Timm Ruppert <[email protected]>
  • Loading branch information
TimmRuppert committed Oct 29, 2024
1 parent 292d220 commit 411458e
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@ cmake-build-*/

# Local build tool output
local_build_tools/*.html

# trace file
*.osi
*.txth
*.mcap
5 changes: 5 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
# Create executables for each example
add_executable(example_mcap_writer example_mcap_writer.cpp)
add_executable(example_native_binary_reader example_native_binary_reader.cpp)
add_executable(example_text_reader example_text_reader.cpp)
add_executable(convert_osi2mcap convert_osi2mcap.cpp)

# Link against OSI made available by parent CMakeLists.txt
if(LINK_WITH_SHARED_OSI)
target_link_libraries(example_mcap_writer PRIVATE open_simulation_interface)
target_link_libraries(example_native_binary_reader PRIVATE open_simulation_interface)
target_link_libraries(example_text_reader PRIVATE open_simulation_interface)
target_link_libraries(convert_osi2mcap PRIVATE open_simulation_interface)
else()
target_link_libraries(example_mcap_writer PRIVATE open_simulation_interface_pic)
target_link_libraries(example_native_binary_reader PRIVATE open_simulation_interface_pic)
target_link_libraries(example_text_reader PRIVATE open_simulation_interface_pic)
target_link_libraries(convert_osi2mcap PRIVATE open_simulation_interface_pic)
include_directories(${OSI_INCLUDE_DIR})
endif()

# Link each example against the library
target_link_libraries(example_mcap_writer PRIVATE OSIUtilities)
target_link_libraries(example_native_binary_reader PRIVATE OSIUtilities)
target_link_libraries(example_text_reader PRIVATE OSIUtilities)
target_link_libraries(convert_osi2mcap PRIVATE OSIUtilities)

# Specify the public headers for the library for clean access
target_include_directories(example_mcap_writer PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(example_native_binary_reader PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(example_text_reader PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(convert_osi2mcap PUBLIC ${PROJECT_SOURCE_DIR}/include)
166 changes: 166 additions & 0 deletions examples/example_text_reader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//
// Copyright (c) 2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// SPDX-License-Identifier: MPL-2.0
//

#include <osi-utilities/tracefile/TextTraceFileReader.h>

#include "osi_groundtruth.pb.h"
#include "osi_sensordata.pb.h"
#include "osi_sensorview.pb.h"
#include "osi_hostvehicledata.pb.h"
#include "osi_trafficcommand.pb.h"
#include "osi_trafficcommandupdate.pb.h"
#include "osi_trafficupdate.pb.h"
#include "osi_motionrequest.pb.h"
#include "osi_streamingupdate.pb.h"

#include <optional>

template <typename T>
void PrintTimestamp(T msg) {
auto timestamp = msg->timestamp().seconds() + msg->timestamp().nanos() / 1000000000.0;
std::cout << "Type: " << msg->descriptor()->full_name() << " Timestamp " << timestamp << "\n";
}


void CastMsgAndPrintTimestamp(const std::optional<osi3::ReadResult>& reading_result)
{
// while reading_result->message_type already contains the correct deserialized OSI message type,
// we need to cast the pointer during runtime to allow multiple different trace files to be read
switch (reading_result->message_type) {
case osi3::ReaderTopLevelMessage::kGroundTruth: {
auto *const ground_truth = dynamic_cast<osi3::GroundTruth*>(reading_result->message.get());
PrintTimestamp(ground_truth);
break;
}
case osi3::ReaderTopLevelMessage::kSensorData: {
auto *const sensor_data = dynamic_cast<osi3::SensorData*>(reading_result->message.get());
PrintTimestamp(sensor_data);
break;
}
case osi3::ReaderTopLevelMessage::kSensorView: {
auto *const sensor_view = dynamic_cast<osi3::SensorView*>(reading_result->message.get());
PrintTimestamp(sensor_view);
break;
}
case osi3::ReaderTopLevelMessage::kHostVehicleData: {
auto *const host_vehicle_data = dynamic_cast<osi3::HostVehicleData*>(reading_result->message.get());
PrintTimestamp(host_vehicle_data);
break;
}
case osi3::ReaderTopLevelMessage::kTrafficCommand: {
auto *const traffic_command = dynamic_cast<osi3::TrafficCommand*>(reading_result->message.get());
PrintTimestamp(traffic_command);
break;
}
case osi3::ReaderTopLevelMessage::kTrafficCommandUpdate: {
auto *const traffic_command_update = dynamic_cast<osi3::TrafficCommandUpdate*>(reading_result->message.get());
PrintTimestamp(traffic_command_update);
break;
}
case osi3::ReaderTopLevelMessage::kTrafficUpdate: {
auto *const traffic_update = dynamic_cast<osi3::TrafficUpdate*>(reading_result->message.get());
PrintTimestamp(traffic_update);
break;
}
case osi3::ReaderTopLevelMessage::kMotionRequest: {
auto *const motion_request = dynamic_cast<osi3::MotionRequest*>(reading_result->message.get());
PrintTimestamp(motion_request);
break;
}
case osi3::ReaderTopLevelMessage::kStreamingUpdate: {
auto *const streaming_update = dynamic_cast<osi3::StreamingUpdate*>(reading_result->message.get());
PrintTimestamp(streaming_update);
break;
}
default: {
std::cout << "Could not determine type of message" << std::endl;
break;
}
}
}

struct ProgramOptions {
std::string file_path;
osi3::ReaderTopLevelMessage message_type = osi3::ReaderTopLevelMessage::kUnknown;
};

const std::unordered_map<std::string, osi3::ReaderTopLevelMessage> kValidTypes = {
{"GroundTruth", osi3::ReaderTopLevelMessage::kGroundTruth},
{"SensorData", osi3::ReaderTopLevelMessage::kSensorData},
{"SensorView", osi3::ReaderTopLevelMessage::kSensorView},
{"SensorViewConfiguration", osi3::ReaderTopLevelMessage::kSensorViewConfiguration},
{"HostVehicleData", osi3::ReaderTopLevelMessage::kHostVehicleData},
{"TrafficCommand", osi3::ReaderTopLevelMessage::kTrafficCommand},
{"TrafficCommandUpdate", osi3::ReaderTopLevelMessage::kTrafficCommandUpdate},
{"TrafficUpdate", osi3::ReaderTopLevelMessage::kTrafficUpdate},
{"MotionRequest", osi3::ReaderTopLevelMessage::kMotionRequest},
{"StreamingUpdate", osi3::ReaderTopLevelMessage::kStreamingUpdate}
};

void printHelp() {
std::cout << "Usage: example_text_reader.cpp <file_path> [--type <message_type>]\n\n"
<< "Arguments:\n"
<< " file_path Path to the txth trace file\n"
<< " --type <message_type> Optional: Specify messages type if not stated in filename\n\n"
<< "Valid message types:\n";
for (const auto& [type, _] : kValidTypes) {
std::cout << " " << type << "\n";
}
}

std::optional<ProgramOptions> parseArgs(const int argc, const char** argv) {
if (argc < 2 || std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h") {
printHelp();
return std::nullopt;
}

ProgramOptions options;
options.file_path = argv[1];
options.message_type = osi3::ReaderTopLevelMessage::kUnknown;

for (int i = 2; i < argc; i++) {
if (std::string arg = argv[i]; arg == "--type" && i + 1 < argc) {
const std::string type_str = argv[++i];
auto types_it = kValidTypes.find(type_str);
if (types_it == kValidTypes.end()) {
std::cerr << "Error: Invalid message type '" << type_str << "'\n\n";
printHelp();
return std::nullopt;
}
options.message_type = types_it->second;
}
}

return options;
}


int main(const int argc, const char** argv) {
// Parse program options
const auto options = parseArgs(argc, argv);
if (!options) {
return 1;
}

// Open the trace file
// downstream functions of Open will guess the message type from the filename (options->message_type has the unknown value)
// or use the provided cli argument value for the message type
auto tracefile_reader = osi3::TextTraceFileReader();
if (!tracefile_reader.Open(options->file_path, options->message_type)) {
std::cerr << "Error: Could not open file '" << options->file_path << "'\n\n";
return 1;
}
std::cout << "Opened file " << options->file_path << std::endl;

// Continuously read messages from file
while (tracefile_reader.HasNext()) {
std::cout << "reading next message\n";
const auto reading_result = tracefile_reader.ReadMessage();
CastMsgAndPrintTimestamp(reading_result);
}

std::cout << "Finished native binary reader example" << std::endl;
return 0;
}
6 changes: 3 additions & 3 deletions include/osi-utilities/tracefile/NativeBinaryTraceFileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

namespace osi3 {


/**
* @brief Function type for parsing binary messages into protobuf objects
* @brief Function type for parsing binary buffers (as char vector) into protobuf objects
*/
using MessageParserFunc = std::function<std::unique_ptr<google::protobuf::Message>(const std::vector<char>&)>;


/**
* @brief Reader implementation for native binary OSI trace files
*/
Expand Down Expand Up @@ -45,7 +45,7 @@ class NativeBinaryTraceFileReader final : public osi3::TraceFileReader {
private:
std::ifstream trace_file_; /**< File stream for reading */
MessageParserFunc parser_; /**< Message parsing function */
ReaderTopLevelMessage message_type_ = ReaderTopLevelMessage::kUnknown; /**< Current message type */
ReaderTopLevelMessage message_type_{ReaderTopLevelMessage::kUnknown}; /**< Current message type */

/**
* @brief Reads raw binary message data from file
Expand Down
17 changes: 17 additions & 0 deletions include/osi-utilities/tracefile/Reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ enum class ReaderTopLevelMessage : u_int8_t
kStreamingUpdate, /**< OSI3::StreamingUpdate */
};

/**
* @brief Map of trace file names to their corresponding message type
*/
const std::unordered_map<std::string, osi3::ReaderTopLevelMessage> kMessageTypeMap = {
{"_gt_", osi3::ReaderTopLevelMessage::kGroundTruth},
{"_sd_", osi3::ReaderTopLevelMessage::kSensorData},
{"_sv_", osi3::ReaderTopLevelMessage::kSensorView},
{"_svc_", osi3::ReaderTopLevelMessage::kSensorViewConfiguration},
{"_hvd_", osi3::ReaderTopLevelMessage::kHostVehicleData},
{"_tc_", osi3::ReaderTopLevelMessage::kTrafficCommand},
{"_tcu_", osi3::ReaderTopLevelMessage::kTrafficCommandUpdate},
{"_tu_", osi3::ReaderTopLevelMessage::kTrafficUpdate},
{"_mr_", osi3::ReaderTopLevelMessage::kMotionRequest},
{"_su_", osi3::ReaderTopLevelMessage::kStreamingUpdate}
};


/**
* @brief Structure containing the result of a read operation
*/
Expand Down
41 changes: 41 additions & 0 deletions include/osi-utilities/tracefile/TextTraceFileReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright (c) 2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// SPDX-License-Identifier: MPL-2.0
//

#ifndef TXTHTRACEFILEREADER_H
#define TXTHTRACEFILEREADER_H

#include "Reader.h"
#include <fstream>
#include <functional>

namespace osi3 {

/**
* @brief Function type for parsing protobuf TextFormat strings into protobuf objects
*/
using MessageParserFunc = std::function<std::unique_ptr<google::protobuf::Message>(const std::string&)>;


class TextTraceFileReader final : public TraceFileReader {
public:
bool Open(const std::string& filename) override;
bool Open(const std::string& filename, const ReaderTopLevelMessage message_type);
void Close() override;
bool HasNext() override;
std::optional<ReadResult> ReadMessage() override;

private:
std::ifstream trace_file_;
MessageParserFunc parser_; /**< Message parsing function */
std::string line_indicating_msg_start_="";
ReaderTopLevelMessage message_type_{ReaderTopLevelMessage::kUnknown}; /**< Current message type */
//MessageParserFunc parser_;
std::string ReadNextMessageFromFile();
};

} // namespace osi3


#endif //TXTHTRACEFILEREADER_H
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(OSIUtilities_SRCS
tracefile/MCAPTraceFileWriter.cpp
tracefile/Reader.cpp
tracefile/NativeBinaryTraceFileReader.cpp
tracefile/TextTraceFileReader.cpp

)

Expand Down
29 changes: 3 additions & 26 deletions src/tracefile/NativeBinaryTraceFileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,6 @@ std::unique_ptr<google::protobuf::Message> ParseMessage(const std::vector<char>&
return std::move(msg);
}

const std::unordered_map<std::string, osi3::ReaderTopLevelMessage> kMessageTypeMap = {
{"_gt_", osi3::ReaderTopLevelMessage::kGroundTruth},
{"_sd_", osi3::ReaderTopLevelMessage::kSensorData},
{"_sv_", osi3::ReaderTopLevelMessage::kSensorView},
{"_svc_", osi3::ReaderTopLevelMessage::kSensorViewConfiguration},
{"_hvd_", osi3::ReaderTopLevelMessage::kHostVehicleData},
{"_tc_", osi3::ReaderTopLevelMessage::kTrafficCommand},
{"_tcu_", osi3::ReaderTopLevelMessage::kTrafficCommandUpdate},
{"_tu_", osi3::ReaderTopLevelMessage::kTrafficUpdate},
{"_mr_", osi3::ReaderTopLevelMessage::kMotionRequest},
{"_su_", osi3::ReaderTopLevelMessage::kStreamingUpdate}
};

const std::unordered_map<osi3::ReaderTopLevelMessage, osi3::MessageParserFunc> kParserMap = {
{osi3::ReaderTopLevelMessage::kGroundTruth, [](const std::vector<char>& data) { return ParseMessage<osi3::GroundTruth>(data); }},
{osi3::ReaderTopLevelMessage::kSensorData, [](const std::vector<char>& data) { return ParseMessage<osi3::SensorData>(data); }},
Expand All @@ -54,7 +41,6 @@ const std::unordered_map<osi3::ReaderTopLevelMessage, osi3::MessageParserFunc> k
{osi3::ReaderTopLevelMessage::kStreamingUpdate, [](const std::vector<char>& data) { return ParseMessage<osi3::StreamingUpdate>(data); }}
};


} // unnamed namespace

namespace osi3 {
Expand Down Expand Up @@ -97,14 +83,6 @@ bool NativeBinaryTraceFileReader::Open(const std::string& filename) {

parser_ = kParserMap.at(message_type_);

// if no parser/type was found, return false
if (!parser_) {
std::cerr << "ERROR: Unable to determine message type from the filename '" << filename
<< "'. Please ensure the filename follows the recommended OSI naming conventions as specified in the documentation."
<< std::endl;
return false;
}

trace_file_ = std::ifstream(filename, std::ios::binary);
if (!trace_file_) {
std::cerr << "ERROR: Failed to open trace file: " << filename << std::endl;
Expand Down Expand Up @@ -134,10 +112,9 @@ std::optional<ReadResult> NativeBinaryTraceFileReader::ReadMessage() {
}


std::optional<ReadResult> result;
result.emplace();
result->message = parser_(serialized_msg);
result->message_type = message_type_;
ReadResult result;
result.message = parser_(serialized_msg);
result.message_type = message_type_;

return result;
}
Expand Down
5 changes: 2 additions & 3 deletions src/tracefile/Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@

#include "osi-utilities/tracefile/Reader.h"
#include "osi-utilities/tracefile/NativeBinaryTraceFileReader.h"
#include "osi-utilities/tracefile/TextTraceFileReader.h"

std::unique_ptr<osi3::TraceFileReader> createTraceFileReader(const std::string& format) {
if (format == "mcap") {
throw std::invalid_argument("Format not implemented yet");
//return std::make_unique<MCAPTraceFileReader>();
} else if (format == "osi") {
//throw std::invalid_argument("Format not implemented yet");
return std::make_unique<osi3::NativeBinaryTraceFileReader>();
} else if (format == "txth") {
throw std::invalid_argument("Format not implemented yet");
//return std::make_unique<TxtTraceFileReader>();
return std::make_unique<osi3::TextTraceFileReader>();
} else {
throw std::invalid_argument("Unsupported format: " + format);
}
Expand Down
Loading

0 comments on commit 411458e

Please sign in to comment.