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

Improve Python Object Rep #92

Open
wants to merge 49 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
14d3550
Initial work off of valgur's branch
riley-kinahan Jan 21, 2025
948cb18
Change imports
riley-kinahan Jan 23, 2025
657043c
update binding methodology
riley-kinahan Jan 24, 2025
0abd032
Get to_dict working
riley-kinahan Jan 24, 2025
1a38853
Field type working
riley-kinahan Jan 24, 2025
7613981
Benchmark
riley-kinahan Jan 27, 2025
8f4db98
Update for tests
riley-kinahan Jan 27, 2025
77c4937
Update encoder and tests
riley-kinahan Jan 27, 2025
9e6e967
Fix most tests
riley-kinahan Jan 27, 2025
19b05a5
Readd decode functions
riley-kinahan Jan 27, 2025
5200c3e
Cleanup comments
riley-kinahan Jan 27, 2025
6445487
undo formatting
riley-kinahan Jan 27, 2025
e3c40fb
Cleanup message database code
riley-kinahan Jan 27, 2025
a87aa65
Imporve dir implementation
riley-kinahan Jan 27, 2025
fa5b415
Finish example
riley-kinahan Jan 27, 2025
bd587d0
add submodules
riley-kinahan Jan 27, 2025
78c969a
optimize field conversion
riley-kinahan Jan 28, 2025
6679f4d
Fix dir breaking change
riley-kinahan Jan 28, 2025
4e93e24
Remove unused imports
riley-kinahan Jan 28, 2025
624ccc0
Fix formatting
riley-kinahan Jan 28, 2025
4fe44f9
doc updates
riley-kinahan Jan 30, 2025
0ceb529
rename for consistency
riley-kinahan Jan 30, 2025
6749e82
use this->
riley-kinahan Jan 31, 2025
2245766
Add custom installer
riley-kinahan Jan 29, 2025
90d2fdc
Stubs almost working
riley-kinahan Jan 29, 2025
cb1ccb6
Working with subfields
riley-kinahan Jan 30, 2025
6723c79
Prototype
riley-kinahan Feb 5, 2025
69eb4bd
Fix delimiters
riley-kinahan Feb 5, 2025
ae61e5f
Fix unit tests
riley-kinahan Feb 5, 2025
622b198
Fix cmake formatting
riley-kinahan Feb 5, 2025
1b7ac46
Change database ref
riley-kinahan Feb 5, 2025
356398d
Update remaining old db path refs
riley-kinahan Feb 5, 2025
3e6de4f
Backwards compatible union hint
riley-kinahan Feb 5, 2025
230357e
try different image
riley-kinahan Feb 5, 2025
8839f0b
Disable incompatible runners
riley-kinahan Feb 5, 2025
ef22a5d
Delete dead code
riley-kinahan Feb 5, 2025
3c0a319
Add docs to C++
riley-kinahan Feb 5, 2025
7ebc838
Add docstrings
riley-kinahan Feb 5, 2025
73d18b6
fix remaining jsondb refs
riley-kinahan Feb 6, 2025
99f94ce
Update python/CMakeLists.txt
riley-kinahan Feb 6, 2025
7904e6c
Update python/bindings/message_database.cpp
riley-kinahan Feb 6, 2025
0068ebf
Add out to gitignore
riley-kinahan Feb 6, 2025
50a0b1c
Expand .gitignore
riley-kinahan Feb 6, 2025
6ef506d
nicer text formatting
riley-kinahan Feb 6, 2025
8ec99ba
Fix compliler warning
riley-kinahan Feb 6, 2025
6423c27
Add type hinting support - drop PyMessage subclasses (#97)
valgur Feb 6, 2025
4480f16
get substruct working
riley-kinahan Feb 6, 2025
caec6d4
Integrate body into message
riley-kinahan Feb 6, 2025
12f0dfd
Fix example
riley-kinahan Feb 6, 2025
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 python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ nanobind_add_module(python_bindings
${CMAKE_CURRENT_SOURCE_DIR}/bindings/message_decoder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/nexcept.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/oem_common.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/oem_enums.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/init_modules.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/parser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/range_decompressor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bindings/rxconfig_handler.cpp
Expand Down
10 changes: 7 additions & 3 deletions python/bindings/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ void init_novatel_framer(nb::module_&);
void init_novatel_header_decoder(nb::module_&);
void init_novatel_message_decoder(nb::module_&);
void init_novatel_oem_enums(nb::module_&);
void init_novatel_oem_messages(nb::module_&);
void init_novatel_parser(nb::module_&);
void init_novatel_range_decompressor(nb::module_&);
void init_novatel_rxconfig_handler(nb::module_&);
Expand All @@ -25,7 +26,6 @@ NB_MODULE(bindings, m)
init_common_common(m);
init_common_logger(m);
init_common_json_db_reader(m);
init_common_message_database(m);
init_common_nexcept(m);
init_novatel_commander(m);
init_novatel_common(m);
Expand All @@ -35,8 +35,12 @@ NB_MODULE(bindings, m)
init_novatel_framer(m);
init_novatel_header_decoder(m);
init_novatel_message_decoder(m);
init_novatel_oem_enums(m);
init_common_message_database(m);
init_novatel_parser(m);
init_novatel_range_decompressor(m);
init_novatel_rxconfig_handler(m);
init_novatel_range_decompressor(m);
nb::module_ messages_mod = m.def_submodule("messages", "NovAtel OEM message definitions.");
init_novatel_oem_messages(messages_mod);
nb::module_ enums_mod = m.def_submodule("enums", "Enumerations used by NovAtel OEM message fields.");
init_novatel_oem_enums(enums_mod);
}
10 changes: 6 additions & 4 deletions python/bindings/encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ void init_novatel_encoder(nb::module_& m)
.def_prop_ro("logger", [](const oem::Encoder& encoder) { return encoder.GetLogger(); })
.def(
"encode",
[](oem::Encoder& encoder, const oem::IntermediateHeader& header, const oem::PyDecodedMessage& py_message,
[](oem::Encoder& encoder, const oem::PyMessage& py_message,
const oem::MetaDataStruct& metadata, ENCODE_FORMAT format) {
MessageDataStruct message_data;
oem::IntermediateHeader* header_cinst = nb::inst_ptr<oem::IntermediateHeader>(py_message.header);
oem::PyMessageBody* body_cinst = nb::inst_ptr<oem::PyMessageBody>(py_message.message_body);
if (format == ENCODE_FORMAT::JSON)
{
// Allocate more space for JSON messages.
Expand All @@ -31,17 +33,17 @@ void init_novatel_encoder(nb::module_& m)
uint8_t buffer[MESSAGE_SIZE_MAX * 3];
auto* buf_ptr = reinterpret_cast<uint8_t*>(&buffer);
uint32_t buf_size = MESSAGE_SIZE_MAX * 3;
STATUS status = encoder.Encode(&buf_ptr, buf_size, header, py_message.fields, message_data, metadata, format);
STATUS status = encoder.Encode(&buf_ptr, buf_size, *header_cinst, body_cinst->fields, message_data, metadata, format);
return nb::make_tuple(status, oem::PyMessageData(message_data));
}
else
{
uint8_t buffer[MESSAGE_SIZE_MAX];
auto buf_ptr = reinterpret_cast<uint8_t*>(&buffer);
uint32_t buf_size = MESSAGE_SIZE_MAX;
STATUS status = encoder.Encode(&buf_ptr, buf_size, header, py_message.fields, message_data, metadata, format);
STATUS status = encoder.Encode(&buf_ptr, buf_size, *header_cinst, body_cinst->fields, message_data, metadata, format);
return nb::make_tuple(status, oem::PyMessageData(message_data));
}
},
"header"_a, "message"_a, "metadata"_a, "encode_format"_a);
"message"_a, "metadata"_a, "encode_format"_a);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ using namespace novatel::edie;

void init_novatel_oem_enums(nb::module_& m)
{
nb::module_ enums_mod = m.def_submodule("enums", "Enumerations used by NovAtel OEM message fields.");
for (const auto& [name, enum_type] : MessageDbSingleton::get()->GetEnumsByNameDict()) //
{
enums_mod.attr(name.c_str()) = enum_type;
m.attr(name.c_str()) = enum_type;
}
}

void init_novatel_oem_messages(nb::module_& m)
{
for (const auto& [name, message_type] : MessageDbSingleton::get()->GetMessagesByNameDict())
{
m.attr(name.c_str()) = message_type;
}
}
66 changes: 62 additions & 4 deletions python/bindings/message_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "bindings_core.hpp"
#include "py_database.hpp"
#include "py_decoded_message.hpp"

namespace nb = nanobind;
using namespace nb::literals;
Expand Down Expand Up @@ -183,26 +184,38 @@ void init_common_message_database(nb::module_& m)
.def("get_msg_def", nb::overload_cast<int32_t>(&PyMessageDatabase::GetMsgDef, nb::const_), "msg_id"_a)
.def("get_enum_def", &PyMessageDatabase::GetEnumDefId, "enum_id"_a)
.def("get_enum_def", &PyMessageDatabase::GetEnumDefName, "enum_name"_a)
.def_prop_ro("enums", &PyMessageDatabase::GetEnumsByNameDict);
.def_prop_ro("enums", &PyMessageDatabase::GetEnumsByNameDict)
.def_prop_ro("messages", &PyMessageDatabase::GetMessagesByNameDict);
}

