diff --git a/.gitignore b/.gitignore index b73cefc..7786602 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ CMakeCache.txt /examples/display/build *.log /examples/rpc_call/build +/examples/bandwidth/build +/examples/servo/build diff --git a/examples/bandwidth/CMakeLists.txt b/examples/bandwidth/CMakeLists.txt new file mode 100644 index 0000000..a6017fc --- /dev/null +++ b/examples/bandwidth/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.15) + +project(BandwidthExample) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(libcontrol REQUIRED) +find_package(spdlog REQUIRED) +find_package(librpc REQUIRED) + +add_executable(BandwidthExample main.cpp) + +target_link_libraries(BandwidthExample + PRIVATE + libcontrol::libcontrol + spdlog::spdlog + librpc::librpc +) diff --git a/examples/bandwidth/CMakeUserPresets.json b/examples/bandwidth/CMakeUserPresets.json new file mode 100644 index 0000000..945b382 --- /dev/null +++ b/examples/bandwidth/CMakeUserPresets.json @@ -0,0 +1,9 @@ +{ + "version": 4, + "vendor": { + "conan": {} + }, + "include": [ + "build/CMakePresets.json" + ] +} \ No newline at end of file diff --git a/examples/bandwidth/README.md b/examples/bandwidth/README.md new file mode 100644 index 0000000..8dab1c6 --- /dev/null +++ b/examples/bandwidth/README.md @@ -0,0 +1,10 @@ +# Servo Example + +## Compiling +``` +conan install . --build=missing --output-folder=build -s build_type=Release +cmake -S . -B "build" -DCMAKE_TOOLCHAIN_FILE="build/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE="Release" +cmake --build "./build" --config "Release" + +./build/BandwidthExample +``` diff --git a/examples/bandwidth/build.sh b/examples/bandwidth/build.sh new file mode 100755 index 0000000..8dd8dd2 --- /dev/null +++ b/examples/bandwidth/build.sh @@ -0,0 +1,4 @@ +conan install . --build=missing --output-folder=build -s build_type=Release +cmake -S . -B "build" -DCMAKE_TOOLCHAIN_FILE="build/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE="Release" +cmake --build "./build" --config "Release" + diff --git a/examples/bandwidth/conanfile.txt b/examples/bandwidth/conanfile.txt new file mode 100644 index 0000000..a61eff3 --- /dev/null +++ b/examples/bandwidth/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +libcontrol/1.0.0 +flatbuffers/24.12.23 +spdlog/1.16.0 +librpc/1.1.7 + +[generators] +CMakeDeps +CMakeToolchain diff --git a/examples/bandwidth/main.cpp b/examples/bandwidth/main.cpp new file mode 100644 index 0000000..81cc555 --- /dev/null +++ b/examples/bandwidth/main.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include "libcontrol.h" + +#define TARGET_MODULE 150 +#define METADATA_TAG 7 + +int main() { + + const auto messaging_interface = std::make_unique(); + + const auto modules = messaging_interface->find_connected_modules(std::chrono::seconds(3)); + + if (!modules.contains(TARGET_MODULE)) { + std::cout << "Could not find target module " << TARGET_MODULE << std::endl; + return -1; + } + + std::vector vec(1024, 'A'); + + while (true) { + messaging_interface->send(vec.data(), vec.size(), TARGET_MODULE, METADATA_TAG, false); + } + + + return 0; +} diff --git a/examples/rpc_call/include/rpc/RemoteManagement.h b/examples/rpc_call/include/rpc/RemoteManagement.h index 6d0042a..4502d2b 100644 --- a/examples/rpc_call/include/rpc/RemoteManagement.h +++ b/examples/rpc_call/include/rpc/RemoteManagement.h @@ -1,3 +1,4 @@ + // // Created by Johnathon Slightham on 2026-02-16. // @@ -21,6 +22,7 @@ class RemoteManagement { m_robot_controller(controller) { } bool perform_ota(); + double ota_progress(); // 0 to 1 representing % progress. void restart(); private: @@ -29,6 +31,7 @@ class RemoteManagement { bool ota_end(); uint16_t m_sequence_num = 0; + uint16_t m_total_packets = 0; uint8_t m_module_id; std::ifstream m_file; std::unique_ptr m_builder; diff --git a/examples/rpc_call/main.cpp b/examples/rpc_call/main.cpp index e3c721e..38d9652 100644 --- a/examples/rpc_call/main.cpp +++ b/examples/rpc_call/main.cpp @@ -9,40 +9,51 @@ #include "libcontrol.h" #include "rpc/RemoteManagement.h" +void progress_monitor_task(std::shared_ptr rm, uint8_t module_id) { + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(5)); + std::cout << "Module " << (int)module_id << ": " << rm->ota_progress() * 100 << "% complete\n"; + if (rm->ota_progress() >= 1.0) return; + } +} + +void task(std::shared_ptr controller, uint8_t module_id, const std::string& filepath) { + auto rm = std::make_shared(module_id, filepath, controller); + std::thread t(progress_monitor_task, rm, module_id); + rm->perform_ota(); + t.join(); + std::cout << "Done updating " << (int)module_id << "\n"; +} + int main() { - - // const auto messaging_interface = std::make_unique(); - - // const auto modules = messaging_interface->find_connected_modules(std::chrono::seconds(3)); - - // std::cout << "Found " << modules.size() << " modules" << std::endl; - - // for (const auto module : modules) { - // std::cout << "Found ID " << (int)module << std::endl; - // } - const auto robot_controller = std::make_shared(); robot_controller->fetchDirectlyConnectedModules(true); std::this_thread::sleep_for(std::chrono::seconds(5)); - // const auto function_tag = 3; - // const auto module = 99; - // std::string msg = "Hello world!"; - // std::vector parameters(msg.begin(), msg.end()); - // auto maybe_return_value = messaging_interface->remote_call(function_tag, module, parameters); + std::vector to_update{}; + for (const auto& maybe_module : robot_controller->getModules()) { + if (const auto &module = maybe_module.lock()) { + if (module->get_leader() != module->get_device_id()) { continue; } + std::cout << "Updating module " << (int)module->get_device_id(); + to_update.emplace_back(module->get_device_id()); + } + } - // 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; - // } - // + if (to_update.size() < 1) { + std::cout << "No modules found to update" << std::endl; + return 0; + } std::string filename = - "/Users/jslightham/Documents/Classes/capstone/firmware/build/firmware.bin"; - const auto rm = std::make_unique(99, filename, robot_controller); - rm->perform_ota(); + "/Users/jslightham/Documents/Classes/capstone/firmware/build/firmware.bin"; + std::vector threads; + for (int i = 0; i < to_update.size(); i++) { + threads.emplace_back(task, robot_controller, to_update[i], filename); + } + + for (auto &t : threads) { + t.join(); + } return 0; } diff --git a/examples/rpc_call/rpc/RemoteManagement.cpp b/examples/rpc_call/rpc/RemoteManagement.cpp index 096609d..9ab0382 100644 --- a/examples/rpc_call/rpc/RemoteManagement.cpp +++ b/examples/rpc_call/rpc/RemoteManagement.cpp @@ -23,6 +23,7 @@ bool RemoteManagement::perform_ota() { m_file.seekg(0, std::ios::end); std::streamsize total_size = m_file.tellg(); m_file.seekg(0, std::ios::beg); + m_total_packets = total_size/OTA_CHUNK_SIZE; // std::cout << "Total number of chunks: " << total_size/OTA_CHUNK_SIZE << std::endl; while (m_file) { @@ -96,3 +97,14 @@ bool RemoteManagement::ota_end() { } return false; } + +double RemoteManagement::ota_progress() { + if (m_total_packets < 1) { + return 0.0; + } + if (m_sequence_num >= m_total_packets) { + return 1.0; + } + + return static_cast(m_sequence_num) / static_cast(m_total_packets); +} diff --git a/examples/servo/CMakeLists.txt b/examples/servo/CMakeLists.txt new file mode 100644 index 0000000..e1663fa --- /dev/null +++ b/examples/servo/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.15) + +project(ServoExample) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(libcontrol REQUIRED) +find_package(spdlog REQUIRED) +find_package(librpc REQUIRED) + +add_executable(ServoExample main.cpp) + +target_link_libraries(ServoExample + PRIVATE + libcontrol::libcontrol + spdlog::spdlog + librpc::librpc +) diff --git a/examples/servo/CMakeUserPresets.json b/examples/servo/CMakeUserPresets.json new file mode 100644 index 0000000..945b382 --- /dev/null +++ b/examples/servo/CMakeUserPresets.json @@ -0,0 +1,9 @@ +{ + "version": 4, + "vendor": { + "conan": {} + }, + "include": [ + "build/CMakePresets.json" + ] +} \ No newline at end of file diff --git a/examples/servo/README.md b/examples/servo/README.md new file mode 100644 index 0000000..9f63005 --- /dev/null +++ b/examples/servo/README.md @@ -0,0 +1,10 @@ +# Servo Example + +## Compiling +``` +conan install . --build=missing --output-folder=build -s build_type=Release +cmake -S . -B "build" -DCMAKE_TOOLCHAIN_FILE="build/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE="Release" +cmake --build "./build" --config "Release" + +./build/ServoExample +``` diff --git a/examples/servo/build.sh b/examples/servo/build.sh new file mode 100755 index 0000000..8dd8dd2 --- /dev/null +++ b/examples/servo/build.sh @@ -0,0 +1,4 @@ +conan install . --build=missing --output-folder=build -s build_type=Release +cmake -S . -B "build" -DCMAKE_TOOLCHAIN_FILE="build/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE="Release" +cmake --build "./build" --config "Release" + diff --git a/examples/servo/conanfile.txt b/examples/servo/conanfile.txt new file mode 100644 index 0000000..a61eff3 --- /dev/null +++ b/examples/servo/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +libcontrol/1.0.0 +flatbuffers/24.12.23 +spdlog/1.16.0 +librpc/1.1.7 + +[generators] +CMakeDeps +CMakeToolchain diff --git a/examples/servo/main.cpp b/examples/servo/main.cpp new file mode 100644 index 0000000..7b2bdc2 --- /dev/null +++ b/examples/servo/main.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#include "libcontrol.h" + +int main() { + + const auto controller = std::make_unique(); + + controller->fetchDirectlyConnectedModules(true); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + + std::cout << "Found " << controller->getModules().size() << " modules" << std::endl; + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dist(0, 10); + + while (true) { + std::cout << "Found " << controller->getModules().size() << " modules" << std::endl; + for (const auto &maybe_module : controller->getModules()) { + if (const auto &module = maybe_module.lock()) { + if (module->get_type() == ModuleType_DC_MOTOR) { + int randomNumber = dist(gen); + if (module->get_position() > 90) { + module->actuate(70 - randomNumber); + } else { + module->actuate(110 + randomNumber); + } + } + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + return 0; +}