From cbffdf6660c4a43e37d5cd9bc91f5a339de8c6e1 Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 9 Oct 2021 15:22:14 +0200 Subject: [PATCH 01/18] Added SMCE_Client Added SMCE_Client, a terminal interface for libSMCE. --- CMakeLists.txt | 11 +++- src/SMCE/SMCE_Client.cpp | 137 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/SMCE/SMCE_Client.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d60323b..988fe99f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ target_sources (HostUDD PRIVATE ) -add_library (objSMCE OBJECT) +add_library (objSMCE OBJECT ) configure_coverage (objSMCE) set_property (TARGET objSMCE PROPERTY CXX_EXTENSIONS Off) set_property (TARGET objSMCE PROPERTY POSITION_INDEPENDENT_CODE True) @@ -153,6 +153,15 @@ target_sources (objSMCE PRIVATE include/SMCE/SketchConf.hpp include/SMCE/internal/BoardDeviceSpecification.hpp ) + +add_executable(SMCE_Cli src/SMCE/SMCE_Client.cpp) +target_link_libraries(SMCE_Cli + PRIVATE objSMCE HostUDD ipcSMCE BindGenProxies + PUBLIC iSMCE + ) +set (SMCE_RES "${PROJECT_BINARY_DIR}") +target_compile_definitions (SMCE_Cli PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") + if (NOT MSVC) target_compile_options (objSMCE PRIVATE "-Wall" "-Wextra" "-Wpedantic" "-Werror" "-Wcast-align") else () diff --git a/src/SMCE/SMCE_Client.cpp b/src/SMCE/SMCE_Client.cpp new file mode 100644 index 00000000..5b5bc0a6 --- /dev/null +++ b/src/SMCE/SMCE_Client.cpp @@ -0,0 +1,137 @@ +/* + * SMCE_Client.cpp + * Created by Rylander and Mejborn, Team 1, DAT265. + * + * A terminal interface for libSMCE, that allows sketches to be ran without a GUI. + * +*/ + +#ifndef SMCE_RESOURCES_DIR +# error "SMCE_RESOURCES_DIR is not set" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +void print_help(const char* argv0) { + std::cout << "Usage: " << argv0 << " " << std::endl; +} + +// Prints a simple command menu for SMCE_Cli +void print_menu(){ + std::cout << "SMCE Client menu:" << std::endl; + std::cout << "-h -> see menu" << std::endl; + std::cout << "-s -> start/resume" << std::endl; + std::cout << "-p -> pause" << std::endl; + std::cout << "-m -> send message to board" << std::endl; + std::cout << "-q -> quit" << std::endl; +} + +int main(int argc, char** argv){ + if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { + print_help(argv[0]); + return EXIT_SUCCESS; + } else if (argc != 3) { + print_help(argv[0]); + return EXIT_FAILURE; + } + //Saves and + char* fqbn = argv[1]; + char* path_to_sketch = argv[2]; + + std::cout << std::endl << "Starting SMCE Client" << std::endl; + std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; + + // Create the toolchain + smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; + if (const auto ec = toolchain.check_suitable_environment()) { + std::cerr << "Error: " << ec.message() << std::endl; + return EXIT_FAILURE; + } + + // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing + // clang-format off + smce::Sketch sketch{path_to_sketch, { + .fqbn = fqbn, + .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } + }}; + // // clang-format on + + std::cout << "Compiling..." << std::endl; + // Compile the sketch on the toolchain + if (const auto ec = toolchain.compile(sketch)) { + std::cerr << "Error: " << ec.message() << std::endl; + auto [_, log] = toolchain.build_log(); + if (!log.empty()) + std::cerr << log << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Creating board..." << std::endl; + // Create the virtual Arduino board + smce::Board board; + board.attach_sketch(sketch); + + // clang-format off + smce::BoardConfig board_conf{ + .uart_channels = { {} }, + .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } } + }; + board.configure(std::move(board_conf)); + // clang-format on + + std::cout << "Done" << std::endl; + + // Print command menu + print_menu(); + + // Main loop, handle the command input + while(true){ + std::string input; + std::cin >> input; + //TODO + //Split input, check if it has more then one string. + // If so its a message, error on more then 2 + if (input == "-h"){ + print_menu(); + }else if (input == "-s"){ + if(!board.start()){ + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + } + }else if (input == "-p"){ + //TODO + std::cout << "pause" << std::endl; + }else if (input == "-m"){ + //TODO + std::cout << "message" << std::endl; + }else if (input == "-q"){ + std::cout << "Quitting..." << std::endl; + board.stop(); + break; + }else if (input == "-io"){ + //TODO + std::cout << "GPIO pins..." << std::endl; + }else{ + std::cout << "Unknown input, try again." << std::endl; + } + } + + + + std::cout << "END"; +} \ No newline at end of file From 95a9a9e01689db24ae7c908bf39303182f5eb2eb Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 11 Oct 2021 17:05:27 +0200 Subject: [PATCH 02/18] Can now handle more then 1 input Implemented a way to handle more then one input, to make it possible for example sending message --- src/SMCE/SMCE_Client.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/SMCE/SMCE_Client.cpp b/src/SMCE/SMCE_Client.cpp index 5b5bc0a6..68101fa8 100644 --- a/src/SMCE/SMCE_Client.cpp +++ b/src/SMCE/SMCE_Client.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,9 @@ void print_menu(){ std::cout << "SMCE Client menu:" << std::endl; std::cout << "-h -> see menu" << std::endl; std::cout << "-s -> start/resume" << std::endl; - std::cout << "-p -> pause" << std::endl; + std::cout << "-p -> pause or resume" << std::endl; + std::cout << "-r -> reset board" << std::endl; + std::cout << "-io -> set a specific value on pin" << std::endl; std::cout << "-m -> send message to board" << std::endl; std::cout << "-q -> quit" << std::endl; } @@ -101,8 +104,10 @@ int main(int argc, char** argv){ // Main loop, handle the command input while(true){ + bool suspended = false; + std::cout << "$>"; std::string input; - std::cin >> input; + std::getline(std::cin,input); //TODO //Split input, check if it has more then one string. // If so its a message, error on more then 2 @@ -114,16 +119,23 @@ int main(int argc, char** argv){ return EXIT_FAILURE; } }else if (input == "-p"){ + suspended = board.suspend(); + if(!suspended){ + suspended = board.suspend(); + std::cout << "Board paused" << std::endl; + }else if(suspended){ + board.resume(); + suspended = false; + std::cout << "Board resumed" << std::endl; + } + }else if (input.starts_with("-m ")){ //TODO - std::cout << "pause" << std::endl; - }else if (input == "-m"){ - //TODO - std::cout << "message" << std::endl; + std::cout << "message" << " " << input.substr(2) << std::endl; }else if (input == "-q"){ std::cout << "Quitting..." << std::endl; board.stop(); break; - }else if (input == "-io"){ + }else if (input.starts_with("-io ")){ //TODO std::cout << "GPIO pins..." << std::endl; }else{ From ed37707cd213ba52dce0654c7680069fef72a110 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 13 Oct 2021 16:57:25 +0200 Subject: [PATCH 03/18] Implemented messaging through UART NOT WORKING! KNOWN BUG. --- src/SMCE/SMCE_Client.cpp | 119 ++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 40 deletions(-) diff --git a/src/SMCE/SMCE_Client.cpp b/src/SMCE/SMCE_Client.cpp index 68101fa8..a0f3c972 100644 --- a/src/SMCE/SMCE_Client.cpp +++ b/src/SMCE/SMCE_Client.cpp @@ -2,7 +2,9 @@ * SMCE_Client.cpp * Created by Rylander and Mejborn, Team 1, DAT265. * - * A terminal interface for libSMCE, that allows sketches to be ran without a GUI. + * A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. + * Functionally to test and debug sketches, as GPIO pins can be set with values and + * messages can be sent to board through uart. * */ @@ -10,6 +12,7 @@ # error "SMCE_RESOURCES_DIR is not set" #endif +#include #include #include #include @@ -28,20 +31,42 @@ using namespace std::literals; +// automic bool for handling threads +std::atomic_bool run_threads = true; + void print_help(const char* argv0) { std::cout << "Usage: " << argv0 << " " << std::endl; } +void exit_sketch(int t){ + std::cerr << "Error code: "<< std::hex << std::bit_cast(static_cast(t)) << std::endl; +} + +//Listen to the uart input from board, writes what it read to terminal +void uart_listener(auto uart){ + auto tx = uart.tx(); + while(run_threads){ + std::string buffer; + buffer.resize(tx.max_size()); + const auto len = tx.read(buffer); + if(len == 0){ + std::this_thread::sleep_for(1ms); + continue; + } + buffer.resize(len); + std::cout << buffer; + } +} -// Prints a simple command menu for SMCE_Cli +// Prints a command menu for SMCE_Client void print_menu(){ std::cout << "SMCE Client menu:" << std::endl; - std::cout << "-h -> see menu" << std::endl; - std::cout << "-s -> start/resume" << std::endl; - std::cout << "-p -> pause or resume" << std::endl; - std::cout << "-r -> reset board" << std::endl; - std::cout << "-io -> set a specific value on pin" << std::endl; - std::cout << "-m -> send message to board" << std::endl; - std::cout << "-q -> quit" << std::endl; + std::cout << "-h -> See menu" << std::endl; + std::cout << "-p -> Pause or resume the board" << std::endl; + std::cout << "-r -> Reset the board" << std::endl; + std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; + std::cout << "-wd -> Set a specific value on a digital pin" << std::endl; + std::cout << "-m -> Send message to board through uart (serial)" << std::endl; + std::cout << "-q -> Power off board and quit program" << std::endl; } int main(int argc, char** argv){ @@ -74,8 +99,8 @@ int main(int argc, char** argv){ }}; // // clang-format on - std::cout << "Compiling..." << std::endl; // Compile the sketch on the toolchain + std::cout << "Compiling..." << std::endl; if (const auto ec = toolchain.compile(sketch)) { std::cerr << "Error: " << ec.message() << std::endl; auto [_, log] = toolchain.build_log(); @@ -84,66 +109,80 @@ int main(int argc, char** argv){ return EXIT_FAILURE; } - std::cout << "Creating board..." << std::endl; // Create the virtual Arduino board - smce::Board board; + std::cout << "Creating board..." << std::endl; + smce::Board board(exit_sketch); board.attach_sketch(sketch); - // clang-format off + // Create board config smce::BoardConfig board_conf{ - .uart_channels = { {} }, + .uart_channels = { {} }, // use standard configuration of uart_channels .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } } }; board.configure(std::move(board_conf)); - // clang-format on - std::cout << "Done" << std::endl; + //Start board + if (!board.start()) { + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + }else{ + std::cout << "Sketch started" << std::endl; + } + + //Create view and uart (serial) channels + auto board_view = board.view(); + auto uart0 = board_view.uart_channels[0]; + + //start listener thread for uart + std::thread uart_thread{[=] {uart_listener(uart0);} }; + // Print command menu print_menu(); // Main loop, handle the command input + bool suspended = false; while(true){ - bool suspended = false; std::cout << "$>"; std::string input; std::getline(std::cin,input); - //TODO - //Split input, check if it has more then one string. - // If so its a message, error on more then 2 - if (input == "-h"){ + board.tick(); + if (input == "-h"){ //help menu print_menu(); - }else if (input == "-s"){ - if(!board.start()){ - std::cerr << "Error: Board failed to start sketch" << std::endl; - return EXIT_FAILURE; - } - }else if (input == "-p"){ - suspended = board.suspend(); + }else if (input == "-p"){ //pause or resume if(!suspended){ suspended = board.suspend(); - std::cout << "Board paused" << std::endl; + if(suspended) + std::cout << "Board paused" << std::endl; + else + std::cout << "Board could not be paused" << std::endl; }else if(suspended){ board.resume(); suspended = false; std::cout << "Board resumed" << std::endl; } - }else if (input.starts_with("-m ")){ - //TODO - std::cout << "message" << " " << input.substr(2) << std::endl; - }else if (input == "-q"){ + }else if (input == "-r"){ //reset + board.reset(); + }else if (input.starts_with("-m ")){ //send message on uart + std::string message = input.substr(3); + for(std::span to_write = message; !to_write.empty();){ + const auto written_count = uart0.rx().write(to_write); + std::cout << "Bytes written: " << written_count << std::endl; + to_write = to_write.subspan(written_count); + } + }else if (input == "-q"){ //power off and quit std::cout << "Quitting..." << std::endl; + run_threads = false; board.stop(); + uart_thread.join(); break; - }else if (input.starts_with("-io ")){ - //TODO - std::cout << "GPIO pins..." << std::endl; + }else if (input.starts_with("-wa ")){ //write value on analog pin + //TODO implement writing to analog GPIO pin. + }else if (input.starts_with("-wd ")){ //write value on digital pin + //TODO implement writing to digital GPIO pin. }else{ + //If input don't match with anything. std::cout << "Unknown input, try again." << std::endl; } } - - - - std::cout << "END"; } \ No newline at end of file From 7da05fd90052201a5b2d1acaa7aeb5f3514392de Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 21 Oct 2021 14:08:40 +0200 Subject: [PATCH 04/18] Refactored SMCE_Client to it own folder Move SMCE_Client to its own folder, created a CMakeLists that installs SMCE_Client.exe and copys the SMCE.dll from the path of enviroment variable SMCE_ROOT. --- CMakeLists.txt | 8 -------- {src/SMCE => Client}/SMCE_Client.cpp | 2 +- client/CMakeLists.txt | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) rename {src/SMCE => Client}/SMCE_Client.cpp (99%) create mode 100644 client/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 988fe99f..67462741 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,14 +154,6 @@ target_sources (objSMCE PRIVATE include/SMCE/internal/BoardDeviceSpecification.hpp ) -add_executable(SMCE_Cli src/SMCE/SMCE_Client.cpp) -target_link_libraries(SMCE_Cli - PRIVATE objSMCE HostUDD ipcSMCE BindGenProxies - PUBLIC iSMCE - ) -set (SMCE_RES "${PROJECT_BINARY_DIR}") -target_compile_definitions (SMCE_Cli PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") - if (NOT MSVC) target_compile_options (objSMCE PRIVATE "-Wall" "-Wextra" "-Wpedantic" "-Werror" "-Wcast-align") else () diff --git a/src/SMCE/SMCE_Client.cpp b/Client/SMCE_Client.cpp similarity index 99% rename from src/SMCE/SMCE_Client.cpp rename to Client/SMCE_Client.cpp index a0f3c972..30c0b2b5 100644 --- a/src/SMCE/SMCE_Client.cpp +++ b/Client/SMCE_Client.cpp @@ -1,5 +1,5 @@ /* - * SMCE_Client.cpp + * client/SMCE_Client.cpp * Created by Rylander and Mejborn, Team 1, DAT265. * * A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 00000000..b4103e8e --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# client/CMakeLists.txt +# Written by Rylander and Mejborn, Team 1, DAT265. +# +# + + +cmake_minimum_required (VERSION 3.16) +project (client) + +find_package (Threads REQUIRED) +find_package (SMCE REQUIRED) + +set (SMCE_RES "${PROJECT_BINARY_DIR}/SMCE_Res") + +add_executable (SMCE_client SMCE_Client.cpp) +target_link_libraries (SMCE_client PRIVATE SMCE::SMCE) +target_compile_definitions (SMCE_client PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") +file (MAKE_DIRECTORY "${SMCE_RES}") +execute_process (COMMAND "${CMAKE_COMMAND}" -E tar xf "${SMCE_RESOURCES_ARK}" + WORKING_DIRECTORY "${SMCE_RES}") + +add_custom_command (TARGET SMCE_client POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "$ENV{SMCE_ROOT}/bin/SMCE.dll" "${PROJECT_BINARY_DIR}/Debug" +) \ No newline at end of file From af112b48aab81a5730e30a9596d51cfbc5af4006 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 21 Oct 2021 14:17:47 +0200 Subject: [PATCH 05/18] Update CMakeLists.txt --- client/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index b4103e8e..6b18fef7 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -22,4 +22,4 @@ execute_process (COMMAND "${CMAKE_COMMAND}" -E tar xf "${SMCE_RESOURCES_ARK}" add_custom_command (TARGET SMCE_client POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "$ENV{SMCE_ROOT}/bin/SMCE.dll" "${PROJECT_BINARY_DIR}/Debug" -) \ No newline at end of file +) \ No newline at end of file From 023a2ae6eccbf529dd8a7e650b3cf976609542ce Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 25 Oct 2021 09:50:22 +0200 Subject: [PATCH 06/18] Added copy SMCE.dll post_build in cmake --- Client/SMCE_Client.cpp | 9 +++++---- client/CMakeLists.txt | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Client/SMCE_Client.cpp b/Client/SMCE_Client.cpp index 30c0b2b5..73ace8ea 100644 --- a/Client/SMCE_Client.cpp +++ b/Client/SMCE_Client.cpp @@ -34,11 +34,11 @@ using namespace std::literals; // automic bool for handling threads std::atomic_bool run_threads = true; -void print_help(const char* argv0) { +void print_help(const char* argv0){ std::cout << "Usage: " << argv0 << " " << std::endl; } -void exit_sketch(int t){ - std::cerr << "Error code: "<< std::hex << std::bit_cast(static_cast(t)) << std::endl; +void exit_sketch(int code){ + std::cerr << "Error code: "<< std::hex << std::bit_cast(static_cast(code)) << std::endl; } //Listen to the uart input from board, writes what it read to terminal @@ -66,7 +66,7 @@ void print_menu(){ std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; std::cout << "-wd -> Set a specific value on a digital pin" << std::endl; std::cout << "-m -> Send message to board through uart (serial)" << std::endl; - std::cout << "-q -> Power off board and quit program" << std::endl; + std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; } int main(int argc, char** argv){ @@ -84,6 +84,7 @@ int main(int argc, char** argv){ std::cout << std::endl << "Starting SMCE Client" << std::endl; std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; + // Create the toolchain smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; if (const auto ec = toolchain.check_suitable_environment()) { diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 6b18fef7..f15b8969 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -21,5 +21,5 @@ execute_process (COMMAND "${CMAKE_COMMAND}" -E tar xf "${SMCE_RESOURCES_ARK}" WORKING_DIRECTORY "${SMCE_RES}") add_custom_command (TARGET SMCE_client POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "$ENV{SMCE_ROOT}/bin/SMCE.dll" "${PROJECT_BINARY_DIR}/Debug" -) \ No newline at end of file + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "$" + ) \ No newline at end of file From 4bed0b091023489418254e0e74dda0e97fcd00ce Mon Sep 17 00:00:00 2001 From: Johan Mejborn Date: Thu, 28 Oct 2021 14:30:02 +0200 Subject: [PATCH 07/18] Added GPIO functionality to libSMCE client --- Client/SMCE_Client.cpp | 224 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 203 insertions(+), 21 deletions(-) diff --git a/Client/SMCE_Client.cpp b/Client/SMCE_Client.cpp index 73ace8ea..be219d1b 100644 --- a/Client/SMCE_Client.cpp +++ b/Client/SMCE_Client.cpp @@ -1,11 +1,11 @@ /* - * client/SMCE_Client.cpp - * Created by Rylander and Mejborn, Team 1, DAT265. - * - * A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. - * Functionally to test and debug sketches, as GPIO pins can be set with values and - * messages can be sent to board through uart. - * +* client/SMCE_Client.cpp +* Created by Rylander and Mejborn, Team 1, DAT265. +* +* A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. +* Functionally to test and debug sketches, as GPIO pins can be set with values and +* messages can be sent to board through uart. +* */ #ifndef SMCE_RESOURCES_DIR @@ -35,30 +35,38 @@ using namespace std::literals; std::atomic_bool run_threads = true; void print_help(const char* argv0){ +<<<<<<< Updated upstream std::cout << "Usage: " << argv0 << " " << std::endl; } void exit_sketch(int code){ std::cerr << "Error code: "<< std::hex << std::bit_cast(static_cast(code)) << std::endl; +======= + std::cout << "Usage: " << argv0 << " " << std::endl; } -//Listen to the uart input from board, writes what it read to terminal -void uart_listener(auto uart){ - auto tx = uart.tx(); - while(run_threads){ - std::string buffer; - buffer.resize(tx.max_size()); - const auto len = tx.read(buffer); - if(len == 0){ - std::this_thread::sleep_for(1ms); - continue; - } - buffer.resize(len); - std::cout << buffer; - } +void exit_sketch(int code){ + std::cerr << "Error code: "<< code << std::endl; +>>>>>>> Stashed changes } +//Listen to the uart input from board, writes what it read to terminal +void uart_listener(smce::VirtualUart uart){ + auto tx = uart.tx(); + while(run_threads){ + std::string buffer; + buffer.resize(tx.max_size()); + const auto len = tx.read(buffer); + if(len == 0){ + std::this_thread::sleep_for(1ms); + continue; + } + buffer.resize(len); + std::cout << buffer; + } +} // Prints a command menu for SMCE_Client void print_menu(){ +<<<<<<< Updated upstream std::cout << "SMCE Client menu:" << std::endl; std::cout << "-h -> See menu" << std::endl; std::cout << "-p -> Pause or resume the board" << std::endl; @@ -186,4 +194,178 @@ int main(int argc, char** argv){ std::cout << "Unknown input, try again." << std::endl; } } +======= + std::cout << "SMCE Client menu:" << std::endl; + std::cout << "-h -> See menu" << std::endl; + std::cout << "-p -> Pause or resume the board" << std::endl; + std::cout << "-r -> Reset the board" << std::endl; + std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; + std::cout << "-wd -> Set a specific value on a digital pin" << std::endl; + std::cout << "-m -> Send message to board through uart (serial)" << std::endl; + std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; +} + +int main(int argc, char** argv){ + if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { + print_help(argv[0]); + return EXIT_SUCCESS; + } else if (argc != 3) { + print_help(argv[0]); + return EXIT_FAILURE; + } + //Saves and + char* fqbn = argv[1]; + char* path_to_sketch = argv[2]; + + std::cout << std::endl << "Starting SMCE Client" << std::endl; + std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; + + + // Create the toolchain + smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; + if (const auto ec = toolchain.check_suitable_environment()) { + std::cerr << "Error: " << ec.message() << std::endl; + return EXIT_FAILURE; + } + + // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing + // clang-format off + smce::Sketch sketch{path_to_sketch, { + .fqbn = fqbn, + .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } + }}; + // // clang-format on + + // Compile the sketch on the toolchain + std::cout << "Compiling..." << std::endl; + if (const auto ec = toolchain.compile(sketch)) { + std::cerr << "Error: " << ec.message() << std::endl; + auto [_, log] = toolchain.build_log(); + if (!log.empty()) + std::cerr << log << std::endl; + return EXIT_FAILURE; + } + + // Create the virtual Arduino board + std::cout << "Creating board..." << std::endl; + smce::Board board(exit_sketch); + board.attach_sketch(sketch); + + // Create Board Config + smce::BoardConfig board_conf{ + .pins = {0,1}, //Creating pins & GPIO drivers + .gpio_drivers = { + smce::BoardConfig::GpioDrivers{0, + smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} + }, + smce::BoardConfig::GpioDrivers{1, + smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} + } + }, + .uart_channels = { {} }, // use standard configuration of uart_channels + .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } }, + .gpio_drivers = { {} } // use standard configuration of gpio_pins + }; + board.configure(std::move(board_conf)); + std::cout << "Done" << std::endl; + + //Start board + if (!board.start()) { + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + }else{ + std::cout << "Sketch started" << std::endl; + } + + //Create view and uart (serial) channels + auto board_view = board.view(); + auto uart0 = board_view.uart_channels[0]; + + //start listener thread for uart + std::thread uart_thread{[=] {uart_listener(uart0);} }; + + // Print command menu + print_menu(); + + // Main loop, handle the command input + bool suspended = false; + while(true){ + std::cout << "$>"; + std::string input; + std::getline(std::cin,input); + board.tick(); + if (input == "-h"){ //help menu + print_menu(); + }else if (input == "-p"){ //pause or resume + if(!suspended){ + suspended = board.suspend(); + if(suspended) + std::cout << "Board paused" << std::endl; + else + std::cout << "Board could not be paused" << std::endl; + }else if(suspended){ + board.resume(); + suspended = false; + std::cout << "Board resumed" << std::endl; + } + }else if (input == "-r"){ //reset + board.reset(); + }else if (input.starts_with("-m ")){ //send message on uart + std::string message = input.substr(3); + for(std::span to_write = message; !to_write.empty();){ + const auto written_count = uart0.rx().write(to_write); + std::cout << "Bytes written: " << written_count << std::endl; + to_write = to_write.subspan(written_count); + } + }else if (input == "-q"){ //power off and quit + std::cout << "Quitting..." << std::endl; + run_threads = false; + board.stop(); + uart_thread.join(); + break; + + }else if (input.starts_with("-wa ")){ //write value on analog pin + bool write = true; + int pin = stoi(input.substr(3,5)); + uint16_t value = stoi(input.substr(5)); + auto apin = board_view.pins[pin].analog(); + if(!apin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + write=false; + } + if(!apin.can_write()){ + std::cout << "Can't write to pin!" << std::endl; + std::cout << "Successful" << std::endl; + write=false; + } + if(write){ + apin.write(value); + std::cout << "Value from board: " << apin.read(); + } + }else if (input.starts_with("-wd ")){ //write value on digital pin + bool write = true; + int pin = stoi(input.substr(3,5)); + uint16_t value = stoi(input.substr(5)); + auto apin = board_view.pins[pin].digital(); + if(!apin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + std::cout << "Successful" << std::endl; + write=false; + } + if(!apin.can_write()){ + std::cout << "Can't write to pin!" << std::endl; + write=false; + } + if(write){ + apin.write(value); + std::cout << "Value from board: " << apin.read(); + } + }else{ + //If input don't match with anything. + std::cout << "Unknown input, try again." << std::endl; + } + } +>>>>>>> Stashed changes } \ No newline at end of file From ecdb59f0c3e6e5a24a7cd21155045a9468349fd7 Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Fri, 29 Oct 2021 15:23:41 +0200 Subject: [PATCH 08/18] Added functionality to read values on gpio pins --- Client/SMCE_Client.cpp | 371 ----------------------------------------- client/SMCE_Client.cpp | 265 +++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+), 371 deletions(-) delete mode 100644 Client/SMCE_Client.cpp create mode 100644 client/SMCE_Client.cpp diff --git a/Client/SMCE_Client.cpp b/Client/SMCE_Client.cpp deleted file mode 100644 index be219d1b..00000000 --- a/Client/SMCE_Client.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* -* client/SMCE_Client.cpp -* Created by Rylander and Mejborn, Team 1, DAT265. -* -* A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. -* Functionally to test and debug sketches, as GPIO pins can be set with values and -* messages can be sent to board through uart. -* -*/ - -#ifndef SMCE_RESOURCES_DIR -# error "SMCE_RESOURCES_DIR is not set" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::literals; - -// automic bool for handling threads -std::atomic_bool run_threads = true; - -void print_help(const char* argv0){ -<<<<<<< Updated upstream - std::cout << "Usage: " << argv0 << " " << std::endl; -} -void exit_sketch(int code){ - std::cerr << "Error code: "<< std::hex << std::bit_cast(static_cast(code)) << std::endl; -======= - std::cout << "Usage: " << argv0 << " " << std::endl; -} - -void exit_sketch(int code){ - std::cerr << "Error code: "<< code << std::endl; ->>>>>>> Stashed changes -} - -//Listen to the uart input from board, writes what it read to terminal -void uart_listener(smce::VirtualUart uart){ - auto tx = uart.tx(); - while(run_threads){ - std::string buffer; - buffer.resize(tx.max_size()); - const auto len = tx.read(buffer); - if(len == 0){ - std::this_thread::sleep_for(1ms); - continue; - } - buffer.resize(len); - std::cout << buffer; - } -} -// Prints a command menu for SMCE_Client -void print_menu(){ -<<<<<<< Updated upstream - std::cout << "SMCE Client menu:" << std::endl; - std::cout << "-h -> See menu" << std::endl; - std::cout << "-p -> Pause or resume the board" << std::endl; - std::cout << "-r -> Reset the board" << std::endl; - std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; - std::cout << "-wd -> Set a specific value on a digital pin" << std::endl; - std::cout << "-m -> Send message to board through uart (serial)" << std::endl; - std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; -} - -int main(int argc, char** argv){ - if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { - print_help(argv[0]); - return EXIT_SUCCESS; - } else if (argc != 3) { - print_help(argv[0]); - return EXIT_FAILURE; - } - //Saves and - char* fqbn = argv[1]; - char* path_to_sketch = argv[2]; - - std::cout << std::endl << "Starting SMCE Client" << std::endl; - std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; - - - // Create the toolchain - smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; - if (const auto ec = toolchain.check_suitable_environment()) { - std::cerr << "Error: " << ec.message() << std::endl; - return EXIT_FAILURE; - } - - // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing - // clang-format off - smce::Sketch sketch{path_to_sketch, { - .fqbn = fqbn, - .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } - }}; - // // clang-format on - - // Compile the sketch on the toolchain - std::cout << "Compiling..." << std::endl; - if (const auto ec = toolchain.compile(sketch)) { - std::cerr << "Error: " << ec.message() << std::endl; - auto [_, log] = toolchain.build_log(); - if (!log.empty()) - std::cerr << log << std::endl; - return EXIT_FAILURE; - } - - // Create the virtual Arduino board - std::cout << "Creating board..." << std::endl; - smce::Board board(exit_sketch); - board.attach_sketch(sketch); - - // Create board config - smce::BoardConfig board_conf{ - .uart_channels = { {} }, // use standard configuration of uart_channels - .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } } - }; - board.configure(std::move(board_conf)); - std::cout << "Done" << std::endl; - - //Start board - if (!board.start()) { - std::cerr << "Error: Board failed to start sketch" << std::endl; - return EXIT_FAILURE; - }else{ - std::cout << "Sketch started" << std::endl; - } - - //Create view and uart (serial) channels - auto board_view = board.view(); - auto uart0 = board_view.uart_channels[0]; - - //start listener thread for uart - std::thread uart_thread{[=] {uart_listener(uart0);} }; - - // Print command menu - print_menu(); - - // Main loop, handle the command input - bool suspended = false; - while(true){ - std::cout << "$>"; - std::string input; - std::getline(std::cin,input); - board.tick(); - if (input == "-h"){ //help menu - print_menu(); - }else if (input == "-p"){ //pause or resume - if(!suspended){ - suspended = board.suspend(); - if(suspended) - std::cout << "Board paused" << std::endl; - else - std::cout << "Board could not be paused" << std::endl; - }else if(suspended){ - board.resume(); - suspended = false; - std::cout << "Board resumed" << std::endl; - } - }else if (input == "-r"){ //reset - board.reset(); - }else if (input.starts_with("-m ")){ //send message on uart - std::string message = input.substr(3); - for(std::span to_write = message; !to_write.empty();){ - const auto written_count = uart0.rx().write(to_write); - std::cout << "Bytes written: " << written_count << std::endl; - to_write = to_write.subspan(written_count); - } - }else if (input == "-q"){ //power off and quit - std::cout << "Quitting..." << std::endl; - run_threads = false; - board.stop(); - uart_thread.join(); - break; - }else if (input.starts_with("-wa ")){ //write value on analog pin - //TODO implement writing to analog GPIO pin. - }else if (input.starts_with("-wd ")){ //write value on digital pin - //TODO implement writing to digital GPIO pin. - }else{ - //If input don't match with anything. - std::cout << "Unknown input, try again." << std::endl; - } - } -======= - std::cout << "SMCE Client menu:" << std::endl; - std::cout << "-h -> See menu" << std::endl; - std::cout << "-p -> Pause or resume the board" << std::endl; - std::cout << "-r -> Reset the board" << std::endl; - std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; - std::cout << "-wd -> Set a specific value on a digital pin" << std::endl; - std::cout << "-m -> Send message to board through uart (serial)" << std::endl; - std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; -} - -int main(int argc, char** argv){ - if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { - print_help(argv[0]); - return EXIT_SUCCESS; - } else if (argc != 3) { - print_help(argv[0]); - return EXIT_FAILURE; - } - //Saves and - char* fqbn = argv[1]; - char* path_to_sketch = argv[2]; - - std::cout << std::endl << "Starting SMCE Client" << std::endl; - std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; - - - // Create the toolchain - smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; - if (const auto ec = toolchain.check_suitable_environment()) { - std::cerr << "Error: " << ec.message() << std::endl; - return EXIT_FAILURE; - } - - // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing - // clang-format off - smce::Sketch sketch{path_to_sketch, { - .fqbn = fqbn, - .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } - }}; - // // clang-format on - - // Compile the sketch on the toolchain - std::cout << "Compiling..." << std::endl; - if (const auto ec = toolchain.compile(sketch)) { - std::cerr << "Error: " << ec.message() << std::endl; - auto [_, log] = toolchain.build_log(); - if (!log.empty()) - std::cerr << log << std::endl; - return EXIT_FAILURE; - } - - // Create the virtual Arduino board - std::cout << "Creating board..." << std::endl; - smce::Board board(exit_sketch); - board.attach_sketch(sketch); - - // Create Board Config - smce::BoardConfig board_conf{ - .pins = {0,1}, //Creating pins & GPIO drivers - .gpio_drivers = { - smce::BoardConfig::GpioDrivers{0, - smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} - }, - smce::BoardConfig::GpioDrivers{1, - smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} - } - }, - .uart_channels = { {} }, // use standard configuration of uart_channels - .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } }, - .gpio_drivers = { {} } // use standard configuration of gpio_pins - }; - board.configure(std::move(board_conf)); - std::cout << "Done" << std::endl; - - //Start board - if (!board.start()) { - std::cerr << "Error: Board failed to start sketch" << std::endl; - return EXIT_FAILURE; - }else{ - std::cout << "Sketch started" << std::endl; - } - - //Create view and uart (serial) channels - auto board_view = board.view(); - auto uart0 = board_view.uart_channels[0]; - - //start listener thread for uart - std::thread uart_thread{[=] {uart_listener(uart0);} }; - - // Print command menu - print_menu(); - - // Main loop, handle the command input - bool suspended = false; - while(true){ - std::cout << "$>"; - std::string input; - std::getline(std::cin,input); - board.tick(); - if (input == "-h"){ //help menu - print_menu(); - }else if (input == "-p"){ //pause or resume - if(!suspended){ - suspended = board.suspend(); - if(suspended) - std::cout << "Board paused" << std::endl; - else - std::cout << "Board could not be paused" << std::endl; - }else if(suspended){ - board.resume(); - suspended = false; - std::cout << "Board resumed" << std::endl; - } - }else if (input == "-r"){ //reset - board.reset(); - }else if (input.starts_with("-m ")){ //send message on uart - std::string message = input.substr(3); - for(std::span to_write = message; !to_write.empty();){ - const auto written_count = uart0.rx().write(to_write); - std::cout << "Bytes written: " << written_count << std::endl; - to_write = to_write.subspan(written_count); - } - }else if (input == "-q"){ //power off and quit - std::cout << "Quitting..." << std::endl; - run_threads = false; - board.stop(); - uart_thread.join(); - break; - - }else if (input.starts_with("-wa ")){ //write value on analog pin - bool write = true; - int pin = stoi(input.substr(3,5)); - uint16_t value = stoi(input.substr(5)); - auto apin = board_view.pins[pin].analog(); - if(!apin.exists()){ - std::cout << "Pin does not exist!" << std::endl; - write=false; - } - if(!apin.can_write()){ - std::cout << "Can't write to pin!" << std::endl; - std::cout << "Successful" << std::endl; - write=false; - } - if(write){ - apin.write(value); - std::cout << "Value from board: " << apin.read(); - } - }else if (input.starts_with("-wd ")){ //write value on digital pin - bool write = true; - int pin = stoi(input.substr(3,5)); - uint16_t value = stoi(input.substr(5)); - auto apin = board_view.pins[pin].digital(); - if(!apin.exists()){ - std::cout << "Pin does not exist!" << std::endl; - std::cout << "Successful" << std::endl; - write=false; - } - if(!apin.can_write()){ - std::cout << "Can't write to pin!" << std::endl; - write=false; - } - if(write){ - apin.write(value); - std::cout << "Value from board: " << apin.read(); - } - }else{ - //If input don't match with anything. - std::cout << "Unknown input, try again." << std::endl; - } - } ->>>>>>> Stashed changes -} \ No newline at end of file diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp new file mode 100644 index 00000000..a48fea02 --- /dev/null +++ b/client/SMCE_Client.cpp @@ -0,0 +1,265 @@ +/* +* client/SMCE_Client.cpp +* Created by Rylander and Mejborn, Team 1, DAT265. +* +* A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. +* Functionally to test and debug sketches, as GPIO pins can be set with values and +* messages can be sent to board through uart. +* +*/ + +#ifndef SMCE_RESOURCES_DIR +# error "SMCE_RESOURCES_DIR is not set" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +// automic bool for handling threads +std::atomic_bool run_threads = true; + +void print_help(const char* argv0){ + std::cout << "Usage: " << argv0 << " " << std::endl; +} + +void exit_sketch(int code){ + std::cerr << "Error code: "<< code << std::endl; +} + +//Listen to the uart input from board, writes what it read to terminal +void uart_listener(smce::VirtualUart uart){ + auto tx = uart.tx(); + while(run_threads){ + std::string buffer; + buffer.resize(tx.max_size()); + const auto len = tx.read(buffer); + if(len == 0){ + std::this_thread::sleep_for(1ms); + continue; + } + buffer.resize(len); + std::cout << buffer << std::endl << std::flush; + } +} +// Prints a command menu for SMCE_Client +void print_menu(){ + std::cout << "SMCE Client menu:" << std::endl; + std::cout << "-h -> See menu" << std::endl; + std::cout << "-p -> Pause or resume the board" << std::endl; + std::cout << "-r -> Reset the board" << std::endl; + std::cout << "-m -> Send message to board through uart (serial)" << std::endl; + std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; + std::cout << "-wd -> Set a specific value on a digital pin, value should be 0 or 1" << std::endl; + std::cout << "-ra -> Read the value on a analog pin" << std::endl; + std::cout << "-rd -> Read the value on a analog pin" << std::endl; + std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; +} + +int main(int argc, char** argv){ + if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { + print_help(argv[0]); + return EXIT_SUCCESS; + } else if (argc != 3) { + print_help(argv[0]); + return EXIT_FAILURE; + } + //Saves and + char* fqbn = argv[1]; + char* path_to_sketch = argv[2]; + + std::cout << std::endl << "Starting SMCE Client" << std::endl; + std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; + + + // Create the toolchain + smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; + if (const auto ec = toolchain.check_suitable_environment()) { + std::cerr << "Error: " << ec.message() << std::endl; + return EXIT_FAILURE; + } + + // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing + // clang-format off + smce::Sketch sketch{path_to_sketch, { + .fqbn = fqbn, + .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } + }}; + // // clang-format on + + // Compile the sketch on the toolchain + std::cout << "Compiling..." << std::endl; + if (const auto ec = toolchain.compile(sketch)) { + std::cerr << "Error: " << ec.message() << std::endl; + auto [_, log] = toolchain.build_log(); + if (!log.empty()) + std::cerr << log << std::endl; + return EXIT_FAILURE; + } + + // Create the virtual Arduino board + std::cout << "Creating board..." << std::endl; + smce::Board board(exit_sketch); + board.attach_sketch(sketch); + + // Create Board Config + smce::BoardConfig board_conf{ + .pins = {0,1}, //Creating pins & GPIO drivers + .gpio_drivers = { + smce::BoardConfig::GpioDrivers{0, + smce::BoardConfig::GpioDrivers::DigitalDriver{true, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{true, true} + }, + smce::BoardConfig::GpioDrivers{1, + smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} + } + }, + .uart_channels = { {} }, // use standard configuration of uart_channels + .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } } + }; + board.configure(std::move(board_conf)); + std::cout << "Done" << std::endl; + + //Start board + if (!board.start()) { + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + }else{ + std::cout << "Sketch started" << std::endl; + } + + //Create view and uart (serial) channels + auto board_view = board.view(); + auto uart0 = board_view.uart_channels[0]; + + //start listener thread for uart + std::thread uart_thread{[=] {uart_listener(uart0);} }; + + // Print command menu + print_menu(); + + // Main loop, handle the command input + bool suspended = false; + while(true){ + std::cout << "$>"; + std::string input; + std::getline(std::cin,input); + board.tick(); + if (input == "-h"){ //help menu + print_menu(); + }else if (input == "-p"){ //pause or resume + if(!suspended){ + suspended = board.suspend(); + if(suspended) + std::cout << "Board paused" << std::endl; + else + std::cout << "Board could not be paused" << std::endl; + }else if(suspended){ + board.resume(); + suspended = false; + std::cout << "Board resumed" << std::endl; + } + }else if (input == "-r"){ //reset + board.reset(); + }else if (input.starts_with("-m ")){ //send message on uart + std::string message = input.substr(3); + for(std::span to_write = message; !to_write.empty();){ + const auto written_count = uart0.rx().write(to_write); + to_write = to_write.subspan(written_count); + } + }else if (input.starts_with("-wa ")){ //write value on analog pin + bool write = true; + int pin = stoi(input.substr(3,5)); + uint16_t value = stoi(input.substr(5)); + auto apin = board_view.pins[pin].analog(); + if(!apin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + write=false; + } + if(!apin.can_write()){ + std::cout << "Can't write to pin!" << std::endl; + write=false; + } + if(write){ + apin.write(value); + } + }else if (input.starts_with("-wd ")){ //write value on digital pin + bool write = true; + int pin = stoi(input.substr(3,5)); + uint16_t value = stoi(input.substr(5)); + auto apin = board_view.pins[pin].digital(); + if(!apin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + write=false; + } + if(!apin.can_write()){ + std::cout << "Can't write to pin!" << std::endl; + write=false; + } + if(write){ + if(value == 0){ + apin.write(false); + }else if(value == 1){ + apin.write(true); + }else{ + std::cout << "Value must be 0 or 1 for digital pins" << std::endl; + } + } + }else if (input.starts_with("-ra ")){ + bool read = true; + int index_pin = stoi(input.substr(3)); + auto pin = board_view.pins[index_pin].analog(); + if(!pin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + read=false; + } + if(!pin.can_read()){ + std::cout << "Can't read from pin!" << std::endl; + read=false; + } + if(read){ + std::cout << "Value from pin " << index_pin << " is " << pin.read() << std::endl; + } + }else if (input.starts_with("-rd ")){ + bool read = true; + int index_pin = stoi(input.substr(3)); + auto pin = board_view.pins[index_pin].digital(); + if(!pin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + read=false; + } + if(!pin.can_read()){ + std::cout << "Can't read from pin!" << std::endl; + read=false; + } + if(read){ + std::cout << "Value from pin " << index_pin << " is " << pin.read() << std::endl; + } + }else if (input == "-q"){ //power off and quit + std::cout << "Quitting..." << std::endl; + run_threads = false; + board.stop(); + uart_thread.join(); + break; + }else{ + //If input don't match with anything. + std::cout << "Unknown input, try again." << std::endl; + } + } +} \ No newline at end of file From 84390c5d4ea1574288d4775c7b45e14adefa95a1 Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Wed, 3 Nov 2021 14:54:37 +0100 Subject: [PATCH 09/18] Fixed typo --- client/SMCE_Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index a48fea02..3329ec6c 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -67,7 +67,7 @@ void print_menu(){ std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; std::cout << "-wd -> Set a specific value on a digital pin, value should be 0 or 1" << std::endl; std::cout << "-ra -> Read the value on a analog pin" << std::endl; - std::cout << "-rd -> Read the value on a analog pin" << std::endl; + std::cout << "-rd -> Read the value on a digital pin" << std::endl; std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; } From b5d35203052da21a218b8ff76bff96efd66ea58f Mon Sep 17 00:00:00 2001 From: Johan Mejborn Date: Wed, 3 Nov 2021 17:25:35 +0100 Subject: [PATCH 10/18] Known bug: Issues with thread --- client/SMCE_Client.cpp | 530 ++++++++++++++++++++--------------------- 1 file changed, 265 insertions(+), 265 deletions(-) diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index 3329ec6c..e1cc37ad 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -1,265 +1,265 @@ -/* -* client/SMCE_Client.cpp -* Created by Rylander and Mejborn, Team 1, DAT265. -* -* A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. -* Functionally to test and debug sketches, as GPIO pins can be set with values and -* messages can be sent to board through uart. -* -*/ - -#ifndef SMCE_RESOURCES_DIR -# error "SMCE_RESOURCES_DIR is not set" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::literals; - -// automic bool for handling threads -std::atomic_bool run_threads = true; - -void print_help(const char* argv0){ - std::cout << "Usage: " << argv0 << " " << std::endl; -} - -void exit_sketch(int code){ - std::cerr << "Error code: "<< code << std::endl; -} - -//Listen to the uart input from board, writes what it read to terminal -void uart_listener(smce::VirtualUart uart){ - auto tx = uart.tx(); - while(run_threads){ - std::string buffer; - buffer.resize(tx.max_size()); - const auto len = tx.read(buffer); - if(len == 0){ - std::this_thread::sleep_for(1ms); - continue; - } - buffer.resize(len); - std::cout << buffer << std::endl << std::flush; - } -} -// Prints a command menu for SMCE_Client -void print_menu(){ - std::cout << "SMCE Client menu:" << std::endl; - std::cout << "-h -> See menu" << std::endl; - std::cout << "-p -> Pause or resume the board" << std::endl; - std::cout << "-r -> Reset the board" << std::endl; - std::cout << "-m -> Send message to board through uart (serial)" << std::endl; - std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; - std::cout << "-wd -> Set a specific value on a digital pin, value should be 0 or 1" << std::endl; - std::cout << "-ra -> Read the value on a analog pin" << std::endl; - std::cout << "-rd -> Read the value on a digital pin" << std::endl; - std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; -} - -int main(int argc, char** argv){ - if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { - print_help(argv[0]); - return EXIT_SUCCESS; - } else if (argc != 3) { - print_help(argv[0]); - return EXIT_FAILURE; - } - //Saves and - char* fqbn = argv[1]; - char* path_to_sketch = argv[2]; - - std::cout << std::endl << "Starting SMCE Client" << std::endl; - std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; - - - // Create the toolchain - smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; - if (const auto ec = toolchain.check_suitable_environment()) { - std::cerr << "Error: " << ec.message() << std::endl; - return EXIT_FAILURE; - } - - // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing - // clang-format off - smce::Sketch sketch{path_to_sketch, { - .fqbn = fqbn, - .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } - }}; - // // clang-format on - - // Compile the sketch on the toolchain - std::cout << "Compiling..." << std::endl; - if (const auto ec = toolchain.compile(sketch)) { - std::cerr << "Error: " << ec.message() << std::endl; - auto [_, log] = toolchain.build_log(); - if (!log.empty()) - std::cerr << log << std::endl; - return EXIT_FAILURE; - } - - // Create the virtual Arduino board - std::cout << "Creating board..." << std::endl; - smce::Board board(exit_sketch); - board.attach_sketch(sketch); - - // Create Board Config - smce::BoardConfig board_conf{ - .pins = {0,1}, //Creating pins & GPIO drivers - .gpio_drivers = { - smce::BoardConfig::GpioDrivers{0, - smce::BoardConfig::GpioDrivers::DigitalDriver{true, true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{true, true} - }, - smce::BoardConfig::GpioDrivers{1, - smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} - } - }, - .uart_channels = { {} }, // use standard configuration of uart_channels - .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = "." } } - }; - board.configure(std::move(board_conf)); - std::cout << "Done" << std::endl; - - //Start board - if (!board.start()) { - std::cerr << "Error: Board failed to start sketch" << std::endl; - return EXIT_FAILURE; - }else{ - std::cout << "Sketch started" << std::endl; - } - - //Create view and uart (serial) channels - auto board_view = board.view(); - auto uart0 = board_view.uart_channels[0]; - - //start listener thread for uart - std::thread uart_thread{[=] {uart_listener(uart0);} }; - - // Print command menu - print_menu(); - - // Main loop, handle the command input - bool suspended = false; - while(true){ - std::cout << "$>"; - std::string input; - std::getline(std::cin,input); - board.tick(); - if (input == "-h"){ //help menu - print_menu(); - }else if (input == "-p"){ //pause or resume - if(!suspended){ - suspended = board.suspend(); - if(suspended) - std::cout << "Board paused" << std::endl; - else - std::cout << "Board could not be paused" << std::endl; - }else if(suspended){ - board.resume(); - suspended = false; - std::cout << "Board resumed" << std::endl; - } - }else if (input == "-r"){ //reset - board.reset(); - }else if (input.starts_with("-m ")){ //send message on uart - std::string message = input.substr(3); - for(std::span to_write = message; !to_write.empty();){ - const auto written_count = uart0.rx().write(to_write); - to_write = to_write.subspan(written_count); - } - }else if (input.starts_with("-wa ")){ //write value on analog pin - bool write = true; - int pin = stoi(input.substr(3,5)); - uint16_t value = stoi(input.substr(5)); - auto apin = board_view.pins[pin].analog(); - if(!apin.exists()){ - std::cout << "Pin does not exist!" << std::endl; - write=false; - } - if(!apin.can_write()){ - std::cout << "Can't write to pin!" << std::endl; - write=false; - } - if(write){ - apin.write(value); - } - }else if (input.starts_with("-wd ")){ //write value on digital pin - bool write = true; - int pin = stoi(input.substr(3,5)); - uint16_t value = stoi(input.substr(5)); - auto apin = board_view.pins[pin].digital(); - if(!apin.exists()){ - std::cout << "Pin does not exist!" << std::endl; - write=false; - } - if(!apin.can_write()){ - std::cout << "Can't write to pin!" << std::endl; - write=false; - } - if(write){ - if(value == 0){ - apin.write(false); - }else if(value == 1){ - apin.write(true); - }else{ - std::cout << "Value must be 0 or 1 for digital pins" << std::endl; - } - } - }else if (input.starts_with("-ra ")){ - bool read = true; - int index_pin = stoi(input.substr(3)); - auto pin = board_view.pins[index_pin].analog(); - if(!pin.exists()){ - std::cout << "Pin does not exist!" << std::endl; - read=false; - } - if(!pin.can_read()){ - std::cout << "Can't read from pin!" << std::endl; - read=false; - } - if(read){ - std::cout << "Value from pin " << index_pin << " is " << pin.read() << std::endl; - } - }else if (input.starts_with("-rd ")){ - bool read = true; - int index_pin = stoi(input.substr(3)); - auto pin = board_view.pins[index_pin].digital(); - if(!pin.exists()){ - std::cout << "Pin does not exist!" << std::endl; - read=false; - } - if(!pin.can_read()){ - std::cout << "Can't read from pin!" << std::endl; - read=false; - } - if(read){ - std::cout << "Value from pin " << index_pin << " is " << pin.read() << std::endl; - } - }else if (input == "-q"){ //power off and quit - std::cout << "Quitting..." << std::endl; - run_threads = false; - board.stop(); - uart_thread.join(); - break; - }else{ - //If input don't match with anything. - std::cout << "Unknown input, try again." << std::endl; - } - } -} \ No newline at end of file +/* +* client/SMCE_Client.cpp +* Created by Rylander and Mejborn, Team 1, DAT265. +* +* A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. +* Functionally to test and debug sketches, as GPIO pins can be set with values and +* messages can be sent to board through uart. +* +*/ + +#ifndef SMCE_RESOURCES_DIR +# error "SMCE_RESOURCES_DIR is not set" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +// automic bool for handling threads +std::atomic_bool run_threads = true; +// Standard arduino dir +std::string dir = "."; +void print_help(const char* argv0){ + std::cout << "Usage: " << argv0 << " " << std::endl; +} + +void exit_sketch(int code){ + std::cerr << "Error code: "<< code << std::endl; +} + +//Listen to the uart input from board, writes what it read to terminal +void uart_listener(smce::VirtualUart uart){ + auto tx = uart.tx(); + while(run_threads){ + std::string buffer; + buffer.resize(tx.max_size()); + const auto len = tx.read(buffer); + if(len == 0){ + std::this_thread::sleep_for(1ms); + continue; + } + buffer.resize(len); + std::cout << buffer << std::endl << std::flush; + } +} +// Prints a command menu for SMCE_Client +void print_menu(){ + std::cout << "SMCE Client menu:" << std::endl; + std::cout << "-h -> See menu" << std::endl; + std::cout << "-p -> Pause or resume the board" << std::endl; + std::cout << "-rc -> Recompile the sketch" << std::endl; + std::cout << "-m -> Send message to board through uart (serial)" << std::endl; + std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; + std::cout << "-wd -> Set a specific value on a digital pin, value should be 0 or 1" << std::endl; + std::cout << "-ra -> Read the value on a analog pin" << std::endl; + std::cout << "-rd -> Read the value on a digital pin" << std::endl; + std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; +} + +int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board) { + // Compile the sketch on the toolchain + std::cout << "Compiling..." << std::endl; + if (const auto ec = toolchain.compile(sketch)) { + std::cerr << "Error: " << ec.message() << std::endl; + auto [_, log] = toolchain.build_log(); + if (!log.empty()) + std::cerr << log << std::endl; + return EXIT_FAILURE; + } + std::cout << "Attach..." << std::endl; + board.attach_sketch(sketch); + // Create Board Config + smce::BoardConfig board_conf{ + .pins = {0,1}, //Creating pins & GPIO drivers + .gpio_drivers = { + smce::BoardConfig::GpioDrivers{0, + smce::BoardConfig::GpioDrivers::DigitalDriver{true, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{true, true} + }, + smce::BoardConfig::GpioDrivers{1, + smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} + } + }, + .uart_channels = { {} }, // use standard configuration of uart_channels + .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = dir } } + }; + std::cout << "Configures..." << std::endl; + board.configure(std::move(board_conf)); + return 0; +} + +int main(int argc, char** argv){ + if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { + print_help(argv[0]); + return EXIT_SUCCESS; + } else if (argc != 3) { + print_help(argv[0]); + return EXIT_FAILURE; + } + //Saves and + char* fqbn = argv[1]; + char* path_to_sketch = argv[2]; + + std::cout << std::endl << "Starting SMCE Client" << std::endl; + std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; + + // Create the toolchain + smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; + if (const auto ec = toolchain.check_suitable_environment()) { + std::cerr << "Error: " << ec.message() << std::endl; + return EXIT_FAILURE; + } + + // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing + // clang-format off + smce::Sketch sketch{path_to_sketch, { + .fqbn = fqbn, + .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } + }}; + // // clang-format on + + // Create the virtual Arduino board + std::cout << "Creating board..." << std::endl; + smce::Board board(exit_sketch); + compile_sketch(sketch,toolchain,board); + + //Start board + if (!board.start()) { + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + }else{ + std::cout << "Sketch started" << std::endl; + } + + //Create view and uart (serial) channels + auto board_view = board.view(); + auto uart0 = board_view.uart_channels[0]; + + //start listener thread for uart + std::thread uart_thread{[=] {uart_listener(uart0);} }; + + // Print command menu + print_menu(); + + // Main loop, handle the command input + bool suspended = false; + while(true){ + std::cout << "$>"; + std::string input; + std::getline(std::cin,input); + board.tick(); + if (input == "-h"){ //help menu + print_menu(); + }else if (input == "-p"){ //pause or resume + if(!suspended){ + suspended = board.suspend(); + if(suspended) + std::cout << "Board paused" << std::endl; + else + std::cout << "Board could not be paused" << std::endl; + }else if(suspended){ + board.resume(); + suspended = false; + std::cout << "Board resumed" << std::endl; + } + }else if (input == "-rc"){ //recompile + std::cout << "1" << std::endl; + run_threads = false; + board.stop(); + std::cout << "2" << std::endl; + board.reset(); + std::cout << "3" << std::endl; + compile_sketch(sketch,toolchain,board); + std::cout << "4" << std::endl; + board.start(); + board_view = board.view(); + uart0 = board_view.uart_channels[0]; + std::cout << "Complete" << std::endl; + }else if (input.starts_with("-m ")){ //send message on uart + std::string message = input.substr(3); + for(std::span to_write = message; !to_write.empty();){ + const auto written_count = uart0.rx().write(to_write); + to_write = to_write.subspan(written_count); + } + }else if (input.starts_with("-wa ")){ //write value on analog pin + bool write = true; + int pin = stoi(input.substr(3,5)); + uint16_t value = stoi(input.substr(5)); + auto apin = board_view.pins[pin].analog(); + if(!apin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + write=false; + } + if(!apin.can_write()){ + std::cout << "Can't write to pin!" << std::endl; + write=false; + } + if(write){ + apin.write(value); + } + }else if (input.starts_with("-wd ")){ //write value on digital pin + bool write = true; + int pin = stoi(input.substr(3,5)); + uint16_t value = stoi(input.substr(5)); + auto apin = board_view.pins[pin].digital(); + if(!apin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + write=false; + } + if(!apin.can_write()){ + std::cout << "Can't write to pin!" << std::endl; + write=false; + } + if(write){ + if(value == 0){ + apin.write(false); + }else if(value == 1){ + apin.write(true); + }else{ + std::cout << "Value must be 0 or 1 for digital pins" << std::endl; + } + } + }else if (input.starts_with("-ra ")){ + bool read = true; + int index_pin = stoi(input.substr(3)); + auto pin = board_view.pins[index_pin].analog(); + if(!pin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + read=false; + } + if(!pin.can_read()){ + std::cout << "Can't read from pin!" << std::endl; + read=false; + } + if(read){ + std::cout << "Value from pin " << index_pin << " is " << pin.read() << std::endl; + } + }else if (input.starts_with("-rd ")){ + bool read = true; + int index_pin = stoi(input.substr(3)); + auto pin = board_view.pins[index_pin].digital(); + if(!pin.exists()){ + std::cout << "Pin does not exist!" << std::endl; + read=false; + } + if(!pin.can_read()){ + std::cout << "Can't read from pin!" << std::endl; + read=false; + } \ No newline at end of file From 68eb00b70b120f04e23b86db916e5462e8a768c2 Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Wed, 10 Nov 2021 13:07:29 +0100 Subject: [PATCH 11/18] Recompile, mute and color added Fixed bugg with recompile causing thread to crash. Added termcolor library to set color for uart messages. Added mute for uart messages. --- client/CMakeLists.txt | 1 + client/SMCE_Client.cpp | 179 ++++--- client/include/termcolor.hpp | 911 +++++++++++++++++++++++++++++++++++ 3 files changed, 1023 insertions(+), 68 deletions(-) create mode 100644 client/include/termcolor.hpp diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f15b8969..715490f6 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -13,6 +13,7 @@ find_package (SMCE REQUIRED) set (SMCE_RES "${PROJECT_BINARY_DIR}/SMCE_Res") +include_directories(${PROJECT_SOURCE_DIR}/include) add_executable (SMCE_client SMCE_Client.cpp) target_link_libraries (SMCE_client PRIVATE SMCE::SMCE) target_compile_definitions (SMCE_client PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index e1cc37ad..be398ef3 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -21,20 +21,18 @@ #include #include #include -#include +#include +#include #include #include #include #include #include -#include +#include + using namespace std::literals; - -// automic bool for handling threads -std::atomic_bool run_threads = true; -// Standard arduino dir -std::string dir = "."; + void print_help(const char* argv0){ std::cout << "Usage: " << argv0 << " " << std::endl; } @@ -42,20 +40,28 @@ void print_help(const char* argv0){ void exit_sketch(int code){ std::cerr << "Error code: "<< code << std::endl; } - + +// automic bool for handling threads +std::atomic_bool run_threads = true; +std::atomic_bool mute_uart = false; +std::mutex t_lock; //Listen to the uart input from board, writes what it read to terminal void uart_listener(smce::VirtualUart uart){ auto tx = uart.tx(); while(run_threads){ - std::string buffer; + std::string buffer; + t_lock.lock(); // if recompiling sketch, lock thread here untill recompiling is done. buffer.resize(tx.max_size()); - const auto len = tx.read(buffer); + const auto len = tx.read(buffer); + t_lock.unlock(); if(len == 0){ std::this_thread::sleep_for(1ms); continue; } - buffer.resize(len); - std::cout << buffer << std::endl << std::flush; + buffer.resize(len); + if(!mute_uart){ + std::cout << termcolor::red << buffer << termcolor::reset <" << std::flush; + } } } // Prints a command menu for SMCE_Client @@ -64,25 +70,26 @@ void print_menu(){ std::cout << "-h -> See menu" << std::endl; std::cout << "-p -> Pause or resume the board" << std::endl; std::cout << "-rc -> Recompile the sketch" << std::endl; - std::cout << "-m -> Send message to board through uart (serial)" << std::endl; + std::cout << "-m -> Send message to board through uart (serial)" << std::endl; + std::cout << "-mt -> disable uart prints in console" << std::endl; std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; std::cout << "-wd -> Set a specific value on a digital pin, value should be 0 or 1" << std::endl; std::cout << "-ra -> Read the value on a analog pin" << std::endl; std::cout << "-rd -> Read the value on a digital pin" << std::endl; std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; } - + +// Standard arduino dir +std::string dir = "."; int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board) { - // Compile the sketch on the toolchain - std::cout << "Compiling..." << std::endl; + // Compile the sketch on the toolchain if (const auto ec = toolchain.compile(sketch)) { std::cerr << "Error: " << ec.message() << std::endl; auto [_, log] = toolchain.build_log(); if (!log.empty()) std::cerr << log << std::endl; return EXIT_FAILURE; - } - std::cout << "Attach..." << std::endl; + } board.attach_sketch(sketch); // Create Board Config smce::BoardConfig board_conf{ @@ -99,11 +106,25 @@ int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board }, .uart_channels = { {} }, // use standard configuration of uart_channels .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = dir } } - }; - std::cout << "Configures..." << std::endl; + }; board.configure(std::move(board_conf)); return 0; -} +} + +int compile_and_start(smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board){ + if(board.status() == smce::Board::Status::running){ + board.stop(); + board.reset(); + } + compile_sketch(sketch,toolchain,board); + //Start board + if (!board.start()) { + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + }else{ + return 0; + } +} int main(int argc, char** argv){ if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { @@ -136,28 +157,21 @@ int main(int argc, char** argv){ // // clang-format on // Create the virtual Arduino board - std::cout << "Creating board..." << std::endl; - smce::Board board(exit_sketch); - compile_sketch(sketch,toolchain,board); - - //Start board - if (!board.start()) { - std::cerr << "Error: Board failed to start sketch" << std::endl; - return EXIT_FAILURE; - }else{ - std::cout << "Sketch started" << std::endl; - } - + std::cout << "Creating board and compiling sketch" << std::endl; + smce::Board board(exit_sketch); + //Compile and start board + compile_and_start(sketch,toolchain,board); + std::cout << "Complete" << std::endl; //Create view and uart (serial) channels auto board_view = board.view(); auto uart0 = board_view.uart_channels[0]; //start listener thread for uart std::thread uart_thread{[=] {uart_listener(uart0);} }; - + std::cout << "Messages recived on uart from arduino is shown as " + << termcolor::red << "red" << termcolor::reset << " text." << std::endl; // Print command menu - print_menu(); - + print_menu(); // Main loop, handle the command input bool suspended = false; while(true){ @@ -166,8 +180,9 @@ int main(int argc, char** argv){ std::getline(std::cin,input); board.tick(); if (input == "-h"){ //help menu - print_menu(); - }else if (input == "-p"){ //pause or resume + print_menu(); + + }else if (input == "-p"){ //pause or resume if(!suspended){ suspended = board.suspend(); if(suspended) @@ -178,26 +193,34 @@ int main(int argc, char** argv){ board.resume(); suspended = false; std::cout << "Board resumed" << std::endl; - } - }else if (input == "-rc"){ //recompile - std::cout << "1" << std::endl; - run_threads = false; - board.stop(); - std::cout << "2" << std::endl; - board.reset(); - std::cout << "3" << std::endl; - compile_sketch(sketch,toolchain,board); - std::cout << "4" << std::endl; - board.start(); - board_view = board.view(); - uart0 = board_view.uart_channels[0]; - std::cout << "Complete" << std::endl; + } + + }else if (input == "-rc"){ //recompile + std::cout << "Recompiling.." << std::endl; + t_lock.lock(); // aquire lock before recompiling, so uart_listener is forced to wait + compile_and_start(sketch,toolchain,board); + // update boardview and uart0 after the sketch has been recompiled. + board_view = board.view(); + uart0 = board_view.uart_channels[0]; + t_lock.unlock(); // unlock as recompile is done + std::cout << "Complete" << std::endl; + }else if (input.starts_with("-m ")){ //send message on uart std::string message = input.substr(3); for(std::span to_write = message; !to_write.empty();){ const auto written_count = uart0.rx().write(to_write); to_write = to_write.subspan(written_count); - } + } + + }else if(input.starts_with("-mt")){ + if(mute_uart){ + mute_uart = false; + std::cout <<"Unmuted uart"< +#include + +// Detect target's platform and set some macros in order to wrap platform +// specific code this library depends on. +#if defined(_WIN32) || defined(_WIN64) +# define TERMCOLOR_TARGET_WINDOWS +#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) +# define TERMCOLOR_TARGET_POSIX +#endif + +// If implementation has not been explicitly set, try to choose one based on +// target platform. +#if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP) +# if defined(TERMCOLOR_TARGET_POSIX) +# define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES +# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION +# elif defined(TERMCOLOR_TARGET_WINDOWS) +# define TERMCOLOR_USE_WINDOWS_API +# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION +# endif +#endif + +// These headers provide isatty()/fileno() functions, which are used for +// testing whether a standard stream refers to the terminal. +#if defined(TERMCOLOR_TARGET_POSIX) +# include +#elif defined(TERMCOLOR_TARGET_WINDOWS) +# include +# include +#endif + + +namespace termcolor +{ + // Forward declaration of the `_internal` namespace. + // All comments are below. + namespace _internal + { + inline int colorize_index(); + inline FILE* get_standard_stream(const std::ostream& stream); + inline bool is_colorized(std::ostream& stream); + inline bool is_atty(const std::ostream& stream); + + #if defined(TERMCOLOR_TARGET_WINDOWS) + inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1); + #endif + } + + inline + std::ostream& colorize(std::ostream& stream) + { + stream.iword(_internal::colorize_index()) = 1L; + return stream; + } + + inline + std::ostream& nocolorize(std::ostream& stream) + { + stream.iword(_internal::colorize_index()) = 0L; + return stream; + } + + inline + std::ostream& reset(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[00m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, -1); + #endif + } + return stream; + } + + inline + std::ostream& bold(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[1m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& dark(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[2m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& italic(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[3m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& underline(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[4m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE); + #endif + } + return stream; + } + + inline + std::ostream& blink(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[5m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& reverse(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[7m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& concealed(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[8m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& crossed(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[9m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template inline + std::ostream& color(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + char command[12]; + std::snprintf(command, sizeof(command), "\033[38;5;%dm", code); + stream << command; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template inline + std::ostream& on_color(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + char command[12]; + std::snprintf(command, sizeof(command), "\033[48;5;%dm", code); + stream << command; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template inline + std::ostream& color(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + char command[20]; + std::snprintf(command, sizeof(command), "\033[38;2;%d;%d;%dm", r, g, b); + stream << command; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template inline + std::ostream& on_color(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + char command[20]; + std::snprintf(command, sizeof(command), "\033[48;2;%d;%d;%dm", r, g, b); + stream << command; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + inline + std::ostream& grey(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[30m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + 0 // grey (black) + ); + #endif + } + return stream; + } + + inline + std::ostream& red(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[31m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& green(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[32m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN + ); + #endif + } + return stream; + } + + inline + std::ostream& yellow(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[33m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& blue(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[34m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE + ); + #endif + } + return stream; + } + + inline + std::ostream& magenta(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[35m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& cyan(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[36m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN + ); + #endif + } + return stream; + } + + inline + std::ostream& white(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[37m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED + ); + #endif + } + return stream; + } + + + inline + std::ostream& bright_grey(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[90m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + 0 | FOREGROUND_INTENSITY // grey (black) + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_red(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[91m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_green(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[92m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_yellow(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[93m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_blue(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[94m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_magenta(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[95m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_cyan(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[96m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& bright_white(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[97m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + + inline + std::ostream& on_grey(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[40m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + 0 // grey (black) + ); + #endif + } + return stream; + } + + inline + std::ostream& on_red(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[41m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& on_green(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[42m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN + ); + #endif + } + return stream; + } + + inline + std::ostream& on_yellow(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[43m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& on_blue(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[44m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE + ); + #endif + } + return stream; + } + + inline + std::ostream& on_magenta(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[45m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& on_cyan(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[46m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE + ); + #endif + } + return stream; + } + + inline + std::ostream& on_white(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[47m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED + ); + #endif + } + + return stream; + } + + + inline + std::ostream& on_bright_grey(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[100m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + 0 | BACKGROUND_INTENSITY // grey (black) + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_red(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[101m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_green(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[102m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_yellow(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[103m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_blue(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[104m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_magenta(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[105m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_cyan(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[106m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + inline + std::ostream& on_bright_white(std::ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[107m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + + return stream; + } + + + + //! Since C++ hasn't a way to hide something in the header from + //! the outer access, I have to introduce this namespace which + //! is used for internal purpose and should't be access from + //! the user code. + namespace _internal + { + // An index to be used to access a private storage of I/O streams. See + // colorize / nocolorize I/O manipulators for details. Due to the fact + // that static variables ain't shared between translation units, inline + // function with local static variable is used to do the trick and share + // the variable value between translation units. + inline int colorize_index() + { + static int colorize_index = std::ios_base::xalloc(); + return colorize_index; + } + + //! Since C++ hasn't a true way to extract stream handler + //! from the a given `std::ostream` object, I have to write + //! this kind of hack. + inline + FILE* get_standard_stream(const std::ostream& stream) + { + if (&stream == &std::cout) + return stdout; + else if ((&stream == &std::cerr) || (&stream == &std::clog)) + return stderr; + + return nullptr; + } + + // Say whether a given stream should be colorized or not. It's always + // true for ATTY streams and may be true for streams marked with + // colorize flag. + inline + bool is_colorized(std::ostream& stream) + { + return is_atty(stream) || static_cast(stream.iword(colorize_index())); + } + + //! Test whether a given `std::ostream` object refers to + //! a terminal. + inline + bool is_atty(const std::ostream& stream) + { + FILE* std_stream = get_standard_stream(stream); + + // Unfortunately, fileno() ends with segmentation fault + // if invalid file descriptor is passed. So we need to + // handle this case gracefully and assume it's not a tty + // if standard stream is not detected, and 0 is returned. + if (!std_stream) + return false; + + #if defined(TERMCOLOR_TARGET_POSIX) + return ::isatty(fileno(std_stream)); + #elif defined(TERMCOLOR_TARGET_WINDOWS) + return ::_isatty(_fileno(std_stream)); + #else + return false; + #endif + } + + #if defined(TERMCOLOR_TARGET_WINDOWS) + //! Change Windows Terminal colors attribute. If some + //! parameter is `-1` then attribute won't changed. + inline void win_change_attributes(std::ostream& stream, int foreground, int background) + { + // yeah, i know.. it's ugly, it's windows. + static WORD defaultAttributes = 0; + + // Windows doesn't have ANSI escape sequences and so we use special + // API to change Terminal output color. That means we can't + // manipulate colors by means of "std::stringstream" and hence + // should do nothing in this case. + if (!_internal::is_atty(stream)) + return; + + // get terminal handle + HANDLE hTerminal = INVALID_HANDLE_VALUE; + if (&stream == &std::cout) + hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); + else if (&stream == &std::cerr) + hTerminal = GetStdHandle(STD_ERROR_HANDLE); + + // save default terminal attributes if it unsaved + if (!defaultAttributes) + { + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + defaultAttributes = info.wAttributes; + } + + // restore all default settings + if (foreground == -1 && background == -1) + { + SetConsoleTextAttribute(hTerminal, defaultAttributes); + return; + } + + // get current settings + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + + if (foreground != -1) + { + info.wAttributes &= ~(info.wAttributes & 0x0F); + info.wAttributes |= static_cast(foreground); + } + + if (background != -1) + { + info.wAttributes &= ~(info.wAttributes & 0xF0); + info.wAttributes |= static_cast(background); + } + + SetConsoleTextAttribute(hTerminal, info.wAttributes); + } + #endif // TERMCOLOR_TARGET_WINDOWS + + } // namespace _internal + +} // namespace termcolor + + +#undef TERMCOLOR_TARGET_POSIX +#undef TERMCOLOR_TARGET_WINDOWS + +#if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION) +# undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES +# undef TERMCOLOR_USE_WINDOWS_API +#endif + +#endif // TERMCOLOR_HPP_ \ No newline at end of file From 2f26c6fae55741dcb6aa4598ad9e701f92e6f533 Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Wed, 10 Nov 2021 14:43:34 +0100 Subject: [PATCH 12/18] Added a README for SMCE_Client --- client/README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 client/README.md diff --git a/client/README.md b/client/README.md new file mode 100644 index 00000000..c6893c2a --- /dev/null +++ b/client/README.md @@ -0,0 +1,60 @@ +# libSMCE command line frontend + +Like SMCE, this sample program requires a C++20 toolchain (for `` mostly). + +## Build instructions +To beable to build, the enviroment variable SMCE_ROOT needs to point to a current installed release. +These can be found under releases on git. Or be build directly from the source code with the commands below. +These should be ran in the libSMCE folder. +```shell +cmake -S . -B build/ +cmake --build build/ +cmake --build build/ --config Release +cmake --install build/ --prefix +``` + +After SMCE_ROOT is added, run: + +```shell +cd client +cmake -S . -B build/ +cmake --build build/ +``` + +You can now find the executable in the `./build` directory. + +### Run instructions +``` +SMCE_client +``` +where +- FQBN: [Fully Qualified Board Name](https://arduino.github.io/arduino-cli/latest/FAQ/#whats-the-fqbn-string) +- Sketch path: Relative or absolute path to the sketch to run + +#### Start arguments + TODO + +### Configuration of board + +As is, configuring of GPIO pins on the board is done in the source file SMCE_Client.cpp, as seen here: + +``` +smce::BoardConfig board_conf{ + .pins = {0,1}, + .gpio_drivers = { + smce::BoardConfig::GpioDrivers{0, + smce::BoardConfig::GpioDrivers::DigitalDriver{true,true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{true,true} + }, + .... + } ...... +``` +.pins = a list of all a pins on the board. +.gpio_drivers = specifies the drivers for each pin, configured as: +``` +smce::BoardConfig::GpioDrivers{, + smce::BoardConfig::GpioDrivers::DigitalDriver{,}, + smce::BoardConfig::GpioDrivers::AnalogDriver{,} + } +``` +DigitalDriver and AnalogDriver has two parameters {,}, these are set as true or false depending on what the pin should be able to do. \ No newline at end of file From b957ff58b4c0ce1f70c70f4b1044ee27d16e8969 Mon Sep 17 00:00:00 2001 From: Johan Mejborn Date: Thu, 11 Nov 2021 18:10:39 +0100 Subject: [PATCH 13/18] Added CMake installation of Lyra and Termcolor --- client/CMakeLists.txt | 22 +- client/include/termcolor.hpp | 911 ----------------------------------- 2 files changed, 19 insertions(+), 914 deletions(-) delete mode 100644 client/include/termcolor.hpp diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 715490f6..efcda73f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -12,10 +12,26 @@ find_package (Threads REQUIRED) find_package (SMCE REQUIRED) set (SMCE_RES "${PROJECT_BINARY_DIR}/SMCE_Res") - -include_directories(${PROJECT_SOURCE_DIR}/include) +include (FetchContent) +FetchContent_Declare (Termcolor + GIT_REPOSITORY "https://github.com/ikalnytskyi/termcolor" + GIT_TAG "v2.0.0" + GIT_SHALLOW On + GIT_PROGRESS On + ) +FetchContent_Declare (Lyra + GIT_REPOSITORY "https://github.com/bfgroup/Lyra" + GIT_TAG "1.5.1" + GIT_SHALLOW On + GIT_PROGRESS On + ) +FetchContent_MakeAvailable(Termcolor Lyra) add_executable (SMCE_client SMCE_Client.cpp) -target_link_libraries (SMCE_client PRIVATE SMCE::SMCE) +target_link_libraries (SMCE_client PRIVATE SMCE::SMCE termcolor::termcolor bfg::Lyra) +target_include_directories (SMCE_client PUBLIC + "${termcolor_SOURCE_DIR}/include/termcolor" + "${lyra_SOURCE_DIR}/include/lyra" + ) target_compile_definitions (SMCE_client PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") file (MAKE_DIRECTORY "${SMCE_RES}") execute_process (COMMAND "${CMAKE_COMMAND}" -E tar xf "${SMCE_RESOURCES_ARK}" diff --git a/client/include/termcolor.hpp b/client/include/termcolor.hpp deleted file mode 100644 index 225d4cf2..00000000 --- a/client/include/termcolor.hpp +++ /dev/null @@ -1,911 +0,0 @@ -//! -//! termcolor -//! ~~~~~~~~~ -//! -//! termcolor is a header-only c++ library for printing colored messages -//! to the terminal. Written just for fun with a help of the Force. -//! -//! :copyright: (c) 2013 by Ihor Kalnytskyi -//! :license: BSD, see LICENSE for details -//! - -#ifndef TERMCOLOR_HPP_ -#define TERMCOLOR_HPP_ - -#include -#include - -// Detect target's platform and set some macros in order to wrap platform -// specific code this library depends on. -#if defined(_WIN32) || defined(_WIN64) -# define TERMCOLOR_TARGET_WINDOWS -#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) -# define TERMCOLOR_TARGET_POSIX -#endif - -// If implementation has not been explicitly set, try to choose one based on -// target platform. -#if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP) -# if defined(TERMCOLOR_TARGET_POSIX) -# define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES -# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION -# elif defined(TERMCOLOR_TARGET_WINDOWS) -# define TERMCOLOR_USE_WINDOWS_API -# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION -# endif -#endif - -// These headers provide isatty()/fileno() functions, which are used for -// testing whether a standard stream refers to the terminal. -#if defined(TERMCOLOR_TARGET_POSIX) -# include -#elif defined(TERMCOLOR_TARGET_WINDOWS) -# include -# include -#endif - - -namespace termcolor -{ - // Forward declaration of the `_internal` namespace. - // All comments are below. - namespace _internal - { - inline int colorize_index(); - inline FILE* get_standard_stream(const std::ostream& stream); - inline bool is_colorized(std::ostream& stream); - inline bool is_atty(const std::ostream& stream); - - #if defined(TERMCOLOR_TARGET_WINDOWS) - inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1); - #endif - } - - inline - std::ostream& colorize(std::ostream& stream) - { - stream.iword(_internal::colorize_index()) = 1L; - return stream; - } - - inline - std::ostream& nocolorize(std::ostream& stream) - { - stream.iword(_internal::colorize_index()) = 0L; - return stream; - } - - inline - std::ostream& reset(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[00m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, -1); - #endif - } - return stream; - } - - inline - std::ostream& bold(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[1m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& dark(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[2m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& italic(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[3m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& underline(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[4m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE); - #endif - } - return stream; - } - - inline - std::ostream& blink(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[5m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& reverse(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[7m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& concealed(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[8m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& crossed(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[9m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[12]; - std::snprintf(command, sizeof(command), "\033[38;5;%dm", code); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& on_color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[12]; - std::snprintf(command, sizeof(command), "\033[48;5;%dm", code); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[20]; - std::snprintf(command, sizeof(command), "\033[38;2;%d;%d;%dm", r, g, b); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - template inline - std::ostream& on_color(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - char command[20]; - std::snprintf(command, sizeof(command), "\033[48;2;%d;%d;%dm", r, g, b); - stream << command; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - #endif - } - return stream; - } - - inline - std::ostream& grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[30m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - 0 // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[31m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[32m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[33m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[34m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[35m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[36m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[37m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED - ); - #endif - } - return stream; - } - - - inline - std::ostream& bright_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[90m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - 0 | FOREGROUND_INTENSITY // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[91m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[92m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[93m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[94m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[95m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[96m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& bright_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[97m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY - ); - #endif - } - return stream; - } - - - inline - std::ostream& on_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[40m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - 0 // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& on_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[41m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[42m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN - ); - #endif - } - return stream; - } - - inline - std::ostream& on_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[43m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[44m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& on_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[45m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_RED - ); - #endif - } - return stream; - } - - inline - std::ostream& on_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[46m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE - ); - #endif - } - return stream; - } - - inline - std::ostream& on_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[47m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED - ); - #endif - } - - return stream; - } - - - inline - std::ostream& on_bright_grey(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[100m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - 0 | BACKGROUND_INTENSITY // grey (black) - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_red(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[101m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_green(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[102m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_yellow(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[103m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_blue(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[104m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_magenta(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[105m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_cyan(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[106m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY - ); - #endif - } - return stream; - } - - inline - std::ostream& on_bright_white(std::ostream& stream) - { - if (_internal::is_colorized(stream)) - { - #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) - stream << "\033[107m"; - #elif defined(TERMCOLOR_USE_WINDOWS_API) - _internal::win_change_attributes(stream, -1, - BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY - ); - #endif - } - - return stream; - } - - - - //! Since C++ hasn't a way to hide something in the header from - //! the outer access, I have to introduce this namespace which - //! is used for internal purpose and should't be access from - //! the user code. - namespace _internal - { - // An index to be used to access a private storage of I/O streams. See - // colorize / nocolorize I/O manipulators for details. Due to the fact - // that static variables ain't shared between translation units, inline - // function with local static variable is used to do the trick and share - // the variable value between translation units. - inline int colorize_index() - { - static int colorize_index = std::ios_base::xalloc(); - return colorize_index; - } - - //! Since C++ hasn't a true way to extract stream handler - //! from the a given `std::ostream` object, I have to write - //! this kind of hack. - inline - FILE* get_standard_stream(const std::ostream& stream) - { - if (&stream == &std::cout) - return stdout; - else if ((&stream == &std::cerr) || (&stream == &std::clog)) - return stderr; - - return nullptr; - } - - // Say whether a given stream should be colorized or not. It's always - // true for ATTY streams and may be true for streams marked with - // colorize flag. - inline - bool is_colorized(std::ostream& stream) - { - return is_atty(stream) || static_cast(stream.iword(colorize_index())); - } - - //! Test whether a given `std::ostream` object refers to - //! a terminal. - inline - bool is_atty(const std::ostream& stream) - { - FILE* std_stream = get_standard_stream(stream); - - // Unfortunately, fileno() ends with segmentation fault - // if invalid file descriptor is passed. So we need to - // handle this case gracefully and assume it's not a tty - // if standard stream is not detected, and 0 is returned. - if (!std_stream) - return false; - - #if defined(TERMCOLOR_TARGET_POSIX) - return ::isatty(fileno(std_stream)); - #elif defined(TERMCOLOR_TARGET_WINDOWS) - return ::_isatty(_fileno(std_stream)); - #else - return false; - #endif - } - - #if defined(TERMCOLOR_TARGET_WINDOWS) - //! Change Windows Terminal colors attribute. If some - //! parameter is `-1` then attribute won't changed. - inline void win_change_attributes(std::ostream& stream, int foreground, int background) - { - // yeah, i know.. it's ugly, it's windows. - static WORD defaultAttributes = 0; - - // Windows doesn't have ANSI escape sequences and so we use special - // API to change Terminal output color. That means we can't - // manipulate colors by means of "std::stringstream" and hence - // should do nothing in this case. - if (!_internal::is_atty(stream)) - return; - - // get terminal handle - HANDLE hTerminal = INVALID_HANDLE_VALUE; - if (&stream == &std::cout) - hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); - else if (&stream == &std::cerr) - hTerminal = GetStdHandle(STD_ERROR_HANDLE); - - // save default terminal attributes if it unsaved - if (!defaultAttributes) - { - CONSOLE_SCREEN_BUFFER_INFO info; - if (!GetConsoleScreenBufferInfo(hTerminal, &info)) - return; - defaultAttributes = info.wAttributes; - } - - // restore all default settings - if (foreground == -1 && background == -1) - { - SetConsoleTextAttribute(hTerminal, defaultAttributes); - return; - } - - // get current settings - CONSOLE_SCREEN_BUFFER_INFO info; - if (!GetConsoleScreenBufferInfo(hTerminal, &info)) - return; - - if (foreground != -1) - { - info.wAttributes &= ~(info.wAttributes & 0x0F); - info.wAttributes |= static_cast(foreground); - } - - if (background != -1) - { - info.wAttributes &= ~(info.wAttributes & 0xF0); - info.wAttributes |= static_cast(background); - } - - SetConsoleTextAttribute(hTerminal, info.wAttributes); - } - #endif // TERMCOLOR_TARGET_WINDOWS - - } // namespace _internal - -} // namespace termcolor - - -#undef TERMCOLOR_TARGET_POSIX -#undef TERMCOLOR_TARGET_WINDOWS - -#if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION) -# undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES -# undef TERMCOLOR_USE_WINDOWS_API -#endif - -#endif // TERMCOLOR_HPP_ \ No newline at end of file From b2ba11cf58d44e61f0501f7c9127c4876ab40e1d Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Fri, 12 Nov 2021 14:03:14 +0100 Subject: [PATCH 14/18] Added start arguments with lyra Added functionality to set Arduino root folder Added functionality to set SMCE_RESOURCE at runtime --- client/README.md | 34 +++++++++++++++++-------- client/SMCE_Client.cpp | 57 +++++++++++++++++++++++++----------------- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/client/README.md b/client/README.md index c6893c2a..721ade33 100644 --- a/client/README.md +++ b/client/README.md @@ -2,9 +2,14 @@ Like SMCE, this sample program requires a C++20 toolchain (for `` mostly). +**IMPORTANT** +As is, SMCE_Client is not guaranteed to work on Windows machines! +Due to a bug that causes the running sketch to crash when sending or reciving messages on uart. + + ## Build instructions -To beable to build, the enviroment variable SMCE_ROOT needs to point to a current installed release. -These can be found under releases on git. Or be build directly from the source code with the commands below. +To be able to build SMCE_client, the enviroment variable SMCE_ROOT needs to point to a current installed release of libSMCE. +These can be found under releases on git. Or it can be build directly from the source code with the commands below. These should be ran in the libSMCE folder. ```shell cmake -S . -B build/ @@ -21,20 +26,26 @@ cmake -S . -B build/ cmake --build build/ ``` -You can now find the executable in the `./build` directory. +You can now find the executable "SMCE_client" in the `./build` directory. -### Run instructions +## Run instructions ``` -SMCE_client +SMCE_client -f -p ``` where - FQBN: [Fully Qualified Board Name](https://arduino.github.io/arduino-cli/latest/FAQ/#whats-the-fqbn-string) + Testing has been done with fqbn = arduino:sam:arduino_due_x - Sketch path: Relative or absolute path to the sketch to run -#### Start arguments - TODO +### Start arguments +-f,--fqbn -> = Fully qualified board name +-p,--path -> = Relative or absolute path to the sketch to run +-d,--dir -> = Relative or absolute path to desired location of arduino root folder +-s,--SMCE -> = Relative or absolute path to SMCE\_RESOURCE folder + +(-s or -- SMCE, can be used if binary is not compiled and already linked to the SMCE_RESOURCE folder for the current computer.) -### Configuration of board +## Configuration of board As is, configuring of GPIO pins on the board is done in the source file SMCE_Client.cpp, as seen here: @@ -44,10 +55,11 @@ smce::BoardConfig board_conf{ .gpio_drivers = { smce::BoardConfig::GpioDrivers{0, smce::BoardConfig::GpioDrivers::DigitalDriver{true,true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{true,true} + smce::BoardConfig::GpioDrivers::AnalogDriver{false,false} }, - .... - } ...... + ... + ... + } ``` .pins = a list of all a pins on the board. .gpio_drivers = specifies the drivers for each pin, configured as: diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index be398ef3..aa75c491 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -22,7 +22,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -78,10 +79,8 @@ void print_menu(){ std::cout << "-rd -> Read the value on a digital pin" << std::endl; std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; } - -// Standard arduino dir -std::string dir = "."; -int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board) { + +int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board, std::string arduino_root_dir) { // Compile the sketch on the toolchain if (const auto ec = toolchain.compile(sketch)) { std::cerr << "Error: " << ec.message() << std::endl; @@ -105,18 +104,18 @@ int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board } }, .uart_channels = { {} }, // use standard configuration of uart_channels - .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = dir } } + .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = arduino_root_dir } } }; board.configure(std::move(board_conf)); return 0; } -int compile_and_start(smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board){ +int compile_and_start(smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board, std::string arduino_root_dir){ if(board.status() == smce::Board::Status::running){ board.stop(); board.reset(); } - compile_sketch(sketch,toolchain,board); + compile_sketch(sketch,toolchain,board,arduino_root_dir); //Start board if (!board.start()) { std::cerr << "Error: Board failed to start sketch" << std::endl; @@ -126,23 +125,35 @@ int compile_and_start(smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Boa } } -int main(int argc, char** argv){ - if (argc == 2 && (argv[1] == "-h" || argv[1] == "--help")) { - print_help(argv[0]); - return EXIT_SUCCESS; - } else if (argc != 3) { - print_help(argv[0]); - return EXIT_FAILURE; - } - //Saves and - char* fqbn = argv[1]; - char* path_to_sketch = argv[2]; +int main(int argc, char** argv){ + + std::string fqbn; + std::string path_to_sketch; + std::string arduino_root_dir = "."; // path to root dir for arduino, standard is in start folder. + std::string smce_resource_dir = SMCE_RESOURCES_DIR; // smce_resource_dir path, given at runtime. + + auto cli + = lyra::opt(fqbn,"fqbn") + ["--fpqn"]["-f"]("Fully qualified board name") + | lyra::opt(path_to_sketch,"path-to-sketch") + ["--path"]["-p"]("The path to the sketch") + | lyra::opt(arduino_root_dir,"Ardunio home folder") + ["--dir"]["-d"]("The absolute path to the desired location of arduino root") + | lyra::opt(smce_resource_dir,"Alternativ path to SMCE_RESOURCE") // Makes it possible to change path to SMCE_RESOURCES at start. + ["--SMCE"]["-s"]("Tha alternative path to SMCE_RESOURCES for runtime, should be absolute."); + + auto result = cli.parse({argc,argv}); + if(!result){ + std::cerr << "Error in command line: " << result.errorMessage() << std::endl; + return 1; + } + std::cout << std::endl << "Starting SMCE Client" << std::endl; - std::cout << "Given Fqbn: " << fqbn << "\n" << "Given path to sketch: " << path_to_sketch << std::endl; + std::cout << "Given Fqbn: " << fqbn << std::endl << "Given path to sketch: " << path_to_sketch << std::endl; // Create the toolchain - smce::Toolchain toolchain{SMCE_RESOURCES_DIR}; + smce::Toolchain toolchain{smce_resource_dir}; if (const auto ec = toolchain.check_suitable_environment()) { std::cerr << "Error: " << ec.message() << std::endl; return EXIT_FAILURE; @@ -160,7 +171,7 @@ int main(int argc, char** argv){ std::cout << "Creating board and compiling sketch" << std::endl; smce::Board board(exit_sketch); //Compile and start board - compile_and_start(sketch,toolchain,board); + compile_and_start(sketch,toolchain,board,arduino_root_dir); std::cout << "Complete" << std::endl; //Create view and uart (serial) channels auto board_view = board.view(); @@ -198,7 +209,7 @@ int main(int argc, char** argv){ }else if (input == "-rc"){ //recompile std::cout << "Recompiling.." << std::endl; t_lock.lock(); // aquire lock before recompiling, so uart_listener is forced to wait - compile_and_start(sketch,toolchain,board); + compile_and_start(sketch,toolchain,board,arduino_root_dir); // update boardview and uart0 after the sketch has been recompiled. board_view = board.view(); uart0 = board_view.uart_channels[0]; From 117473b58e71be9c41dabf052f42e6402d0a22e9 Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Mon, 15 Nov 2021 11:38:32 +0100 Subject: [PATCH 15/18] Added uart to file write Added so incoming uart messages can be written to a file instead of console. Set at start by setting the start argument -u or --file to true. --- client/CMakeLists.txt | 19 ++++++++++++------ client/README.md | 1 + client/SMCE_Client.cpp | 42 +++++++++++++++++++++++++++++---------- client/src/UartToFile.cpp | 28 ++++++++++++++++++++++++++ client/src/UartToFile.hpp | 12 +++++++++++ 5 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 client/src/UartToFile.cpp create mode 100644 client/src/UartToFile.hpp diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index efcda73f..70f2c40d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -6,12 +6,13 @@ cmake_minimum_required (VERSION 3.16) -project (client) +project (SMCE_client) find_package (Threads REQUIRED) find_package (SMCE REQUIRED) set (SMCE_RES "${PROJECT_BINARY_DIR}/SMCE_Res") + include (FetchContent) FetchContent_Declare (Termcolor GIT_REPOSITORY "https://github.com/ikalnytskyi/termcolor" @@ -26,17 +27,23 @@ FetchContent_Declare (Lyra GIT_PROGRESS On ) FetchContent_MakeAvailable(Termcolor Lyra) -add_executable (SMCE_client SMCE_Client.cpp) -target_link_libraries (SMCE_client PRIVATE SMCE::SMCE termcolor::termcolor bfg::Lyra) -target_include_directories (SMCE_client PUBLIC + +include_directories(${PROJECT_SOURCE_DIR}/src) +add_executable (${PROJECT_NAME} SMCE_Client.cpp) +target_sources (${PROJECT_NAME} PRIVATE + src/UartToFile.hpp + src/UartToFile.cpp + ) +target_link_libraries (${PROJECT_NAME} PRIVATE SMCE::SMCE termcolor::termcolor bfg::Lyra) +target_include_directories (${PROJECT_NAME} PUBLIC "${termcolor_SOURCE_DIR}/include/termcolor" "${lyra_SOURCE_DIR}/include/lyra" ) -target_compile_definitions (SMCE_client PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") +target_compile_definitions (${PROJECT_NAME} PRIVATE "SMCE_RESOURCES_DIR=\"${SMCE_RES}\"") file (MAKE_DIRECTORY "${SMCE_RES}") execute_process (COMMAND "${CMAKE_COMMAND}" -E tar xf "${SMCE_RESOURCES_ARK}" WORKING_DIRECTORY "${SMCE_RES}") -add_custom_command (TARGET SMCE_client POST_BUILD +add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "$" ) \ No newline at end of file diff --git a/client/README.md b/client/README.md index 721ade33..fc8da51d 100644 --- a/client/README.md +++ b/client/README.md @@ -42,6 +42,7 @@ where -p,--path -> = Relative or absolute path to the sketch to run -d,--dir -> = Relative or absolute path to desired location of arduino root folder -s,--SMCE -> = Relative or absolute path to SMCE\_RESOURCE folder +-u,--file -> = Set to true if uart should write to file (created in the set arduino root folder) (-s or -- SMCE, can be used if binary is not compiled and already linked to the SMCE_RESOURCE folder for the current computer.) diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index aa75c491..162a7282 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -23,7 +23,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -47,8 +48,9 @@ std::atomic_bool run_threads = true; std::atomic_bool mute_uart = false; std::mutex t_lock; //Listen to the uart input from board, writes what it read to terminal -void uart_listener(smce::VirtualUart uart){ - auto tx = uart.tx(); +void uart_listener(smce::VirtualUart uart,bool file_write,std::string path){ + auto tx = uart.tx(); + std::string file = path+"/uartlog"+get_time()+".txt"; while(run_threads){ std::string buffer; t_lock.lock(); // if recompiling sketch, lock thread here untill recompiling is done. @@ -60,9 +62,13 @@ void uart_listener(smce::VirtualUart uart){ continue; } buffer.resize(len); - if(!mute_uart){ - std::cout << termcolor::red << buffer << termcolor::reset <" << std::flush; - } + if(file_write){ + uart_to_file(buffer,file); + }else{ + if(!mute_uart){ + std::cout << termcolor::red << buffer << termcolor::reset <" << std::flush; + } + } } } // Prints a command menu for SMCE_Client @@ -131,23 +137,37 @@ int main(int argc, char** argv){ std::string path_to_sketch; std::string arduino_root_dir = "."; // path to root dir for arduino, standard is in start folder. std::string smce_resource_dir = SMCE_RESOURCES_DIR; // smce_resource_dir path, given at runtime. + bool file_write = false; //DEFAULT is to write in console + bool show_help = false; + //Setup lyra start arguments for the parser. auto cli - = lyra::opt(fqbn,"fqbn") + = lyra::help(show_help) + | lyra::opt(fqbn,"fqbn") ["--fpqn"]["-f"]("Fully qualified board name") | lyra::opt(path_to_sketch,"path-to-sketch") ["--path"]["-p"]("The path to the sketch") | lyra::opt(arduino_root_dir,"Ardunio home folder") ["--dir"]["-d"]("The absolute path to the desired location of arduino root") | lyra::opt(smce_resource_dir,"Alternativ path to SMCE_RESOURCE") // Makes it possible to change path to SMCE_RESOURCES at start. - ["--SMCE"]["-s"]("Tha alternative path to SMCE_RESOURCES for runtime, should be absolute."); + ["--SMCE"]["-s"]("Tha alternative path to SMCE_RESOURCES for runtime, should be absolute.") + | lyra::opt(file_write,"file_write") + ["--file"]["-u"]("Set to true if uart should write to file (created in the set arduino root folder)"); auto result = cli.parse({argc,argv}); + + // If something is not right with parser of input, show error if(!result){ std::cerr << "Error in command line: " << result.errorMessage() << std::endl; return 1; - } - + } + // If user input -h or --help, display help. + if(show_help) + { + std::cout << cli << "\n"; + return 0; + } + std::cout << std::endl << "Starting SMCE Client" << std::endl; std::cout << "Given Fqbn: " << fqbn << std::endl << "Given path to sketch: " << path_to_sketch << std::endl; @@ -178,7 +198,7 @@ int main(int argc, char** argv){ auto uart0 = board_view.uart_channels[0]; //start listener thread for uart - std::thread uart_thread{[=] {uart_listener(uart0);} }; + std::thread uart_thread{[=] {uart_listener(uart0,file_write,arduino_root_dir);} }; std::cout << "Messages recived on uart from arduino is shown as " << termcolor::red << "red" << termcolor::reset << " text." << std::endl; // Print command menu diff --git a/client/src/UartToFile.cpp b/client/src/UartToFile.cpp new file mode 100644 index 00000000..07f2fddd --- /dev/null +++ b/client/src/UartToFile.cpp @@ -0,0 +1,28 @@ +#include +#include + +#include +#include + +using namespace std; + +std::string get_time(){ + time_t currentTime; + struct tm *localTime; + + time( ¤tTime ); + localTime = localtime( ¤tTime ); + + int hour = localTime->tm_hour; + int min = localTime->tm_min; + int sec = localTime->tm_sec; + return(to_string(hour)+":"+to_string(min)+":"+to_string(sec)); +} + +int uart_to_file(std::string message, std::string path){ + ofstream file; + file.open(path, std::ios_base::app); + file << get_time() +": " +message + "\n"; + file.close(); + return 0; +} diff --git a/client/src/UartToFile.hpp b/client/src/UartToFile.hpp new file mode 100644 index 00000000..eb36a204 --- /dev/null +++ b/client/src/UartToFile.hpp @@ -0,0 +1,12 @@ + + +#ifndef SMCE_UARTTOFILE_HPP +#define SMCE_UARTTOFILE_HPP + +#include + +std::string get_time(); + +int uart_to_file(std::string message,std::string path); + +#endif \ No newline at end of file From 79ed7caa8931fd8b23bf3885f645af40fe037d63 Mon Sep 17 00:00:00 2001 From: Johan Mejborn Date: Tue, 23 Nov 2021 15:40:08 +0100 Subject: [PATCH 16/18] Global variables changes and typos --- client/SMCE_Client.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index 162a7282..4f357cbe 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -43,17 +43,17 @@ void exit_sketch(int code){ std::cerr << "Error code: "<< code << std::endl; } -// automic bool for handling threads -std::atomic_bool run_threads = true; -std::atomic_bool mute_uart = false; -std::mutex t_lock; +// atomic bool for handling threads +static std::atomic_bool run_threads = true; +static std::atomic_bool mute_uart = false; +static std::mutex t_lock; //Listen to the uart input from board, writes what it read to terminal void uart_listener(smce::VirtualUart uart,bool file_write,std::string path){ auto tx = uart.tx(); std::string file = path+"/uartlog"+get_time()+".txt"; while(run_threads){ std::string buffer; - t_lock.lock(); // if recompiling sketch, lock thread here untill recompiling is done. + t_lock.lock(); // if recompiling sketch, lock thread here until recompiling is done. buffer.resize(tx.max_size()); const auto len = tx.read(buffer); t_lock.unlock(); @@ -199,7 +199,7 @@ int main(int argc, char** argv){ //start listener thread for uart std::thread uart_thread{[=] {uart_listener(uart0,file_write,arduino_root_dir);} }; - std::cout << "Messages recived on uart from arduino is shown as " + std::cout << "Messages received on uart from arduino is shown as " << termcolor::red << "red" << termcolor::reset << " text." << std::endl; // Print command menu print_menu(); From 2a29d24bc8faefe5649e66070659f8b297cc2ad2 Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Fri, 26 Nov 2021 09:06:13 +0100 Subject: [PATCH 17/18] Fixed typos and small refactoring Focused on the smaller problems from the pull request review. Still has several bugs / changes that needs to be done. --- client/CMakeLists.txt | 2 +- client/README.md | 13 +- client/SMCE_Client.cpp | 515 +++++++++++++++++--------------------- client/src/UartToFile.cpp | 5 +- 4 files changed, 239 insertions(+), 296 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 70f2c40d..e4686fc5 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -28,8 +28,8 @@ FetchContent_Declare (Lyra ) FetchContent_MakeAvailable(Termcolor Lyra) -include_directories(${PROJECT_SOURCE_DIR}/src) add_executable (${PROJECT_NAME} SMCE_Client.cpp) +target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/src) target_sources (${PROJECT_NAME} PRIVATE src/UartToFile.hpp src/UartToFile.cpp diff --git a/client/README.md b/client/README.md index fc8da51d..806d6ad7 100644 --- a/client/README.md +++ b/client/README.md @@ -1,6 +1,6 @@ # libSMCE command line frontend -Like SMCE, this sample program requires a C++20 toolchain (for `` mostly). +Like SMCE, this command line frontend requires a C++20 toolchain. **IMPORTANT** As is, SMCE_Client is not guaranteed to work on Windows machines! @@ -8,17 +8,6 @@ Due to a bug that causes the running sketch to crash when sending or reciving me ## Build instructions -To be able to build SMCE_client, the enviroment variable SMCE_ROOT needs to point to a current installed release of libSMCE. -These can be found under releases on git. Or it can be build directly from the source code with the commands below. -These should be ran in the libSMCE folder. -```shell -cmake -S . -B build/ -cmake --build build/ -cmake --build build/ --config Release -cmake --install build/ --prefix -``` - -After SMCE_ROOT is added, run: ```shell cd client diff --git a/client/SMCE_Client.cpp b/client/SMCE_Client.cpp index 4f357cbe..73d1c818 100644 --- a/client/SMCE_Client.cpp +++ b/client/SMCE_Client.cpp @@ -1,339 +1,294 @@ -/* -* client/SMCE_Client.cpp -* Created by Rylander and Mejborn, Team 1, DAT265. -* -* A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. -* Functionally to test and debug sketches, as GPIO pins can be set with values and -* messages can be sent to board through uart. -* -*/ - -#ifndef SMCE_RESOURCES_DIR -# error "SMCE_RESOURCES_DIR is not set" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include +/* + * client/SMCE_Client.cpp + * Created by Rylander and Mejborn, Team 1, DAT265. + * + * A terminal interface for libSMCE, that allows sketches to be ran without the use of smce-gd. + * Functionally to test and debug sketches, as GPIO pins can be set with values and + * messages can be sent to board through uart. + * + */ + +#ifndef SMCE_RESOURCES_DIR +# error "SMCE_RESOURCES_DIR is not set" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include - - -using namespace std::literals; - -void print_help(const char* argv0){ - std::cout << "Usage: " << argv0 << " " << std::endl; -} - -void exit_sketch(int code){ - std::cerr << "Error code: "<< code << std::endl; -} +#include +#include +#include + +using namespace std::literals; + +void exit_sketch(int code) { std::cerr << "Error code: " << code << std::endl; } // atomic bool for handling threads static std::atomic_bool run_threads = true; static std::atomic_bool mute_uart = false; static std::mutex t_lock; -//Listen to the uart input from board, writes what it read to terminal -void uart_listener(smce::VirtualUart uart,bool file_write,std::string path){ +// Listen to the uart input from board, writes what it read to terminal +void uart_listener(smce::VirtualUart uart, bool file_write, std::string path) { auto tx = uart.tx(); - std::string file = path+"/uartlog"+get_time()+".txt"; - while(run_threads){ + std::string file = path + "/uartlog" + get_time() + ".txt"; + while (run_threads) { std::string buffer; t_lock.lock(); // if recompiling sketch, lock thread here until recompiling is done. - buffer.resize(tx.max_size()); + buffer.resize(tx.max_size()); const auto len = tx.read(buffer); - t_lock.unlock(); - if(len == 0){ - std::this_thread::sleep_for(1ms); - continue; - } + t_lock.unlock(); + if (len == 0) { + std::this_thread::sleep_for(1ms); + continue; + } buffer.resize(len); - if(file_write){ - uart_to_file(buffer,file); - }else{ - if(!mute_uart){ - std::cout << termcolor::red << buffer << termcolor::reset <" << std::flush; - } - } - } -} -// Prints a command menu for SMCE_Client -void print_menu(){ - std::cout << "SMCE Client menu:" << std::endl; - std::cout << "-h -> See menu" << std::endl; - std::cout << "-p -> Pause or resume the board" << std::endl; - std::cout << "-rc -> Recompile the sketch" << std::endl; - std::cout << "-m -> Send message to board through uart (serial)" << std::endl; - std::cout << "-mt -> disable uart prints in console" << std::endl; - std::cout << "-wa -> Set a specific value on a analog pin" << std::endl; - std::cout << "-wd -> Set a specific value on a digital pin, value should be 0 or 1" << std::endl; - std::cout << "-ra -> Read the value on a analog pin" << std::endl; - std::cout << "-rd -> Read the value on a digital pin" << std::endl; - std::cout << "-q -> Power off board and quit program" << std::endl << std::endl; -} - -int compile_sketch (smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board, std::string arduino_root_dir) { - // Compile the sketch on the toolchain - if (const auto ec = toolchain.compile(sketch)) { - std::cerr << "Error: " << ec.message() << std::endl; - auto [_, log] = toolchain.build_log(); - if (!log.empty()) - std::cerr << log << std::endl; - return EXIT_FAILURE; - } - board.attach_sketch(sketch); - // Create Board Config - smce::BoardConfig board_conf{ - .pins = {0,1}, //Creating pins & GPIO drivers - .gpio_drivers = { - smce::BoardConfig::GpioDrivers{0, - smce::BoardConfig::GpioDrivers::DigitalDriver{true, true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{true, true} - }, - smce::BoardConfig::GpioDrivers{1, - smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, - smce::BoardConfig::GpioDrivers::AnalogDriver{false, true} - } - }, - .uart_channels = { {} }, // use standard configuration of uart_channels - .sd_cards = { smce::BoardConfig::SecureDigitalStorage{ .root_dir = arduino_root_dir } } - }; - board.configure(std::move(board_conf)); - return 0; + if (file_write) { + uart_to_file(buffer, file); + } else if (!mute_uart) { + std::cout << termcolor::red << buffer << termcolor::reset << std::endl << "$>" << std::flush; + } + } +} +// Prints a command menu for SMCE_Client +void print_menu() { + std::cout << "SMCE Client menu:\n" + << "-h -> See menu\n" + << "-p -> Pause or resume the board\n" + << "-rc -> Recompile the sketch\n" + << "-m -> Send message to board through uart (serial)\n" + << "-mt -> disable uart prints in console\n" + << "-wa -> Set a specific value on a analog pin\n" + << "-wd -> Set a specific value on a digital pin, value should be 0 or 1\n" + << "-ra -> Read the value on a analog pin\n" + << "-rd -> Read the value on a digital pin\n" + << "-q -> Power off board and quit program \n"; } -int compile_and_start(smce::Sketch &sketch,smce::Toolchain &toolchain ,smce::Board &board, std::string arduino_root_dir){ - if(board.status() == smce::Board::Status::running){ - board.stop(); - board.reset(); +int compile_sketch(smce::Sketch& sketch, smce::Toolchain& toolchain, smce::Board& board, std::string arduino_root_dir) { + // Compile the sketch on the toolchain + if (const auto ec = toolchain.compile(sketch)) { + std::cerr << "Error: " << ec.message() << std::endl; + auto [_, log] = toolchain.build_log(); + if (!log.empty()) + std::cerr << log << std::endl; + return EXIT_FAILURE; } - compile_sketch(sketch,toolchain,board,arduino_root_dir); - //Start board - if (!board.start()) { - std::cerr << "Error: Board failed to start sketch" << std::endl; - return EXIT_FAILURE; - }else{ - return 0; - } + board.attach_sketch(sketch); + smce::BoardConfig board_conf{ + .pins = {0, 1}, // Creating pins & GPIO drivers + .gpio_drivers = {smce::BoardConfig::GpioDrivers{10, smce::BoardConfig::GpioDrivers::DigitalDriver{true, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{true, true}}, + smce::BoardConfig::GpioDrivers{1, smce::BoardConfig::GpioDrivers::DigitalDriver{false, true}, + smce::BoardConfig::GpioDrivers::AnalogDriver{false, true}}}, + .uart_channels = {{}}, // use standard configuration of uart_channels + .sd_cards = {smce::BoardConfig::SecureDigitalStorage{.root_dir = arduino_root_dir}}}; + board.configure(std::move(board_conf)); + return EXIT_SUCCESS; } - -int main(int argc, char** argv){ - std::string fqbn; +int compile_and_start(smce::Sketch& sketch, smce::Toolchain& toolchain, smce::Board& board, + std::string arduino_root_dir) { + if (board.status() == smce::Board::Status::running) { + board.stop(); + board.reset(); + } + compile_sketch(sketch, toolchain, board, arduino_root_dir); + // Start board + if (!board.start()) { + std::cerr << "Error: Board failed to start sketch" << std::endl; + return EXIT_FAILURE; + } else { + return EXIT_SUCCESS; + } +} + +int main(int argc, char** argv) { + + std::string fqbn; std::string path_to_sketch; - std::string arduino_root_dir = "."; // path to root dir for arduino, standard is in start folder. - std::string smce_resource_dir = SMCE_RESOURCES_DIR; // smce_resource_dir path, given at runtime. - bool file_write = false; //DEFAULT is to write in console + std::string arduino_root_dir = "."; // path to root dir for arduino, standard is in start folder. + std::string smce_resource_dir = SMCE_RESOURCES_DIR; // smce_resource_dir path, given at runtime. + bool file_write = false; // DEFAULT is to write in console bool show_help = false; - //Setup lyra start arguments for the parser. - auto cli - = lyra::help(show_help) - | lyra::opt(fqbn,"fqbn") - ["--fpqn"]["-f"]("Fully qualified board name") - | lyra::opt(path_to_sketch,"path-to-sketch") - ["--path"]["-p"]("The path to the sketch") - | lyra::opt(arduino_root_dir,"Ardunio home folder") - ["--dir"]["-d"]("The absolute path to the desired location of arduino root") - | lyra::opt(smce_resource_dir,"Alternativ path to SMCE_RESOURCE") // Makes it possible to change path to SMCE_RESOURCES at start. - ["--SMCE"]["-s"]("Tha alternative path to SMCE_RESOURCES for runtime, should be absolute.") - | lyra::opt(file_write,"file_write") - ["--file"]["-u"]("Set to true if uart should write to file (created in the set arduino root folder)"); + // Setup lyra start arguments for the parser. + auto cli = + lyra::help(show_help) | lyra::opt(fqbn, "fqbn")["--fpqn"]["-f"]("Fully qualified board name") | + lyra::opt(path_to_sketch, "path-to-sketch")["--path"]["-p"]("The path to the sketch") | + lyra::opt(arduino_root_dir, + "Ardunio home folder")["--dir"]["-d"]("The absolute path to the desired location of Arduino root") | + lyra::opt(smce_resource_dir, + "Alternative path to SMCE_RESOURCE") // Makes it possible to change path to SMCE_RESOURCES at start. + ["--SMCE"]["-s"]("Tha alternative path to SMCE_RESOURCES for runtime, should be absolute.") | + lyra::opt(file_write, "file_write")["--file"]["-u"]( + "Set to true if uart should write to file (created in the set Arduino root folder)"); - auto result = cli.parse({argc,argv}); + auto result = cli.parse({argc, argv}); // If something is not right with parser of input, show error - if(!result){ + if (!result) { std::cerr << "Error in command line: " << result.errorMessage() << std::endl; return 1; - } - // If user input -h or --help, display help. - if(show_help) - { + } + // If user input -h or --help, display help. + if (show_help) { std::cout << cli << "\n"; return 0; } - - - std::cout << std::endl << "Starting SMCE Client" << std::endl; - std::cout << "Given Fqbn: " << fqbn << std::endl << "Given path to sketch: " << path_to_sketch << std::endl; - - // Create the toolchain - smce::Toolchain toolchain{smce_resource_dir}; - if (const auto ec = toolchain.check_suitable_environment()) { - std::cerr << "Error: " << ec.message() << std::endl; - return EXIT_FAILURE; - } - - // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing - // clang-format off - smce::Sketch sketch{path_to_sketch, { - .fqbn = fqbn, - .legacy_preproc_libs = { {"WiFi"}, {"MQTT"} } - }}; - // // clang-format on - - // Create the virtual Arduino board - std::cout << "Creating board and compiling sketch" << std::endl; - smce::Board board(exit_sketch); - //Compile and start board - compile_and_start(sketch,toolchain,board,arduino_root_dir); - std::cout << "Complete" << std::endl; - //Create view and uart (serial) channels - auto board_view = board.view(); - auto uart0 = board_view.uart_channels[0]; - - //start listener thread for uart - std::thread uart_thread{[=] {uart_listener(uart0,file_write,arduino_root_dir);} }; - std::cout << "Messages received on uart from arduino is shown as " - << termcolor::red << "red" << termcolor::reset << " text." << std::endl; - // Print command menu - print_menu(); - // Main loop, handle the command input - bool suspended = false; - while(true){ - std::cout << "$>"; - std::string input; - std::getline(std::cin,input); - board.tick(); - if (input == "-h"){ //help menu + + std::cout << std::endl << "Starting SMCE Client" << std::endl; + std::cout << "Given Fqbn: " << fqbn << std::endl << "Given path to sketch: " << path_to_sketch << std::endl; + + // Create the toolchain + smce::Toolchain toolchain{smce_resource_dir}; + if (const auto ec = toolchain.check_suitable_environment()) { + std::cerr << "Error: " << ec.message() << std::endl; + return EXIT_FAILURE; + } + + // Create the sketch, and declare that it requires the WiFi and MQTT Arduino libraries during preprocessing + // clang-format off + smce::Sketch sketch{path_to_sketch, {.fqbn = fqbn, .legacy_preproc_libs = {{"WiFi"}, {"MQTT"}}}}; + // // clang-format on + + // Create the virtual Arduino board + std::cout << "Creating board and compiling sketch" << std::endl; + smce::Board board{exit_sketch}; + + // Compile and start board + compile_and_start(sketch, toolchain, board, arduino_root_dir); + std::cout << "Complete" << std::endl; + // Create view and uart (serial) channels + auto board_view = board.view(); + auto uart0 = board_view.uart_channels[0]; + + // start listener thread for uart + std::thread uart_thread{[=] { uart_listener(uart0, file_write, arduino_root_dir); }}; + std::cout << "Messages received on uart from arduino is shown as " << termcolor::red << "red" << termcolor::reset + << " text." << std::endl; + // Print command menu + print_menu(); + // Main loop, handle the command input + while (true) { + std::cout << "$>"; + std::string input; + std::getline(std::cin, input); + board.tick(); + if (input == "-h") { // help menu print_menu(); - }else if (input == "-p"){ //pause or resume - if(!suspended){ - suspended = board.suspend(); - if(suspended) - std::cout << "Board paused" << std::endl; - else - std::cout << "Board could not be paused" << std::endl; - }else if(suspended){ - board.resume(); - suspended = false; - std::cout << "Board resumed" << std::endl; + } else if (input == "-p") { // pause or resume + if (board.status() != smce::Board::Status::suspended) { + if (board.suspend()) + std::cout << "Board paused" << std::endl; + else + std::cout << "Board could not be paused" << std::endl; + } else if (board.status() == smce::Board::Status::suspended) { + board.resume(); + std::cout << "Board resumed" << std::endl; } - - }else if (input == "-rc"){ //recompile - std::cout << "Recompiling.." << std::endl; - t_lock.lock(); // aquire lock before recompiling, so uart_listener is forced to wait - compile_and_start(sketch,toolchain,board,arduino_root_dir); + } else if (input == "-rc") { // recompile + std::cout << "Recompiling.." << std::endl; + t_lock.lock(); // aquire lock before recompiling, so uart_listener is forced to wait + compile_and_start(sketch, toolchain, board, arduino_root_dir); // update boardview and uart0 after the sketch has been recompiled. - board_view = board.view(); - uart0 = board_view.uart_channels[0]; - t_lock.unlock(); // unlock as recompile is done + board_view = board.view(); + uart0 = board_view.uart_channels[0]; + t_lock.unlock(); // unlock as recompile is done std::cout << "Complete" << std::endl; - }else if (input.starts_with("-m ")){ //send message on uart - std::string message = input.substr(3); - for(std::span to_write = message; !to_write.empty();){ - const auto written_count = uart0.rx().write(to_write); - to_write = to_write.subspan(written_count); - } + } else if (input.starts_with("-m ")) { // send message on uart + std::string message = input.substr(3); + for (std::span to_write = message; !to_write.empty();) { + const auto written_count = uart0.rx().write(to_write); + to_write = to_write.subspan(written_count); + } - }else if(input.starts_with("-mt")){ - if(mute_uart){ + } else if (input.starts_with("-mt")) { + if (mute_uart) { mute_uart = false; - std::cout <<"Unmuted uart"< #include -using namespace std; std::string get_time(){ time_t currentTime; @@ -16,11 +15,11 @@ std::string get_time(){ int hour = localTime->tm_hour; int min = localTime->tm_min; int sec = localTime->tm_sec; - return(to_string(hour)+":"+to_string(min)+":"+to_string(sec)); + return(std::to_string(hour)+":"+std::to_string(min)+":"+std::to_string(sec)); } int uart_to_file(std::string message, std::string path){ - ofstream file; + std::ofstream file; file.open(path, std::ios_base::app); file << get_time() +": " +message + "\n"; file.close(); From 100b84e67e1633adc02bfc504dd8f44e0ea5764c Mon Sep 17 00:00:00 2001 From: Eric Rylander Date: Fri, 26 Nov 2021 09:51:54 +0100 Subject: [PATCH 18/18] Removed ctime and used chrono instead --- client/src/UartToFile.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/client/src/UartToFile.cpp b/client/src/UartToFile.cpp index d3534d95..2dc8195f 100644 --- a/client/src/UartToFile.cpp +++ b/client/src/UartToFile.cpp @@ -1,21 +1,16 @@ #include -#include - +#include +#include #include #include std::string get_time(){ - time_t currentTime; - struct tm *localTime; - - time( ¤tTime ); - localTime = localtime( ¤tTime ); - - int hour = localTime->tm_hour; - int min = localTime->tm_min; - int sec = localTime->tm_sec; - return(std::to_string(hour)+":"+std::to_string(min)+":"+std::to_string(sec)); + auto time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::tm time = *std::localtime(&time_t); + std::stringstream ss; + ss << std::put_time(&time, "%T"); + return ss.str(); } int uart_to_file(std::string message, std::string path){