PyMessageDatabase::PyMessageDatabase() { UpdatePythonEnums(); }
PyMessageDatabase::PyMessageDatabase() {
UpdatePythonEnums();
UpdateMessageTypes();
}

PyMessageDatabase::PyMessageDatabase(std::vector<MessageDefinition::ConstPtr> vMessageDefinitions_,
std::vector<EnumDefinition::ConstPtr> vEnumDefinitions_)
: MessageDatabase(std::move(vMessageDefinitions_), std::move(vEnumDefinitions_))
{
UpdatePythonEnums();
UpdateMessageTypes();
}

PyMessageDatabase::PyMessageDatabase(const MessageDatabase& message_db) noexcept : MessageDatabase(message_db) { UpdatePythonEnums(); }
PyMessageDatabase::PyMessageDatabase(const MessageDatabase& message_db) noexcept : MessageDatabase(message_db) {
UpdatePythonEnums();
UpdateMessageTypes();
}

PyMessageDatabase::PyMessageDatabase(const MessageDatabase&& message_db) noexcept : MessageDatabase(message_db) { UpdatePythonEnums(); }
PyMessageDatabase::PyMessageDatabase(const MessageDatabase&& message_db) noexcept : MessageDatabase(message_db) {
UpdatePythonEnums();
UpdateMessageTypes();
}

