mirror of
https://github.com/BotChain-Robots/control.git
synced 2026-03-09 16:22:26 +01:00
Formatting, add remote calling to c library
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "libcontrol.h"
|
||||
@@ -16,16 +16,16 @@ int main() {
|
||||
|
||||
std::cout << "Found " << controller->getModules().size() << " modules" << std::endl;
|
||||
|
||||
for (const auto& maybe_module : controller->getModules()) {
|
||||
if (const auto& module = maybe_module.lock()) {
|
||||
for (const auto &maybe_module : controller->getModules()) {
|
||||
if (const auto &module = maybe_module.lock()) {
|
||||
std::cout << "Found module " << (int)module->get_device_id();
|
||||
|
||||
if (module->get_type() == ModuleType_DISPLAY) {
|
||||
module->actuate(std::format("BotChain \n\n\nModule ID: {}", module->get_device_id()));
|
||||
module->actuate(
|
||||
std::format("BotChain \n\n\nModule ID: {}", module->get_device_id()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ find_package(libcontrol REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
find_package(librpc REQUIRED)
|
||||
|
||||
add_executable(RpcCallExample main.cpp)
|
||||
add_executable(RpcCallExample main.cpp flatbuffers/OTAPacketBuilder.cpp rpc/RemoteDebugging.cpp rpc/RemoteManagement.cpp)
|
||||
|
||||
target_include_directories(RpcCallExample PUBLIC include)
|
||||
|
||||
target_link_libraries(RpcCallExample
|
||||
PRIVATE
|
||||
|
||||
25
examples/rpc_call/flatbuffers/OTAPacketBuilder.cpp
Normal file
25
examples/rpc_call/flatbuffers/OTAPacketBuilder.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
#include "flatbuffers/OTAPacketBuilder.h"
|
||||
#include "flatbuffers/SerializedMessage.h"
|
||||
|
||||
namespace Flatbuffers {
|
||||
|
||||
SerializedMessage OTAPacketBuilder::build_ota_packet(uint16_t packet_num,
|
||||
const std::vector<uint8_t> &packet) {
|
||||
builder_.Clear();
|
||||
|
||||
const auto packet_vector = builder_.CreateVector(packet);
|
||||
|
||||
const auto message = Messaging::CreateOTAPacket(builder_, packet_num,
|
||||
static_cast<int>(packet.size()), packet_vector);
|
||||
|
||||
builder_.Finish(message);
|
||||
|
||||
return {builder_.GetBufferPointer(), builder_.GetSize()};
|
||||
}
|
||||
|
||||
const Messaging::OTAPacket *OTAPacketBuilder::parse_ota_packet(const uint8_t *buffer) {
|
||||
return flatbuffers::GetRoot<Messaging::OTAPacket>(buffer);
|
||||
}
|
||||
|
||||
} // namespace Flatbuffers
|
||||
28
examples/rpc_call/include/flatbuffers/OTAPacketBuilder.h
Normal file
28
examples/rpc_call/include/flatbuffers/OTAPacketBuilder.h
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
#ifndef OTAPACKETBUILDER_H
|
||||
#define OTAPACKETBUILDER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "flatbuffers/SerializedMessage.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers_generated/OTAPacket_generated.h"
|
||||
|
||||
namespace Flatbuffers {
|
||||
|
||||
class OTAPacketBuilder {
|
||||
public:
|
||||
OTAPacketBuilder() : builder_(1024) {
|
||||
}
|
||||
|
||||
SerializedMessage build_ota_packet(uint16_t packet_num, const std::vector<uint8_t> &packet);
|
||||
|
||||
static const Messaging::OTAPacket *parse_ota_packet(const uint8_t *buffer);
|
||||
|
||||
private:
|
||||
flatbuffers::FlatBufferBuilder builder_;
|
||||
};
|
||||
} // namespace Flatbuffers
|
||||
|
||||
#endif // OTAPACKETBUILDER_H
|
||||
15
examples/rpc_call/include/flatbuffers/SerializedMessage.h
Normal file
15
examples/rpc_call/include/flatbuffers/SerializedMessage.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2025-07-05.
|
||||
//
|
||||
|
||||
#ifndef SERIALIZEDMESSAGE_H
|
||||
#define SERIALIZEDMESSAGE_H
|
||||
|
||||
namespace Flatbuffers {
|
||||
struct SerializedMessage {
|
||||
void *data;
|
||||
size_t size;
|
||||
};
|
||||
} // namespace Flatbuffers
|
||||
|
||||
#endif // SERIALIZEDMESSAGE_H
|
||||
@@ -0,0 +1,115 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_OTAPACKET_MESSAGING_H_
|
||||
#define FLATBUFFERS_GENERATED_OTAPACKET_MESSAGING_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||
// generated, otherwise it may not be compatible.
|
||||
// static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||
// FLATBUFFERS_VERSION_MINOR == 2 &&
|
||||
// FLATBUFFERS_VERSION_REVISION == 10,
|
||||
// "Non-compatible flatbuffers version included");
|
||||
|
||||
namespace Messaging {
|
||||
|
||||
struct OTAPacket;
|
||||
struct OTAPacketBuilder;
|
||||
|
||||
struct OTAPacket FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
typedef OTAPacketBuilder Builder;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_SEQUENCE_NUMBER = 4,
|
||||
VT_LENGTH = 6,
|
||||
VT_PAYLOAD = 8
|
||||
};
|
||||
uint16_t sequence_number() const {
|
||||
return GetField<uint16_t>(VT_SEQUENCE_NUMBER, 0);
|
||||
}
|
||||
uint16_t length() const {
|
||||
return GetField<uint16_t>(VT_LENGTH, 0);
|
||||
}
|
||||
const ::flatbuffers::Vector<uint8_t> *payload() const {
|
||||
return GetPointer<const ::flatbuffers::Vector<uint8_t> *>(VT_PAYLOAD);
|
||||
}
|
||||
bool Verify(::flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<uint16_t>(verifier, VT_SEQUENCE_NUMBER, 2) &&
|
||||
VerifyField<uint16_t>(verifier, VT_LENGTH, 2) &&
|
||||
VerifyOffset(verifier, VT_PAYLOAD) && verifier.VerifyVector(payload()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct OTAPacketBuilder {
|
||||
typedef OTAPacket Table;
|
||||
::flatbuffers::FlatBufferBuilder &fbb_;
|
||||
::flatbuffers::uoffset_t start_;
|
||||
void add_sequence_number(uint16_t sequence_number) {
|
||||
fbb_.AddElement<uint16_t>(OTAPacket::VT_SEQUENCE_NUMBER, sequence_number, 0);
|
||||
}
|
||||
void add_length(uint16_t length) {
|
||||
fbb_.AddElement<uint16_t>(OTAPacket::VT_LENGTH, length, 0);
|
||||
}
|
||||
void add_payload(::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload) {
|
||||
fbb_.AddOffset(OTAPacket::VT_PAYLOAD, payload);
|
||||
}
|
||||
explicit OTAPacketBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
::flatbuffers::Offset<OTAPacket> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = ::flatbuffers::Offset<OTAPacket>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline ::flatbuffers::Offset<OTAPacket>
|
||||
CreateOTAPacket(::flatbuffers::FlatBufferBuilder &_fbb, uint16_t sequence_number = 0,
|
||||
uint16_t length = 0,
|
||||
::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload = 0) {
|
||||
OTAPacketBuilder builder_(_fbb);
|
||||
builder_.add_payload(payload);
|
||||
builder_.add_length(length);
|
||||
builder_.add_sequence_number(sequence_number);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline ::flatbuffers::Offset<OTAPacket>
|
||||
CreateOTAPacketDirect(::flatbuffers::FlatBufferBuilder &_fbb, uint16_t sequence_number = 0,
|
||||
uint16_t length = 0, const std::vector<uint8_t> *payload = nullptr) {
|
||||
auto payload__ = payload ? _fbb.CreateVector<uint8_t>(*payload) : 0;
|
||||
return Messaging::CreateOTAPacket(_fbb, sequence_number, length, payload__);
|
||||
}
|
||||
|
||||
inline const Messaging::OTAPacket *GetOTAPacket(const void *buf) {
|
||||
return ::flatbuffers::GetRoot<Messaging::OTAPacket>(buf);
|
||||
}
|
||||
|
||||
inline const Messaging::OTAPacket *GetSizePrefixedOTAPacket(const void *buf) {
|
||||
return ::flatbuffers::GetSizePrefixedRoot<Messaging::OTAPacket>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyOTAPacketBuffer(::flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<Messaging::OTAPacket>(nullptr);
|
||||
}
|
||||
|
||||
inline bool VerifySizePrefixedOTAPacketBuffer(::flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifySizePrefixedBuffer<Messaging::OTAPacket>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishOTAPacketBuffer(::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<Messaging::OTAPacket> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline void FinishSizePrefixedOTAPacketBuffer(::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<Messaging::OTAPacket> root) {
|
||||
fbb.FinishSizePrefixed(root);
|
||||
}
|
||||
|
||||
} // namespace Messaging
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_OTAPACKET_MESSAGING_H_
|
||||
24
examples/rpc_call/include/rpc/RemoteDebugging.h
Normal file
24
examples/rpc_call/include/rpc/RemoteDebugging.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2026-02-16.
|
||||
//
|
||||
|
||||
#ifndef NEW_DEV_TOOLS_REMOTEDEBUGGING_H
|
||||
#define NEW_DEV_TOOLS_REMOTEDEBUGGING_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "libcontrol.h"
|
||||
|
||||
class RemoteDebugging {
|
||||
public:
|
||||
RemoteDebugging(std::shared_ptr<RobotController> controller) : m_robot_controller(controller) {
|
||||
}
|
||||
std::string get_task_manager(uint8_t module_id);
|
||||
std::string get_logs(uint8_t module_id);
|
||||
|
||||
private:
|
||||
std::shared_ptr<RobotController> m_robot_controller;
|
||||
};
|
||||
|
||||
#endif //NEW_DEV_TOOLS_REMOTEDEBUGGING_H
|
||||
38
examples/rpc_call/include/rpc/RemoteManagement.h
Normal file
38
examples/rpc_call/include/rpc/RemoteManagement.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2026-02-16.
|
||||
//
|
||||
|
||||
#ifndef REMOTEMANAGEMENT_H
|
||||
#define REMOTEMANAGEMENT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include "flatbuffers/OTAPacketBuilder.h"
|
||||
#include "libcontrol.h"
|
||||
|
||||
class RemoteManagement {
|
||||
public:
|
||||
RemoteManagement(uint8_t module_id, const std::string &path,
|
||||
std::shared_ptr<RobotController> controller)
|
||||
: m_module_id(module_id), m_file(path, std::ios::binary),
|
||||
m_builder(std::make_unique<Flatbuffers::OTAPacketBuilder>()),
|
||||
m_robot_controller(controller) {
|
||||
}
|
||||
bool perform_ota();
|
||||
void restart();
|
||||
|
||||
private:
|
||||
bool start_ota();
|
||||
bool write_ota(std::vector<uint8_t> &transmit_buffer);
|
||||
bool ota_end();
|
||||
|
||||
uint16_t m_sequence_num = 0;
|
||||
uint8_t m_module_id;
|
||||
std::ifstream m_file;
|
||||
std::unique_ptr<Flatbuffers::OTAPacketBuilder> m_builder;
|
||||
std::shared_ptr<RobotController> m_robot_controller;
|
||||
};
|
||||
|
||||
#endif // REMOTEMANAGEMENT_H
|
||||
@@ -7,34 +7,42 @@
|
||||
#include <vector>
|
||||
|
||||
#include "libcontrol.h"
|
||||
#include "rpc/RemoteManagement.h"
|
||||
|
||||
int main() {
|
||||
|
||||
const auto messaging_interface = std::make_unique<MessagingInterface>();
|
||||
// const auto messaging_interface = std::make_unique<MessagingInterface>();
|
||||
|
||||
const auto modules =
|
||||
messaging_interface->find_connected_modules(std::chrono::seconds(3));
|
||||
// const auto modules = messaging_interface->find_connected_modules(std::chrono::seconds(3));
|
||||
|
||||
std::cout << "Found " << modules.size() << " modules" << std::endl;
|
||||
// std::cout << "Found " << modules.size() << " modules" << std::endl;
|
||||
|
||||
for (const auto module : modules) {
|
||||
std::cout << "Found ID " << (int)module << std::endl;
|
||||
}
|
||||
// for (const auto module : modules) {
|
||||
// std::cout << "Found ID " << (int)module << std::endl;
|
||||
// }
|
||||
|
||||
const auto function_tag = 100;
|
||||
const auto module = 98;
|
||||
std::string msg = "Hello world!";
|
||||
std::vector<uint8_t> parameters(msg.begin(), msg.end());
|
||||
auto maybe_return_value =
|
||||
messaging_interface->remote_call(function_tag, module, parameters);
|
||||
const auto robot_controller = std::make_shared<RobotController>();
|
||||
robot_controller->fetchDirectlyConnectedModules(true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
|
||||
if (maybe_return_value) {
|
||||
auto return_value = std::move(*maybe_return_value);
|
||||
std::cout << "Got return value " << (char *)return_value->data()
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cout << "Function call time out" << std::endl;
|
||||
}
|
||||
// const auto function_tag = 3;
|
||||
// const auto module = 99;
|
||||
// std::string msg = "Hello world!";
|
||||
// std::vector<uint8_t> parameters(msg.begin(), msg.end());
|
||||
// auto maybe_return_value = messaging_interface->remote_call(function_tag, module, parameters);
|
||||
|
||||
return 0;
|
||||
// if (maybe_return_value) {
|
||||
// auto return_value = std::move(*maybe_return_value);
|
||||
// std::cout << "Got return value " << (char *)return_value->data() << std::endl;
|
||||
// } else {
|
||||
// std::cout << "Function call time out" << std::endl;
|
||||
// }
|
||||
//
|
||||
|
||||
std::string filename =
|
||||
"/Users/jslightham/Documents/Classes/capstone/firmware/build/firmware.bin";
|
||||
const auto rm = std::make_unique<RemoteManagement>(99, filename, robot_controller);
|
||||
rm->perform_ota();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
23
examples/rpc_call/rpc/RemoteDebugging.cpp
Normal file
23
examples/rpc_call/rpc/RemoteDebugging.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2026-02-16.
|
||||
//
|
||||
|
||||
#include "rpc/RemoteDebugging.h"
|
||||
|
||||
std::string RemoteDebugging::get_task_manager(uint8_t module_id) {
|
||||
const auto maybe = m_robot_controller->remote_call(2, module_id, {});
|
||||
if (maybe) {
|
||||
std::string str((*maybe)->begin(), (*maybe)->end());
|
||||
return str;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string RemoteDebugging::get_logs(uint8_t module_id) {
|
||||
const auto maybe = m_robot_controller->remote_call(3, module_id, {});
|
||||
if (maybe) {
|
||||
std::string str((*maybe)->begin(), (*maybe)->end());
|
||||
return str;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
98
examples/rpc_call/rpc/RemoteManagement.cpp
Normal file
98
examples/rpc_call/rpc/RemoteManagement.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Created by Johnathon Slightham on 2026-02-16.
|
||||
//
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "rpc/RemoteManagement.h"
|
||||
|
||||
#define MAX_PACKET_TX_ATTEMPTS 5
|
||||
#define OTA_CHUNK_SIZE 1024
|
||||
|
||||
bool RemoteManagement::perform_ota() {
|
||||
if (!m_file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!start_ota()) {
|
||||
// std::cout << "Fail to start OTA update" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file.seekg(0, std::ios::end);
|
||||
std::streamsize total_size = m_file.tellg();
|
||||
m_file.seekg(0, std::ios::beg);
|
||||
// std::cout << "Total number of chunks: " << total_size/OTA_CHUNK_SIZE << std::endl;
|
||||
|
||||
while (m_file) {
|
||||
// std::cout << "Top of transmit " << m_sequence_num << std::endl;
|
||||
|
||||
std::vector<uint8_t> buffer(OTA_CHUNK_SIZE);
|
||||
m_file.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
|
||||
std::streamsize bytes_read = m_file.gcount();
|
||||
|
||||
if (bytes_read <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_sequence_num == 1 && buffer[0] != 0xE9) {
|
||||
// std::cout << "First byte of firmware must be 0xE9" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// buffer.resize(bytes_read);
|
||||
if (!write_ota(buffer)) {
|
||||
// std::cout << "Failed to write" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ota_end();
|
||||
restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteManagement::restart() {
|
||||
// Will never return since the module will shutdown
|
||||
m_robot_controller->remote_call(7, m_module_id, {});
|
||||
}
|
||||
|
||||
bool RemoteManagement::start_ota() {
|
||||
// std::cout << "Starting OTA" << std::endl;
|
||||
const auto maybe = m_robot_controller->remote_call(4, m_module_id, {});
|
||||
if (maybe) {
|
||||
// std::cout << "Got valid response" << std::endl;
|
||||
m_sequence_num = 1;
|
||||
return (*maybe)->at(0) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoteManagement::write_ota(std::vector<uint8_t> &transmit_buffer) {
|
||||
// std::cout << "Write OTA " << std::endl;
|
||||
const auto [ota_packet, packet_size] =
|
||||
m_builder->build_ota_packet(m_sequence_num, transmit_buffer);
|
||||
std::vector<uint8_t> vec((uint8_t *)ota_packet, (uint8_t *)ota_packet + packet_size);
|
||||
int attempts = 0;
|
||||
while (attempts < MAX_PACKET_TX_ATTEMPTS) {
|
||||
const auto maybe = m_robot_controller->remote_call(5, m_module_id, vec);
|
||||
if (maybe && (*maybe)->at(0) > 0) {
|
||||
// std::cout << "Success writing OTA" << std::endl;
|
||||
m_sequence_num++;
|
||||
return true;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoteManagement::ota_end() {
|
||||
const auto maybe = m_robot_controller->remote_call(6, m_module_id, {});
|
||||
if (maybe) {
|
||||
m_sequence_num = 0;
|
||||
return (*maybe)->at(0) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user