From 32c20a2da1fe75833798c8ff27ad6ed46db144e4 Mon Sep 17 00:00:00 2001 From: Jonathan Diamond Date: Thu, 5 Oct 2023 11:56:12 -0700 Subject: [PATCH 1/4] Add C++ request_version example. --- examples/BUILD | 1 + examples/CMakeLists.txt | 3 +- examples/common/print_message.cc | 21 ++++ examples/common/print_message.h | 2 + examples/request_version/BUILD | 12 ++ examples/request_version/CMakeLists.txt | 3 + examples/request_version/request_version.cc | 116 ++++++++++++++++++++ 7 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 examples/request_version/BUILD create mode 100644 examples/request_version/CMakeLists.txt create mode 100644 examples/request_version/request_version.cc diff --git a/examples/BUILD b/examples/BUILD index 9b535792..ce0020e2 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -6,6 +6,7 @@ filegroup( srcs = [ "//generate_data", "//message_decode", + "//request_version", "//tcp_client", "//udp_client", ] diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index cf83972d..84ffc17b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,8 +1,9 @@ add_subdirectory(common) add_subdirectory(generate_data) -add_subdirectory(message_decode) add_subdirectory(lband_decode) +add_subdirectory(message_decode) +add_subdirectory(request_version) add_subdirectory(tcp_client) add_subdirectory(udp_client) diff --git a/examples/common/print_message.cc b/examples/common/print_message.cc index 33a4b7c7..23c0ae63 100644 --- a/examples/common/print_message.cc +++ b/examples/common/print_message.cc @@ -107,6 +107,17 @@ void PrintMessage(const MessageHeader& header, const void* payload_in) { sv.azimuth_deg); printf(" In solution: %s\n", sv.usage > 0 ? "yes" : "no"); } + } else if (header.message_type == MessageType::VERSION_INFO) { + auto& contents = *reinterpret_cast(payload); + payload += sizeof(contents); + + double system_time = contents.system_time_ns * 1e-9; + printf( + "Version info message @ System time %.3f seconds. [sequence=%u, " + "size=%zu B]\n", + system_time, header.sequence_number, message_size); + printf(" Firmware version: %.*s\n", contents.fw_version_length, + reinterpret_cast(payload)); } else { printf("Received message type %s. [sequence=%u, %zu bytes]\n", to_string(header.message_type), header.sequence_number, @@ -114,6 +125,16 @@ void PrintMessage(const MessageHeader& header, const void* payload_in) { } } +void PrintHex(const void* data, size_t data_len_bytes) { + const uint8_t* data_ptr = static_cast(data); + for (size_t i = 0; i < data_len_bytes; ++i) { + printf("%02x", data_ptr[i]); + if (i < data_len_bytes - 1) { + printf(" "); + } + } +} + } // namespace examples } // namespace fusion_engine } // namespace point_one diff --git a/examples/common/print_message.h b/examples/common/print_message.h index 8b889921..5f8c1986 100644 --- a/examples/common/print_message.h +++ b/examples/common/print_message.h @@ -20,6 +20,8 @@ namespace examples { void PrintMessage(const fusion_engine::messages::MessageHeader& header, const void* payload); +void PrintHex(const void* data, size_t data_len_bytes); + } // namespace examples } // namespace fusion_engine } // namespace point_one diff --git a/examples/request_version/BUILD b/examples/request_version/BUILD new file mode 100644 index 00000000..f98bcbd1 --- /dev/null +++ b/examples/request_version/BUILD @@ -0,0 +1,12 @@ +package(default_visibility = ["//visibility:public"]) + +cc_binary( + name = "request_version", + srcs = [ + "request_version.cc", + ], + deps = [ + "//common:print_message", + "@fusion_engine_client", + ], +) diff --git a/examples/request_version/CMakeLists.txt b/examples/request_version/CMakeLists.txt new file mode 100644 index 00000000..06f12ba4 --- /dev/null +++ b/examples/request_version/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(request_version request_version.cc) +target_link_libraries(request_version PUBLIC fusion_engine_client) +target_link_libraries(request_version PUBLIC print_message) diff --git a/examples/request_version/request_version.cc b/examples/request_version/request_version.cc new file mode 100644 index 00000000..0f147a19 --- /dev/null +++ b/examples/request_version/request_version.cc @@ -0,0 +1,116 @@ +/**************************************************************************/ /** +* @brief Message encode example. +* @file +******************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include "../common/print_message.h" + +using namespace point_one::fusion_engine::examples; +using namespace point_one::fusion_engine::messages; +using namespace point_one::fusion_engine::parsers; + +bool message_found = false; + +int main(int argc, const char* argv[]) { + if (argc != 1) { + printf("Usage: %s\n", argv[0]); + printf(R"EOF( +Simulate sending a version request, and parsing the response. +)EOF"); + return 0; + } + + // Enforce a 4-byte aligned address. + alignas(4) uint8_t storage[4096]; + + ////////////////////////////////////////////////////////////////////////////// + // Write a VersionInfoMessage request. + ////////////////////////////////////////////////////////////////////////////// + + uint8_t* buffer = storage; + auto header = reinterpret_cast(buffer); + buffer += sizeof(MessageHeader); + *header = MessageHeader(); + + header->sequence_number = 0; + header->message_type = MessageType::MESSAGE_REQUEST; + header->payload_size_bytes = sizeof(MessageRequest); + + auto req_message = reinterpret_cast(buffer); + *req_message = MessageRequest(); + + req_message->message_type = VersionInfoMessage::MESSAGE_TYPE; + + header->crc = CalculateCRC(storage); + + printf("Sending VersionInfoMessage request:\n "); + // This data would be sent over serial to the device. + PrintHex(storage, sizeof(MessageHeader) + sizeof(MessageRequest)); + printf("\n"); + + ////////////////////////////////////////////////////////////////////////////// + // Generate an example response + ////////////////////////////////////////////////////////////////////////////// + + static constexpr char VERSION_STR[] = {'t', 'e', 's', 't'}; + + buffer = storage; + header = reinterpret_cast(buffer); + buffer += sizeof(MessageHeader); + *header = MessageHeader(); + + header->sequence_number = 0; + header->message_type = MessageType::VERSION_INFO; + header->payload_size_bytes = sizeof(VersionInfoMessage) + sizeof(VERSION_STR); + + auto version_message = reinterpret_cast(buffer); + *version_message = VersionInfoMessage(); + version_message->fw_version_length = sizeof(VERSION_STR); + buffer += sizeof(VersionInfoMessage); + + char* version_str_ptr = reinterpret_cast(buffer); + // NOTE: Not NULL terminated. + memcpy(version_str_ptr, VERSION_STR, sizeof(VERSION_STR)); + + header->crc = CalculateCRC(storage); + + ////////////////////////////////////////////////////////////////////////////// + // Receive example response + ////////////////////////////////////////////////////////////////////////////// + + printf("Waiting for response\n"); + size_t READ_SIZE = 10; + // We're using this data as if it were received from the device. + buffer = storage; + // In a real application, you'd need to do the bookkeeping to trigger a + // timeout if no response is received after a couple seconds. + bool has_timed_out = false; + + FusionEngineFramer framer(1024); + framer.SetMessageCallback( + [](const MessageHeader& header, const void* payload) { + // Ignore messages besides the expected response type. + if (header.message_type == VersionInfoMessage::MESSAGE_TYPE) { + PrintMessage(header, payload); + message_found = true; + } + }); + + while (!has_timed_out && !message_found) { + // Use the example data as if it were received from the device. + framer.OnData(buffer, READ_SIZE); + buffer += READ_SIZE; + } + + printf("Response received.\n"); + + return 0; +} From 2561cf155903dd5158b40934b92da462a8ae6db1 Mon Sep 17 00:00:00 2001 From: Jonathan Diamond Date: Thu, 5 Oct 2023 12:23:24 -0700 Subject: [PATCH 2/4] Make example more "realistic". --- examples/common/print_message.cc | 1 + examples/request_version/request_version.cc | 42 +++++++++++++++------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/examples/common/print_message.cc b/examples/common/print_message.cc index 23c0ae63..e3d72a73 100644 --- a/examples/common/print_message.cc +++ b/examples/common/print_message.cc @@ -125,6 +125,7 @@ void PrintMessage(const MessageHeader& header, const void* payload_in) { } } +/******************************************************************************/ void PrintHex(const void* data, size_t data_len_bytes) { const uint8_t* data_ptr = static_cast(data); for (size_t i = 0; i < data_len_bytes; ++i) { diff --git a/examples/request_version/request_version.cc b/examples/request_version/request_version.cc index 0f147a19..879fb24d 100644 --- a/examples/request_version/request_version.cc +++ b/examples/request_version/request_version.cc @@ -19,6 +19,27 @@ using namespace point_one::fusion_engine::parsers; bool message_found = false; +// Enforce a 4-byte aligned address. +alignas(4) uint8_t storage[4096]; + +// Fake Send/Receive functions. +/******************************************************************************/ +void SendData(void* data, size_t data_len_bytes) {} + +/******************************************************************************/ +size_t ReceiveData(uint8_t* buffer, size_t read_size) { + static size_t offset = 0; + if (offset + read_size < sizeof(storage)) { + // We're using this data as if it were received from the device. + memcpy(buffer, storage + offset, read_size); + offset += read_size; + return read_size; + } else { + return 0; + } +} + +/******************************************************************************/ int main(int argc, const char* argv[]) { if (argc != 1) { printf("Usage: %s\n", argv[0]); @@ -28,9 +49,6 @@ Simulate sending a version request, and parsing the response. return 0; } - // Enforce a 4-byte aligned address. - alignas(4) uint8_t storage[4096]; - ////////////////////////////////////////////////////////////////////////////// // Write a VersionInfoMessage request. ////////////////////////////////////////////////////////////////////////////// @@ -52,16 +70,19 @@ Simulate sending a version request, and parsing the response. header->crc = CalculateCRC(storage); printf("Sending VersionInfoMessage request:\n "); - // This data would be sent over serial to the device. PrintHex(storage, sizeof(MessageHeader) + sizeof(MessageRequest)); + // This data would be sent over serial to the device. + SendData(storage, sizeof(MessageHeader) + sizeof(MessageRequest)); + printf("\n"); ////////////////////////////////////////////////////////////////////////////// - // Generate an example response + // Generate an example response of the data a device would send back. ////////////////////////////////////////////////////////////////////////////// static constexpr char VERSION_STR[] = {'t', 'e', 's', 't'}; + // @ref ReceiveData will read data from `storage`. buffer = storage; header = reinterpret_cast(buffer); buffer += sizeof(MessageHeader); @@ -83,16 +104,14 @@ Simulate sending a version request, and parsing the response. header->crc = CalculateCRC(storage); ////////////////////////////////////////////////////////////////////////////// - // Receive example response + // Receive example response. ////////////////////////////////////////////////////////////////////////////// printf("Waiting for response\n"); - size_t READ_SIZE = 10; - // We're using this data as if it were received from the device. - buffer = storage; // In a real application, you'd need to do the bookkeeping to trigger a // timeout if no response is received after a couple seconds. bool has_timed_out = false; + uint8_t read_buffer[10]; FusionEngineFramer framer(1024); framer.SetMessageCallback( @@ -105,9 +124,8 @@ Simulate sending a version request, and parsing the response. }); while (!has_timed_out && !message_found) { - // Use the example data as if it were received from the device. - framer.OnData(buffer, READ_SIZE); - buffer += READ_SIZE; + size_t data_read = ReceiveData(read_buffer, sizeof(read_buffer)); + framer.OnData(read_buffer, data_read); } printf("Response received.\n"); From c0cd36c5c90d69aab004a6d0d06e0b97546ecf78 Mon Sep 17 00:00:00 2001 From: Jonathan Diamond Date: Thu, 5 Oct 2023 13:06:08 -0700 Subject: [PATCH 3/4] Address warning. --- examples/request_version/request_version.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/request_version/request_version.cc b/examples/request_version/request_version.cc index 879fb24d..c2b684e6 100644 --- a/examples/request_version/request_version.cc +++ b/examples/request_version/request_version.cc @@ -24,7 +24,10 @@ alignas(4) uint8_t storage[4096]; // Fake Send/Receive functions. /******************************************************************************/ -void SendData(void* data, size_t data_len_bytes) {} +void SendData(void* data, size_t data_len_bytes) { + (void)data; + (void)data_len_bytes; +} /******************************************************************************/ size_t ReceiveData(uint8_t* buffer, size_t read_size) { From d82be6dab0a0f9c9677ff0518a43b5771c67c4f7 Mon Sep 17 00:00:00 2001 From: Jonathan Diamond Date: Thu, 5 Oct 2023 13:15:47 -0700 Subject: [PATCH 4/4] Update documentation. --- README.md | 2 ++ examples/request_version/request_version.cc | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 026085fa..1b039db9 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ The `examples/` directory contains example applications demonstrating how to use - `external_cmake_project` - Download a copy of the FusionEngine Client library from the public repository and import it into a CMake project using `FetchContent`. - `generate_data` - Generate a binary file containing a fixed set of messages. +- `lband_decode` - Example of decoding RTCM corrections from a recorded file containing LBandFrameMessage. +- `request_version` - Simulate sending a request for a version info message, and waiting for a response. - `tcp_client` - Connect to a device over TCP and display the received FusionEngine messages. - `udp_client` - Connect to a device over UDP and display the received FusionEngine messages. diff --git a/examples/request_version/request_version.cc b/examples/request_version/request_version.cc index c2b684e6..eca05435 100644 --- a/examples/request_version/request_version.cc +++ b/examples/request_version/request_version.cc @@ -1,5 +1,6 @@ /**************************************************************************/ /** -* @brief Message encode example. +* @brief Simulate sending a request for a version info message, and waiting for +* a response. * @file ******************************************************************************/