From 3d13da4e921d9d34e6bacb4303f24de19c3012d9 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Sun, 22 Apr 2018 00:57:14 -0700 Subject: [PATCH] implement function return values on protocol (this time for real) --- Firmware/communication/communication.cpp | 4 +- Firmware/communication/protocol.hpp | 170 ++++++++++------------- 2 files changed, 76 insertions(+), 98 deletions(-) diff --git a/Firmware/communication/communication.cpp b/Firmware/communication/communication.cpp index 8e4f826a..ed2c1d0d 100644 --- a/Firmware/communication/communication.cpp +++ b/Firmware/communication/communication.cpp @@ -92,6 +92,7 @@ public: void NVIC_SystemReset_helper() { NVIC_SystemReset(); } void enter_dfu_mode_helper() { enter_dfu_mode(); } float get_oscilloscope_val(uint32_t index) { return oscilloscope[index]; } + int32_t test_function(int32_t delta) { static int cnt = 0; return cnt += delta; } } static_functions; // When adding new functions/variables to the protocol, be careful not to @@ -120,7 +121,8 @@ static inline auto make_obj_tree() { ), make_protocol_object("axis0", axes[0]->make_protocol_definitions()), make_protocol_object("axis1", axes[1]->make_protocol_definitions()), - make_protocol_function_with_ret("get_oscilloscope_val", static_functions, &StaticFunctions::get_oscilloscope_val, "index"), + make_protocol_function("get_oscilloscope_val", static_functions, &StaticFunctions::get_oscilloscope_val, "index"), + make_protocol_function("test_function", static_functions, &StaticFunctions::test_function, "delta"), make_protocol_function("save_configuration", static_functions, &StaticFunctions::save_configuration_helper), make_protocol_function("erase_configuration", static_functions, &StaticFunctions::erase_configuration_helper), make_protocol_function("reboot", static_functions, &StaticFunctions::NVIC_SystemReset_helper), diff --git a/Firmware/communication/protocol.hpp b/Firmware/communication/protocol.hpp index 827b226a..0bafbcb5 100644 --- a/Firmware/communication/protocol.hpp +++ b/Firmware/communication/protocol.hpp @@ -775,89 +775,50 @@ struct PropertyListFactory { }; -template -class ProtocolFunction : public Endpoint { +template +struct return_type; + +template<> +struct return_type<> { typedef void type; }; +template +struct return_type { typedef T type; }; +template +struct return_type { typedef std::tuple type; }; + + + +template +class ProtocolFunction; + +template + //template typename asd, + //template typename ssss> +class ProtocolFunction, std::tuple> : Endpoint { public: - static constexpr size_t endpoint_count = 1 + MemberList...>::endpoint_count; - template - ProtocolFunction(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TArgs...), TNames ... names) : - name_(name), all_arg_names_{names...}, obj_(obj), func_ptr_(func_ptr), - input_properties_(PropertyListFactory::template make_property_list<0>(all_arg_names_, in_args_)) + + // @brief The return type of the function as written by a C++ programmer + using TRet = typename return_type::type; + + static constexpr size_t endpoint_count = 1 + MemberList...>::endpoint_count + MemberList...>::endpoint_count; + + ProtocolFunction(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TInputs...), + std::array input_names, + std::array output_names) : + name_(name), obj_(obj), func_ptr_(func_ptr), + input_names_{input_names}, output_names_{output_names}, + input_properties_(PropertyListFactory::template make_property_list<0>(input_names_, in_args_)), + output_properties_(PropertyListFactory::template make_property_list<0>(output_names_, out_args_)) { LOG_PROTO("my tuple is at %x and of size %u\r\n", (uintptr_t)&in_args_, sizeof(in_args_)); } ProtocolFunction(const ProtocolFunction& other) : - name_(other.name_), all_arg_names_(other.all_arg_names_), obj_(other.obj_), func_ptr_(other.func_ptr_), - input_properties_(PropertyListFactory::template make_property_list<0>( - all_arg_names_, in_args_)) - { - LOG_PROTO("COPIED! my tuple is at %x and of size %u\r\n", (uintptr_t)&in_args_, sizeof(in_args_)); - } - - void write_json(size_t id, StreamSink* output) { - // write name - write_string("{\"name\":\"", output); - write_string(name_, output); - - // write endpoint ID - write_string("\",\"id\":", output); - char id_buf[10]; - snprintf(id_buf, sizeof(id_buf), "%u", id); // TODO: get rid of printf - write_string(id_buf, output); - - // write arguments - write_string(",\"type\":\"function\",\"arguments\":[", output); - input_properties_.write_json(id + 1, output), - write_string("]}", output); - } - - Endpoint* get_by_name(const char * name, size_t length) { - return nullptr; // can't address functions by name - } - - void register_endpoints(Endpoint** list, size_t id, size_t length) { - if (id < length) - list[id] = this; - input_properties_.register_endpoints(list, id + 1, length); - } - - void handle(const uint8_t* input, size_t input_length, StreamSink* output) { - (void) input; - (void) input_length; - (void) output; - LOG_PROTO("tuple still at %x and of size %u\r\n", (uintptr_t)&in_args_, sizeof(in_args_)); - LOG_PROTO("invoke function using %d and %.3f\r\n", std::get<0>(in_args_), std::get<1>(in_args_)); - invoke_function_with_tuple(obj_, func_ptr_, in_args_); - } - - const char * name_; - std::array all_arg_names_; // TODO: remove - TObj& obj_; - TRet(TObj::*func_ptr_)(TArgs...); - std::tuple in_args_; - MemberList...> input_properties_; -}; - -template -class ProtocolFunctionWithRet : Endpoint { -public: - static constexpr size_t endpoint_count = 1 + MemberList>::endpoint_count + MemberList...>::endpoint_count; - template - ProtocolFunctionWithRet(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TArgs...), TNames ... names) : - name_(name), out_arg_names_{"out"}, all_arg_names_{names...}, obj_(obj), func_ptr_(func_ptr), - output_properties_(PropertyListFactory::template make_property_list<0>(out_arg_names_, out_args_)), - input_properties_(PropertyListFactory::template make_property_list<0>(all_arg_names_, in_args_)) - { - LOG_PROTO("my tuple is at %x and of size %u\r\n", (uintptr_t)&in_args_, sizeof(in_args_)); - } - - ProtocolFunctionWithRet(const ProtocolFunctionWithRet& other) : - name_(other.name_), all_arg_names_(other.all_arg_names_), obj_(other.obj_), func_ptr_(other.func_ptr_), - output_properties_(PropertyListFactory::template make_property_list<0>( - out_arg_names_, out_args_)), - input_properties_(PropertyListFactory::template make_property_list<0>( - all_arg_names_, in_args_)) + name_(other.name_), obj_(other.obj_), func_ptr_(other.func_ptr_), + input_names_(other.input_names_), output_names_(other.output_names_), + input_properties_(PropertyListFactory::template make_property_list<0>( + input_names_, in_args_)), + output_properties_(PropertyListFactory::template make_property_list<0>( + output_names_, out_args_)) { LOG_PROTO("COPIED! my tuple is at %x and of size %u\r\n", (uintptr_t)&in_args_, sizeof(in_args_)); } @@ -881,6 +842,10 @@ public: write_string("]}", output); } + Endpoint* get_by_name(const char * name, size_t length) { + return nullptr; // can't address functions by name + } + void register_endpoints(Endpoint** list, size_t id, size_t length) { if (id < length) list[id] = this; @@ -888,40 +853,51 @@ public: output_properties_.register_endpoints(list, id + 1 + decltype(input_properties_)::endpoint_count, length); } + template std::enable_if_t + handle_ex() { + invoke_function_with_tuple(obj_, func_ptr_, in_args_); + } + + template std::enable_if_t + handle_ex() { + std::get<0>(out_args_) = invoke_function_with_tuple(obj_, func_ptr_, in_args_); + } + + template std::enable_if_t= 2> + handle_ex() { + out_args_ = invoke_function_with_tuple(obj_, func_ptr_, in_args_); + } + void handle(const uint8_t* input, size_t input_length, StreamSink* output) { (void) input; (void) input_length; (void) output; LOG_PROTO("tuple still at %x and of size %u\r\n", (uintptr_t)&in_args_, sizeof(in_args_)); LOG_PROTO("invoke function using %d and %.3f\r\n", std::get<0>(in_args_), std::get<1>(in_args_)); - std::get<0>(out_args_) = invoke_function_with_tuple(obj_, func_ptr_, in_args_); + handle_ex(); } const char * name_; - std::array out_arg_names_; // TODO: remove - std::array all_arg_names_; // TODO: remove TObj& obj_; - TRet(TObj::*func_ptr_)(TArgs...); - //TRet ret_val_; - std::tuple out_args_; - std::tuple in_args_; - MemberList> output_properties_; - MemberList...> input_properties_; + TRet(TObj::*func_ptr_)(TInputs...); + std::array input_names_; // TODO: remove + std::array output_names_; // TODO: remove + std::tuple in_args_; + std::tuple out_args_; + MemberList...> input_properties_; + MemberList...> output_properties_; }; -//template> -//ProtocolFunction make_protocol_function(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TArgs...), TNames ... names) { -// return ProtocolFunction(name, obj, func_ptr, names...); -//} - -template> -ProtocolFunction make_protocol_function(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TArgs...), TNames ... names) { - return ProtocolFunction(name, obj, func_ptr, names...); +template> +ProtocolFunction, std::tuple<>> make_protocol_function(const char * name, TObj& obj, void(TObj::*func_ptr)(TArgs...), TNames ... names) { + return ProtocolFunction, std::tuple<>>(name, obj, func_ptr, {names...}, {}); } -template> -ProtocolFunctionWithRet make_protocol_function_with_ret(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TArgs...), TNames ... names) { - return ProtocolFunctionWithRet(name, obj, func_ptr, names...); +template::value>> +ProtocolFunction, std::tuple> make_protocol_function(const char * name, TObj& obj, TRet(TObj::*func_ptr)(TArgs...), TNames ... names) { + return ProtocolFunction, std::tuple>(name, obj, func_ptr, {names...}, {"result"}); }