From 7b397967236727e0f0f83b4bf9852d6bd3f7d649 Mon Sep 17 00:00:00 2001 From: Pascal Engeler <engelerp@phys.ethz.ch> Date: Fri, 9 Jun 2023 23:31:26 +0200 Subject: [PATCH] Added communicator library --- .../drivers/communicator/communicator.cpp | 207 ++++++++++++++++++ .../drivers/communicator/communicator.hpp | 35 +++ 2 files changed, 242 insertions(+) create mode 100644 firmware/drivers/communicator/communicator.cpp create mode 100644 firmware/drivers/communicator/communicator.hpp diff --git a/firmware/drivers/communicator/communicator.cpp b/firmware/drivers/communicator/communicator.cpp new file mode 100644 index 0000000..df399f3 --- /dev/null +++ b/firmware/drivers/communicator/communicator.cpp @@ -0,0 +1,207 @@ +#include <communicator.cpp> +#include <utility.hpp> +#include <ptimer.hpp> +#include <pid_controller.hpp> + +unsigned long Communicator::timeout_us_ = 20000; //timeout 20ms +char Communicator::outbuf[256]; //out buffer +char Communicator::cmd_ = 'X'; //command received +std::vector<char> Communicator::arg_ = std::vector<char>('\0',256); //arguments received + +bool Communicator::communicate(){ + if(!serialCharAvailable_()){ + return false; + } + else{ + cmd_ = getSerialChar_(); + if(isSetCommand_()){ + //read argument + char latest = cmd; + size_t i = 0; + PTimer::start(); + while(latest != ';' && i < arg_.size()-10 && PTimer::elapsed() < timeout_us_){ + if(serialCharAvailable_()){ + latest = getSerialChar_(); + arg_[i++] = latest; + if(latest == ';'){ + arg[i-1] = '\0'; + } + PTimer::start(); + } + } + if(PTimer::elapsed() >= timeout_us_){ + handleTimeout_(); //timeout + return false; + } + else if(i >= arg_.size()-10){ + handleInputOverflow_(); //input overflow + return false; + } + //apply the setting + else{ + handleSetCommand_(); + return true; + } + } + else if(isGetCommand_()){ + if(cmd_ == 't'){ //getTemperature + snprintf( outbuf_, + 255, + "%f,%f,%f,%f,%f;", + Temperatures.temperatures[0], + Temperatures.temperatures[1], + Temperatures.temperatures[2], + Temperatures.temperatures[3], + Temperatures.temperatures[4] + ); + sendBuf_(); + return true; + } + else if(cmd_ == 'p'){ //getPidCoeff + auto kpids = Pid_controller::get_kpid(); + snprintf( outbuf_, + 255, + "%f,%f,%f;", + kpids[0], + kpids[1], + kpids[2] + ); + sendBuf_(); + return true; + } + else if(cmd_ == 'v'){ //getPropIntDer + auto pids = Pid_controller::get_pid(); + snprintf( outbuf_, + 255, + "%f,%f,%f;", + pids[0], + pids[1], + pids[2] + ); + sendBuf_(); + return true; + } + else if(cmd_ == 'o'){ //getOutput + snprintf(outbuf_, 255, "%f;", Pid_controller::get_output()); + sendBuf_(); + return true; + } + else if(cmd_ == 's'){ //getSetpoint + snprintf(outbuf_, 255, "%f;", Pid_controller::get_setpoint()); + sendBuf_(); + return true; + } + else{ //invalid command + handleInvalidCommand_(); + return false; + } + } + else if(isNopCommand_()){ + handleNopCommand_(); + return true; + } + else{ //invalid command + handleInvalidCommand_(); + return false; + } + } +} + +bool Communicator::serialCharAvailable_() const{ + return SERCHAN.available() > 0; +} + +bool Communicator::isSetCommand_() const{ + return cmd_ == 'P' || + cmd_ == 'I' || + cmd_ == 'D' || + cmd_ == 'N' || + cmd_ == 'S'; +} + +bool Communicator::isGetCommand_() const{ + return cmd_ == 't' || + cmd_ == 'p' || + cmd_ == 'v' || + cmd_ == 'o' || + cmd_ == 's'; +} + +bool Communicator::isNopCommand_() const{ + return cmd_ == '?'; +} + +char Communicator::getSerialChar_() const{ + int newChar = SERCHAN.read(); + if(newChar < 0 || newChar >= 128){//invalid char + return 'X'; + } + else{ + return char(newChar); + } +} + +void Communicator::sendBuf_() const{ + SERCHAN.write(outbuf_); +} + +void Communicator::handleTimeout_() const{ + snprintf(outbuf_, 255, "!"); + sendBuf_(); +} + +void Communicator::handleInputOverflow_() const{ + snprintf(outbuf_, 255, "!"); + sendBuf_(); +} + +void Communicator::handleSetCommand_() const{ + char* endptr = arg_.data()+250; + double darg = std::strtod(arg_.data(), &endptr); + if(arg_.data() == endptr){ //error + handleInvalidCommand_(); + return; + } + else if(cmd_ == 'P'){ + Pid_controller::set_Kp(darg); + snprintf(outbuf_, 255, ";"); + sendBuf_(); + return; + } + else if(cmd_ == 'I'){ + Pid_controller::set_Ki(darg); + snprintf(outbuf_, 255, ";"); + sendBuf_(); + return; + } + else if(cmd_ == 'D'){ + Pid_controller::set_Kd(darg); + snprintf(outbuf_, 255, ";"); + sendBuf_(); + return; + } + else if(cmd_ == 'N'){ + Pid_controller::set_I_reset(darg); + snprintf(outbuf_, 255, ";"); + sendBuf_(); + return; + } + else if(cmd_ == 'S'){ + Pid_controller::set_setpoint(darg); + snprintf(outbuf_, 255, ";"); + sendBuf_(); + return; + } +} + +void Communicator::handleNopCommand_() const{ + snprintf(outbuf_, 255, ";"); + sendBuf_(); + return; +} + +void Communicator::handleInvalidCommand_() const{ + snprintf(outbuf_, 255, "!"); + sendBuf_(); + return; +} diff --git a/firmware/drivers/communicator/communicator.hpp b/firmware/drivers/communicator/communicator.hpp new file mode 100644 index 0000000..ec2e69d --- /dev/null +++ b/firmware/drivers/communicator/communicator.hpp @@ -0,0 +1,35 @@ +#ifndef COMMUNICATOR_HPP_INCLUDED +#define COMMUNICATOR_HPP_INCLUDED +#include <vector> + +#define SERCHAN SerialUSB + +class Communicator{ +public: + static bool communicate(); + +private: + /*Function Members*/ + static bool serialCharAvailable_() const; + static bool isSetCommand_() const; + static bool isGetCommand_() const; + static bool isNopCommand_() const; + + static char getSerialChar_() const; + static void sendBuf_() const; + + static void handleTimeout_(); + static void handleInputOverflow_(); + static void handleSetCommand_(); + static void handleNopCommand_(); + static void handleInvalidCommand_(); + + + /*Data Members*/ + static unsigned long timeout_us_; + static char outbuf_[256]; + static char cmd_; + static std::vector<char> arg_; +} + +#endif -- GitLab