void PyMessageDatabase::GenerateMappings()
{
MessageDatabase::GenerateMappings();
UpdatePythonEnums();
UpdateMessageTypes();
}

inline void PyMessageDatabase::UpdatePythonEnums()
Expand All @@ -222,3 +235,48 @@ inline void PyMessageDatabase::UpdatePythonEnums()
enums_by_name[enum_name] = enum_type;
}
}

void PyMessageDatabase::AddFieldType(std::vector<std::shared_ptr<BaseField>> fields, std::string base_name, nb::handle type_constructor,
nb::handle type_tuple, nb::handle type_dict)
{
// rescursively add field types for each field array element within the provided vector
rldoris marked this conversation as resolved.
Show resolved Hide resolved
for (const auto& field : fields) {
if (field->type == FIELD_TYPE::FIELD_ARRAY)
{
auto* field_array_field = dynamic_cast<FieldArrayField*>(field.get());
std::string field_name = base_name + "_" + field_array_field->name + "_Field";
nb::object field_type = type_constructor(field_name, type_tuple, type_dict);
messages_by_name[field_name] = field_type;
AddFieldType(field_array_field->fields, field_name, type_constructor, type_tuple, type_dict);
}
}
}

void PyMessageDatabase::UpdateMessageTypes()
rldoris marked this conversation as resolved.
Show resolved Hide resolved
{
// clear existing definitions
messages_by_name.clear();

// get type constructor
nb::object type_constructor = nb::module_::import_("builtins").attr("type");
// specify the python superclasses for the new message and message body types
nb::tuple type_tuple = nb::make_tuple(nb::type<oem::PyMessage>());
nb::tuple body_type_tuple = nb::make_tuple(nb::type<oem::PyMessageBody>());
// provide no additional attributes via `__dict__`
nb::dict type_dict = nb::dict();

// add message and message body types for each message definition
for (const auto& message_def : MessageDefinitions()) {
nb::object msg_def = type_constructor(message_def->name, type_tuple, type_dict);
messages_by_name[message_def->name] = msg_def;
nb::object msg_body_def = type_constructor(message_def->name + "_Body", body_type_tuple, type_dict);
messages_by_name[message_def->name + "_Body"] = msg_body_def;
// add additional MessageBody types for each field array element within the message definition
AddFieldType(message_def->fields.at(message_def->latestMessageCrc), message_def->name + "_Body", type_constructor, body_type_tuple, type_dict);
}
// provide UNKNOWN types for undecodable messages
nb::object default_msg_def = type_constructor("UNKNOWN", type_tuple, type_dict);
messages_by_name["UNKNOWN"] = default_msg_def;
nb::object default_msg_body_def = type_constructor("UNKNOWN_Body", body_type_tuple, type_dict);
messages_by_name["UNKNOWN_Body"] = default_msg_body_def;
}
Loading
Loading