Skip to content

Commit

Permalink
Added classes for handling specific frame types and any frame
Browse files Browse the repository at this point in the history
  • Loading branch information
jbangelo committed Jan 3, 2020
1 parent eaefa4b commit f1fc44e
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 3 deletions.
3 changes: 1 addition & 2 deletions c/example/cpp_example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-strict-prototypes -Wno-unknown-warning-option -Werror -std=gnu99 ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-strict-prototypes -Wno-unknown-warning-option -Werror -std=c++11 ${CMAKE_CXX_FLAGS}")

add_executable(libsbp_cpp_example cpp_example.cc)

find_package(PkgConfig)

link_directories("/usr/local/lib/")
include_directories("/usr/local/include/")

add_executable(libsbp_cpp_example cpp_example.cc)
target_link_libraries(libsbp_cpp_example sbp)
40 changes: 39 additions & 1 deletion c/example/cpp_example/cpp_example.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <libsbp/cpp/state.h>
#include <libsbp/cpp/message_handler.h>
#include <libsbp/cpp/frame_handler.h>

void usage(char *prog_name) {
fprintf(stderr, "usage: %s [filename]\n", prog_name);
Expand Down Expand Up @@ -52,6 +53,40 @@ class ECEFHandler : private sbp::MessageHandler<msg_gps_time_t, msg_pos_ecef_t>
}
};

class LLHFrameHandler : private sbp::FrameHandler<msg_gps_time_t, msg_pos_llh_t> {
public:
LLHFrameHandler(sbp::State *state) : sbp::FrameHandler<msg_gps_time_t, msg_pos_llh_t>(state) {
}

void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
uint8_t payload_len, uint8_t payload[],
uint16_t frame_len, uint8_t frame[]) {
(void)sender_id;
(void)payload;
(void)frame;
if (msg_type == SBP_MSG_POS_LLH) {
std::cout << "Receveid new POS_LLH frame, payload length " << (int)payload_len << ", frame length " << frame_len << "\n";
} else if (msg_type == SBP_MSG_GPS_TIME) {
std::cout << "Received new GPS_TIME frame, payload length " << (int)payload_len << ", frame length " << frame_len << "\n";
}
}
};

class EverythingHandler : private sbp::AllFrameHandler {
public:
EverythingHandler(sbp::State *state) : sbp::AllFrameHandler(state) {
}

void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
uint8_t payload_len, uint8_t payload[],
uint16_t frame_len, uint8_t frame[]) {
(void)sender_id;
(void)payload;
(void)frame;
std::cout << "Receveid new frame, message type " << msg_type << ", payload length " << (int)payload_len << ", frame length " << frame_len << "\n";
}
};

int main(int argc, char **argv)
{
if (argc <= 1) {
Expand All @@ -68,7 +103,9 @@ int main(int argc, char **argv)
}

sbp::State s;
ECEFHandler handler(&s);
ECEFHandler ecef_handler(&s);
LLHFrameHandler llh_handler(&s);
EverythingHandler everything_handler(&s);

s.set_reader(&reader);

Expand All @@ -78,3 +115,4 @@ int main(int argc, char **argv)

return 0;
}

191 changes: 191 additions & 0 deletions c/include/libsbp/cpp/frame_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/**
* Copyright (C) 2020 Swift Navigation Inc.
* Contact: Swift Navigation <[email protected]>
*
* This source is subject to the license found in the file 'LICENSE' which must
* be be distributed together with this source. All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
*/

#ifndef SBP_CPP_FRAME_HANDLER_H_
#define SBP_CPP_FRAME_HANDLER_H_

#include <cassert>
#include <array>

#include <libsbp/cpp/state.h>
#include <libsbp/cpp/message_traits.h>

