From 43a167f9fba81489e2dadc432facd10cdb686eb2 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Tue, 19 May 2020 15:50:43 +0200 Subject: [PATCH] make PWM/analog input work --- Firmware/fibre/cpp/endpoints_template.j2 | 27 +++++++++++-------- .../fibre/cpp/include/fibre/introspection.hpp | 24 ++++++++++++++--- Firmware/fibre/cpp/include/fibre/protocol.hpp | 11 ++++++++ Firmware/interface_generator.py | 1 + Firmware/odrive-interface.yaml | 19 ++++++++----- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Firmware/fibre/cpp/endpoints_template.j2 b/Firmware/fibre/cpp/endpoints_template.j2 index 98c5eb1d..8e2bc9e1 100644 --- a/Firmware/fibre/cpp/endpoints_template.j2 +++ b/Firmware/fibre/cpp/endpoints_template.j2 @@ -13,6 +13,8 @@ #ifndef __FIBRE_INTERFACES_HPP #define __FIBRE_INTERFACES_HPP +#include + namespace fibre { const unsigned char embedded_json[] = [[embedded_endpoint_definitions | to_c_string]]; @@ -48,22 +50,25 @@ bool is_endpoint_ref_valid(endpoint_ref_t endpoint_ref) { } } +Introspectable get_property(size_t idx) { + switch (idx) { +[%- for endpoint in endpoints %] +[%- if endpoint.function.name == 'exchange' and endpoint.in_bindings | list == ['obj'] %][# //case [[endpoint.id]]: *(decltype([[endpoint.in_bindings['obj']]])*)buf = [[endpoint.in_bindings['obj']]]; break;#] + case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]); +[%- endif %] +[%- endfor %] + default: return {}; + } +} + bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) { if (endpoint_ref.json_crc != json_crc_) { return false; } - return false; - // TODO: implement - /*cbufptr_t input_buffer{}; - bufptr_t output_buffer{}; - - switch (idx) { -[%- for endpoint in endpoints %] - case [[endpoint.id]]: return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_type]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %]&input_buffer, &output_buffer); -[%- endfor %] - default: return false; - }*/ + Introspectable property = get_property(endpoint_ref.endpoint_id); + const FloatSettableTypeInfo* type_info = dynamic_cast(property.get_type_info()); + return type_info && type_info->set_float(property, value); } } diff --git a/Firmware/fibre/cpp/include/fibre/introspection.hpp b/Firmware/fibre/cpp/include/fibre/introspection.hpp index ac5885f2..6792d9be 100644 --- a/Firmware/fibre/cpp/include/fibre/introspection.hpp +++ b/Firmware/fibre/cpp/include/fibre/introspection.hpp @@ -62,6 +62,8 @@ private: class Introspectable { friend class TypeInfo; public: + Introspectable() {} + /** * @brief Returns an Introspectable object for the attribute referenced by * the specified attribute name. @@ -114,9 +116,11 @@ public: return type_info_ && type_info_->set_string(*this, buffer, length); } -private: - Introspectable() {} + const TypeInfo* get_type_info() { + return type_info_; + } +private: // We use this storage to hold generic small objects. Usually that's a pointer // but sometimes it's an on-demand constructed Property<...>. // Caution: only put objects in here which are trivially copyable, movable @@ -151,6 +155,10 @@ template using maybe_underlying_type_t = typename maybe_underlying_t +struct FloatSettableTypeInfo { + virtual bool set_float(const Introspectable& obj, float val) const { return false; } +}; + /* Built-in type infos ********************************************************/ template @@ -175,10 +183,11 @@ const FibrePropertyTypeInfo> FibrePropertyTypeInfo -struct FibrePropertyTypeInfo> : TypeInfo { +struct FibrePropertyTypeInfo> : FloatSettableTypeInfo, TypeInfo { using TypeInfo::TypeInfo; static const PropertyInfo property_table[]; static const FibrePropertyTypeInfo> singleton; + static const Introspectable make_introspectable(Property obj) { return TypeInfo::make_introspectable(obj, &singleton); } bool get_string(const Introspectable& obj, char* buffer, size_t length) const override { return to_string(static_cast>(as>(obj).read()), buffer, length, 0); @@ -192,6 +201,15 @@ struct FibrePropertyTypeInfo> : TypeInfo { as>(obj).exchange(static_cast(value)); return true; } + + bool set_float(const Introspectable& obj, float val) const override { + maybe_underlying_type_t value; + if (!conversion::set_from_float(val, &value)) { + return false; + } + as>(obj).exchange(static_cast(value)); + return true; + } }; template diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 62cb384f..7f9733aa 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -397,6 +397,17 @@ struct Codec::value>> { } static bool encode(T value, bufptr_t* buffer) { return SimpleSerializer::write(value, &(buffer->begin()), buffer->end()); } }; +template<> struct Codec { + static std::optional decode(cbufptr_t* buffer) { + std::optional val0 = SimpleSerializer::read(&(buffer->begin()), buffer->end()); + std::optional val1 = SimpleSerializer::read(&(buffer->begin()), buffer->end()); + return (val0.has_value() && val1.has_value()) ? std::make_optional(endpoint_ref_t{val1.value(), val0.value()}) : std::nullopt; + } + static bool encode(endpoint_ref_t value, bufptr_t* buffer) { + return SimpleSerializer::write(value.endpoint_id, &(buffer->begin()), buffer->end()) + && SimpleSerializer::write(value.json_crc, &(buffer->begin()), buffer->end()); + } +}; } diff --git a/Firmware/interface_generator.py b/Firmware/interface_generator.py index c0b2148e..7e84afff 100644 --- a/Firmware/interface_generator.py +++ b/Firmware/interface_generator.py @@ -142,6 +142,7 @@ value_types = { 'int16': {'builtin': True, 'fullname': 'int16', 'name': 'int16', 'c_type': 'int16_t'}, 'int32': {'builtin': True, 'fullname': 'int32', 'name': 'int32', 'c_type': 'int32_t'}, 'int64': {'builtin': True, 'fullname': 'int64', 'name': 'int64', 'c_type': 'int64_t'}, + 'endpoint_ref': {'builtin': True, 'fullname': 'endpoint_ref', 'name': 'endpoint_ref', 'c_type': 'endpoint_ref_t'}, } enums = {} diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 59f901b0..854f9588 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -140,12 +140,12 @@ interfaces: unit: A doc: Max current the power supply can sink. You most likely want a non-positive value here. Set to -INFINITY to disable. - #gpio1_pwm_mapping: Endpoint # TODO: disable for ODrive v3.2 and older - #gpio2_pwm_mapping: Endpoint # TODO: disable for ODrive v3.2 and older - #gpio3_pwm_mapping: Endpoint # TODO: disable for ODrive v3.2 and older - #gpio4_pwm_mapping: Endpoint - #gpio3_analog_mapping: Endpoint - #gpio4_analog_mapping: Endpoint + gpio1_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[0]'} # TODO: disable for ODrive v3.2 and older + gpio2_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[1]'} # TODO: disable for ODrive v3.2 and older + gpio3_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[2]'} # TODO: disable for ODrive v3.2 and older + gpio4_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[3]'} + gpio3_analog_mapping: {type: Endpoint, c_name: 'analog_mappings[0]'} + gpio4_analog_mapping: {type: Endpoint, c_name: 'analog_mappings[1]'} user_config_loaded: readonly bool axis0: {type: Axis, c_name: get_axis(0)} @@ -176,6 +176,13 @@ interfaces: functions: set_baud_rate: {in: {baudRate: uint32}} + Endpoint: + c_is_class: False + attributes: + endpoint: endpoint_ref + min: float32 + max: float32 + Axis: c_is_class: True attributes: