From 3cba81e6f70bdf98f8c04864b2d9fafacdfce5f0 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 6 Nov 2017 14:38:15 +0100 Subject: [PATCH] make remote precedure calls work --- Firmware/MotorControl/commands.cpp | 27 ++++--- Firmware/MotorControl/protocol.cpp | 2 +- Firmware/MotorControl/protocol.hpp | 6 +- tools/demo.py | 4 +- tools/odrive/core.py | 125 ++++++++++++++++++++--------- tools/odrive/protocol.py | 10 +-- tools/test_communication.py | 47 ++++++++--- 7 files changed, 146 insertions(+), 75 deletions(-) diff --git a/Firmware/MotorControl/commands.cpp b/Firmware/MotorControl/commands.cpp index 436889b6..4864beee 100644 --- a/Firmware/MotorControl/commands.cpp +++ b/Firmware/MotorControl/commands.cpp @@ -39,18 +39,21 @@ static const GpioMode_t gpio_mode = GPIO_MODE_UART; //GPIO 1,2 is UART Tx,Rx /* Variables exposed to USB & UART via read/write commands */ // TODO: include range information in JSON description -std::function motors_0_set_pos_setpoint_func = std::bind(set_pos_setpoint, &motors[0], - std::ref(motors[0].set_pos_setpoint_args.pos_setpoint), - std::ref(motors[0].set_pos_setpoint_args.vel_feed_forward), - std::ref(motors[0].set_pos_setpoint_args.current_feed_forward) -); -std::function motors_0_set_vel_setpoint_func = std::bind(set_vel_setpoint, &motors[0], - std::ref(motors[0].set_vel_setpoint_args.vel_setpoint), - std::ref(motors[0].set_vel_setpoint_args.current_feed_forward) -); -std::function motors_0_set_current_setpoint_func = std::bind(set_current_setpoint, &motors[0], - std::ref(motors[0].set_current_setpoint_args.current_setpoint) -); +void motors_0_set_pos_setpoint_func(void) { + set_pos_setpoint(&motors[0], + motors[0].set_pos_setpoint_args.pos_setpoint, + motors[0].set_pos_setpoint_args.vel_feed_forward, + motors[0].set_pos_setpoint_args.current_feed_forward); +} +void motors_0_set_vel_setpoint_func(void) { + set_vel_setpoint(&motors[0], + motors[0].set_vel_setpoint_args.vel_setpoint, + motors[0].set_vel_setpoint_args.current_feed_forward); +} +void motors_0_set_current_setpoint_func(void) { + set_current_setpoint(&motors[0], + motors[0].set_current_setpoint_args.current_setpoint); +} // clang-format off // TODO: Autogenerate this table. It will come up again very soon in the Arduino library. diff --git a/Firmware/MotorControl/protocol.cpp b/Firmware/MotorControl/protocol.cpp index 41b80ccc..09837449 100644 --- a/Firmware/MotorControl/protocol.cpp +++ b/Firmware/MotorControl/protocol.cpp @@ -75,7 +75,7 @@ void Endpoint::write_json(size_t id, bool* need_comma, StreamSink* output) const } if (type_ == BEGIN_OBJECT) { - write_string(",\"content\":[", output); + write_string(",\"members\":[", output); *need_comma = false; } else if (type_ == BEGIN_FUNCTION) { write_string(",\"arguments\":[", output); diff --git a/Firmware/MotorControl/protocol.hpp b/Firmware/MotorControl/protocol.hpp index 17386219..77a6e664 100644 --- a/Firmware/MotorControl/protocol.hpp +++ b/Firmware/MotorControl/protocol.hpp @@ -376,11 +376,9 @@ public: "\"type\":\"object\"", nullptr); } - static Endpoint make_function(const char* name, std::function* function) { - typedef void(f_t)(void); - f_t* f = *function->target(); + static Endpoint make_function(const char* name, void(*function)(void)) { return Endpoint(name, BEGIN_FUNCTION, trigger_endpoint_handler, - "\"type\":\"function\"", reinterpret_cast(f)); + "\"type\":\"function\"", reinterpret_cast(function)); } static Endpoint close_tree() { diff --git a/tools/demo.py b/tools/demo.py index 808d46c6..d8b88615 100755 --- a/tools/demo.py +++ b/tools/demo.py @@ -24,13 +24,15 @@ print("Bus voltage is " + str(my_drive.vbus_voltage) + "V") my_drive.motor0.pos_setpoint = 3.14 print("Position setpoint is " + str(my_drive.motor0.pos_setpoint)) +# And this is how function calls are done: +my_drive.motor0.set_pos_setpoint(0.0, 0.0, 0.0) # little sine wave to test t0 = time.monotonic() while True: setpoint = 10000.0 * math.sin((time.monotonic() - t0)*2) print("goto " + str(int(setpoint))) - my_drive.motor0.pos_setpoint = setpoint + my_drive.motor0.set_pos_setpoint(setpoint, 0.0, 0.0) time.sleep(0.01) diff --git a/tools/odrive/core.py b/tools/odrive/core.py index c8787ce4..e04ea476 100644 --- a/tools/odrive/core.py +++ b/tools/odrive/core.py @@ -18,6 +18,7 @@ import os import odrive.protocol import itertools import struct +import functools def noprint(x): pass @@ -46,57 +47,104 @@ class SimpleDeviceProperty(property): self._channel.remote_endpoint_operation(self._id, buffer, True, 0) -def create_object(json_data, namespace, channel, printer=noprint): + +def call_remote_function(channel, trigger_id, arg_properties, *args): + if (len(arg_properties) != len(args)): + raise TypeError("expected {} arguments but have {}".format(len(arg_properties), len(args))) + for i in range(len(args)): + arg_properties[i].fset(None, args[i]) + channel.remote_endpoint_operation(trigger_id, None, True, 0) + +def raise_if_undefined(self, name, value): + if hasattr(self, name): + object.__setattr__(self, name, value) + else: + raise TypeError('Cannot set name %r on object of type %s' % ( + name, self.__class__.__name__)) + +def create_property(name, json_data, channel, printer): + name = name or "[anonymous]" + + type_str = json_data.get("type", None) + if type_str is None: + printer("property {} has no specified type".format(name)) + return None + + if type_str == "float": + property_type = float + struct_format = "