namespace sbp {

/**
* A helper function for calling a C++ object member function from a libsbp frame callback.
*
* This function is registered with libsbp as a callback and calls the `handle_sbp_frame`
* member function of an object from that callback passing through all of the arguments.
* The instance of the object is passed in via the `context` parameter.
*
* @tparam ClassT The class type to call the function on
*
* @param sender_id The decoded sender ID, is forwarded
* @param msg_type The message type, is forwarded
* @param payload_len The length of the payload, is forwarded
* @param payload A pointer to the payload, is forwarded
* @param frame_len The length of the frame, is forwarded
* @param frame A pointer to the frame, is forwarded
* @param context Pointer to an instance of `ClassT` to use
*/
template<typename ClassT>
inline void sbp_frame_cb_passthrough(uint16_t sender_id, uint16_t msg_type,
uint8_t payload_len, uint8_t payload[],
uint16_t frame_len, uint8_t frame[],
void *context) {
assert(nullptr != context);

auto instance = static_cast<ClassT *>(context);
instance->handle_sbp_frame(sender_id, msg_type, payload_len, payload, frame_len, frame);
}

/**
* Base type for defining classes that handle specific SBP Frames
*
* Application classes should derive from this class if they wish to handle
* entire frames of specific SBP messages with a member function. `FrameHandler`
* instantiates all of the callback nodes, and registers the member function with
* the given `sbp_state_t`.
*
* Classes that derive from `FrameHandler` need to implement
* void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
* uint8_t payload_len, uint8_t payload[],
* uint16_t frame_len, uint8_t frame[]);
*
* This member function will be called for each message specified in the template parameters.
* You will be able to differentiate the message types based on the `msg_type` argument.
*
* Due to the nature of the callback registration in libsbp we dissallow copying or
* moving of `FrameHandler`.
*
* @note It should not matter if the class derives publicly or privately from `FrameHandler`
* or if the `handle_sbp_frame` function is public or private.
*
* @example
* class ECEFHandler : private sbp::FrameHandler<msg_gps_time_t, msg_pos_ecef_t> {
* public:
* ECEFHandler(sbp::State *state) : sbp::FrameHandler<msg_gps_time_t, msg_pos_ecef_t>(state) {
* // The callbacks have already been registered
* // Perform other initialization tasks
* }
*
* void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
* uint8_t payload_len, uint8_t payload[],
* uint16_t frame_len, uint8_t frame[]) {
* // handle either GPS_TIME or POS_ECEF message types
* }
* };
*
*/
template<typename ...MsgTypes>
class FrameHandler {
static constexpr size_t kMsgCount = sizeof...(MsgTypes);

State &state_;
std::array<sbp_msg_callbacks_node_t, kMsgCount> callback_nodes_;

public:

explicit FrameHandler(State *state) : state_(*state), callback_nodes_() {
static constexpr std::array<uint16_t, kMsgCount> ids = { (0, sbp::MessageTraits<MsgTypes>::id)... };

for (size_t i = 0; i < kMsgCount; ++i) {
sbp_register_frame_callback(state_.get_state(),
ids[i],
&sbp_frame_cb_passthrough<FrameHandler>,
this,
&callback_nodes_[i]);
}
}

virtual ~FrameHandler() {
for (auto& node : callback_nodes_) {
sbp_remove_callback(state_.get_state(), &node);
}
}

FrameHandler(const FrameHandler&) = delete;
FrameHandler(FrameHandler&& other) = delete;
FrameHandler& operator=(const FrameHandler&) = delete;
FrameHandler& operator=(FrameHandler&&) = delete;

virtual void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
uint8_t payload_len, uint8_t payload[],
uint16_t frame_len, uint8_t frame[]) = 0;
};

/**
* Base type for defining classes that handle all SBP frames.
*
* Application classes should derive from this class if they wish to handle
* all valid SBP frames with a single member function. `AllFrameHandler`
* instantiates the callback node, and registers the member functions with
* the given `sbp_state_t`.
*
* Classes that derive from `AllFrameHandler` need to implement
* void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
* uint8_t payload_len, uint8_t payload[],
* uint16_t frame_len, uint8_t frame[]);
*
* Due to the nature of the callback registration in libsbp we dissallow copying or
* moving of `AllFrameHandler`.
*
* @note It should not matter if the class derives publicly or privately from `AllFrameHandler`
* or if the `handle_sbp_frame` function is public or private.
*
* @example
* class EverythingHandler : private sbp::AllFrameHandler {
* public:
* EverythingHandler(sbp::State *state) : sbp::AllFrameHandler(state) {
* // The callbacks have already been registered
* // Perform other initialization tasks
* }
*
* void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
* uint8_t payload_len, uint8_t payload[],
* uint16_t frame_len, uint8_t frame[]) {
* // handle all frames here
* }
* };
*
*/
class AllFrameHandler {
State &state_;
sbp_msg_callbacks_node_t callback_node_;

public:

explicit AllFrameHandler(State *state) : state_(*state), callback_node_() {
sbp_register_all_msg_callback(state_.get_state(),
sbp_frame_cb_passthrough<AllFrameHandler>,
this,
&callback_node_);
}

virtual ~AllFrameHandler() {
sbp_remove_callback(state_.get_state(), &callback_node_);
}

AllFrameHandler(const AllFrameHandler&) = delete;
AllFrameHandler(AllFrameHandler&& other) = delete;
AllFrameHandler& operator=(const AllFrameHandler&) = delete;
AllFrameHandler& operator=(AllFrameHandler&&) = delete;

virtual void handle_sbp_frame(uint16_t sender_id, uint16_t msg_type,
uint8_t payload_len, uint8_t payload[],
uint16_t frame_len, uint8_t frame[]) = 0;
};

} /* namespace sbp */

#endif /* SBP_CPP_MESSAGE_HANDLER_H_ */

0 comments on commit f1fc44e

Please sign in to comment.