diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp
index db09f99b34..ccc64bc55f 100644
--- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp
+++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp
@@ -151,13 +151,6 @@ GlobalSettings::GlobalSettings()
, m_advanced_options(
"Advanced Options: You should not need to touch anything below here."
)
- , ENABLE_PABOTBASE1(
- "Enable PABotBase1:
Enable support for the legacy PABotBase 1 protocol.
"
- "Turn this on if you are still using Arduino Uno R3, Arduino Leonardo, Teensy, or Pro Micro. "
- "Note that this feature is slated to be removed in September 2026.",
- LockMode::UNLOCK_WHILE_RUNNING,
- false
- )
, DUMP_VIDEO_FORMATS(
"Dump Video Formats:
Log all video formats supported by your capture card.",
LockMode::UNLOCK_WHILE_RUNNING,
@@ -226,7 +219,6 @@ GlobalSettings::GlobalSettings()
PA_ADD_STATIC(m_advanced_options);
add_option(PokemonAutomation::LOG_EVERYTHING(), "LOG_EVERYTHING");
- PA_ADD_OPTION(ENABLE_PABOTBASE1);
PA_ADD_OPTION(DUMP_VIDEO_FORMATS);
PA_ADD_OPTION(SAVE_DEBUG_IMAGES);
diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
index 7f36879680..be883b2994 100644
--- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
+++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
@@ -104,7 +104,6 @@ class GlobalSettings : public BatchOption, private ConfigOption::Listener, priva
SectionDividerOption m_advanced_options;
- BooleanCheckBoxOption ENABLE_PABOTBASE1;
BooleanCheckBoxOption DUMP_VIDEO_FORMATS;
BooleanCheckBoxOption SAVE_DEBUG_IMAGES;
BooleanCheckBoxOption SAVE_DEBUG_VIDEOS_ON_SWITCH;
diff --git a/SerialPrograms/Source/CommonFramework/Main.cpp b/SerialPrograms/Source/CommonFramework/Main.cpp
index 42512baad9..3c47e8b9ca 100644
--- a/SerialPrograms/Source/CommonFramework/Main.cpp
+++ b/SerialPrograms/Source/CommonFramework/Main.cpp
@@ -42,7 +42,7 @@
#include "CommonFramework/VideoPipeline/Backends/CameraImplementations.h"
#include "CommonTools/OCR/OCR_Routines.h"
#include "ControllerInput/ControllerInput.h"
-#include "Controllers/SerialPortPollerQt.h"
+#include "Controllers/SerialPort/SerialPortPollerQt.h"
#include "Integrations/DiscordWebhook.h"
#include "Windows/MainWindow.h"
diff --git a/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp b/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp
index bd86ca5ef0..e81b72dd91 100644
--- a/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp
+++ b/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp
@@ -16,7 +16,6 @@
#include "PABotBase2/SerialPABotBase2_Descriptor.h"
-#include "SerialPABotBase/SerialPABotBase_SelectorWidget.h"
#include "PABotBase2/SerialPABotBase2_SelectorWidget.h"
#include "NintendoSwitch/Controllers/SysbotBase/SysbotBase_SelectorWidget.h"
@@ -55,9 +54,6 @@ ControllerSelectorWidget::ControllerSelectorWidget(QWidget& parent, ControllerSe
// Add all the supported interfaces.
{
- if (GlobalSettings::instance().ENABLE_PABOTBASE1){
- m_interface_list.emplace_back(ControllerInterface::SerialPABotBase);
- }
m_interface_list.emplace_back(ControllerInterface::SerialPABotBase2);
m_interface_list.emplace_back(ControllerInterface::TcpSysbotBase);
// m_interface_list.emplace_back(ControllerInterface::UsbSysbotBase);
@@ -212,11 +208,6 @@ void ControllerSelectorWidget::refresh_selection(ControllerInterface interface_t
// m_status_text->setText(QString::fromStdString(html_color_text("Not Connected", COLOR_RED)));
switch (interface_type){
- case ControllerInterface::SerialPABotBase:
- m_selector = new SerialPABotBase::SerialPABotBase_SelectorWidget(*this, m_session.descriptor().get());
- m_dropdowns->insertWidget(1, m_selector, 1);
- break;
-
case ControllerInterface::SerialPABotBase2:
m_selector = new SerialPABotBase::SerialPABotBase2_SelectorWidget(*this, m_session.descriptor().get());
m_dropdowns->insertWidget(1, m_selector, 1);
diff --git a/SerialPrograms/Source/Controllers/PABotBase2/PABotBase2_DeviceHandle.cpp b/SerialPrograms/Source/Controllers/PABotBase2/PABotBase2_DeviceHandle.cpp
index 4c1f6a5a07..c8d96761c3 100644
--- a/SerialPrograms/Source/Controllers/PABotBase2/PABotBase2_DeviceHandle.cpp
+++ b/SerialPrograms/Source/Controllers/PABotBase2/PABotBase2_DeviceHandle.cpp
@@ -14,7 +14,7 @@
#include "Common/Cpp/ColoredText.h"
#include "Controllers/ControllerTypeStrings.h"
#include "Controllers/ControllerSettings.h"
-#include "Controllers/SerialPABotBase/SerialPABotBase.h"
+#include "Controllers/SerialPort/SerialPABotBase.h"
#include "PABotBase2_DeviceHandle.h"
//#include
diff --git a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.cpp b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.cpp
index a7751e8c78..0e88cd331f 100644
--- a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.cpp
+++ b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.cpp
@@ -7,7 +7,7 @@
#ifdef QT_CORE_LIB
#include
#include
-#include "Controllers/SerialPortPollerQt.h"
+#include "Controllers/SerialPort/SerialPortPollerQt.h"
#endif
#include "Common/Cpp/ScopeExit.h"
#include "Common/Cpp/PrettyPrint.h"
diff --git a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.h b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.h
index f916552440..61ab4af666 100644
--- a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.h
+++ b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Connection.h
@@ -10,8 +10,8 @@
#include "Common/Cpp/Concurrency/AsyncTask.h"
#include "Common/Cpp/SerialConnection/SerialConnection.h"
#include "Common/PABotBase2/ReliableConnectionLayer/PABotBase2CC_ReliableStreamConnection.h"
+#include "Controllers/SerialPort/SerialLogger.h"
#include "Controllers/PABotBase2/PABotBase2_Connection.h"
-#include "Controllers/SerialPABotBase/Connection/MessageLogger.h"
namespace PokemonAutomation{
namespace SerialPABotBase{
diff --git a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Descriptor.cpp b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Descriptor.cpp
index 06c96a09fc..9d67dc6296 100644
--- a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Descriptor.cpp
+++ b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_Descriptor.cpp
@@ -7,7 +7,7 @@
#include "Common/Cpp/Json/JsonValue.h"
#include "Controllers/ControllerTypeStrings.h"
#ifdef QT_CORE_LIB
-#include "Controllers/SerialPortPollerQt.h"
+#include "Controllers/SerialPort/SerialPortPollerQt.h"
#endif
#include "SerialPABotBase2_Connection.h"
#include "SerialPABotBase2_Descriptor.h"
diff --git a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp
index 9bef4a88f2..85d557edee 100644
--- a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp
+++ b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp
@@ -4,7 +4,7 @@
*
*/
-#include "Controllers/SerialPABotBase/SerialPABotBase_SelectorWidget.h"
+#include
#include "SerialPABotBase2_Descriptor.h"
#include "SerialPABotBase2_SelectorWidget.h"
@@ -19,6 +19,45 @@ template class RegisterUiStateQtWidget
diff --git a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBase.cpp b/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBase.cpp
deleted file mode 100644
index bac4024420..0000000000
--- a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBase.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Pokemon Automation Bot-Base Interface
- *
- * From: https://github.com/PokemonAutomation/
- *
- */
-
-#include "BotBaseMessage.h"
-#include "BotBase.h"
-
-//#include
-//using std::cout;
-//using std::endl;
-
-namespace PokemonAutomation{
-
-
-
-}
diff --git a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBase.h b/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBase.h
deleted file mode 100644
index 87221f6c69..0000000000
--- a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBase.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Pokemon Automation Bot-Base Interface
- *
- * From: https://github.com/PokemonAutomation/
- *
- */
-
-#ifndef PokemonAutomation_AbstractBotBase_H
-#define PokemonAutomation_AbstractBotBase_H
-
-#include
-#include "Common/Cpp/CancellableScope.h"
-#include "Common/Cpp/ListenerSet.h"
-
-namespace PokemonAutomation{
-
-class Logger;
-struct BotBaseMessage;
-class BotBaseRequest;
-class BotBaseControllerContext;
-
-
-
-class BotBaseController : public Cancellable::CancelListener{
-public:
- struct Listener{
- virtual void on_info_message(const BotBaseMessage& message) noexcept{};
- virtual void on_error_message(const BotBaseMessage& message) noexcept{};
- };
- void add_listener(Listener& listener){
- m_listeners.add(listener);
- }
- void remove_listener(Listener& listener){
- m_listeners.remove(listener);
- }
-
-public:
- using ContextType = BotBaseControllerContext;
-
- enum class State{
- RUNNING,
- STOPPING,
- STOPPED,
-// ERROR,
- };
-
-public:
- virtual ~BotBaseController() = default;
- virtual void stop(std::string error_message = "") noexcept = 0;
-
- virtual Logger& logger() = 0;
- virtual State state() const = 0;
- virtual size_t queue_limit() const = 0;
-
- // Waits for all pending requests to finish.
- virtual void wait_for_all_requests(Cancellable* cancelled = nullptr) = 0;
-
- // Stop all pending commands. This wipes the command queue on both sides
- // and stops any currently executing command.
- virtual void stop_all_commands() = 0;
-
- // Tell the device that the next command should replace the command queue.
- //
- // So once the next command is issued, it will stop all ongoing commands
- // and run the new command instead.
- //
- // Once this function is called, all commands before it are no longer
- // guaranteed to finish even if no command interrupts it.
- virtual void next_command_interrupt() = 0;
-
-public:
- virtual bool try_issue_request(
- const BotBaseRequest& request,
- Cancellable* cancelled = nullptr
- ) = 0;
- virtual void issue_request(
- const BotBaseRequest& request,
- Cancellable* cancelled = nullptr
- ) = 0;
- virtual BotBaseMessage issue_request_and_wait(
- const BotBaseRequest& request,
- Cancellable* cancelled = nullptr
- ) = 0;
-
-protected:
- ListenerSet m_listeners;
-};
-
-
-
-
-
-}
-
-
-#endif
-
diff --git a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBaseMessage.h b/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBaseMessage.h
deleted file mode 100644
index 377522183c..0000000000
--- a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/BotBaseMessage.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* Bot-Base Message
- *
- * From: https://github.com/PokemonAutomation/
- *
- */
-
-#ifndef PokemonAutomation_BotBaseMessage_H
-#define PokemonAutomation_BotBaseMessage_H
-
-#include
-#include
-#include
-#include "Common/Cpp/PrettyPrint.h"
-#include "Common/Cpp/Exceptions.h"
-#include "Common/Cpp/LifetimeSanitizer.h"
-#include "Common/Cpp/Options/BooleanCheckBoxOption.h"
-#include "Common/SerialPABotBase/SerialPABotBase_Protocol.h"
-#include "CommonFramework/Logging/Logger.h"
-
-namespace PokemonAutomation{
-
-
-struct BotBaseMessage{
- uint8_t type;
- std::string body;
-
- LifetimeSanitizer sanitizer;
-
- BotBaseMessage() = default;
- BotBaseMessage(uint8_t p_type, std::string p_body)
- : type(p_type)
- , body(std::move(p_body))
- {}
-
- template
- BotBaseMessage(uint8_t p_type, const Params& params)
- : type(p_type)
- , body((char*)¶ms, sizeof(params))
- {}
-
- template
- void convert(Logger& logger, MessageBody& params) const{
- sanitizer.check_usage();
- if (type != MessageType){
- throw SerialProtocolException(
- logger, PA_CURRENT_FUNCTION,
- "Received Incorrect Response Type: Expected = " + std::to_string(MessageType) + ", Actual = " + std::to_string(type)
- );
- }
- if (body.size() != sizeof(MessageBody)){
- throw SerialProtocolException(
- logger, PA_CURRENT_FUNCTION,
- "Received Incorrect Response Size: Expected = " + std::to_string(sizeof(MessageBody)) + ", Actual = " + std::to_string(body.size())
- );
- }
- memcpy(¶ms, body.c_str(), body.size());
- sanitizer.check_usage();
- }
-
-};
-
-class BotBaseRequest{
-public:
- BotBaseRequest(bool is_command)
- : m_is_command(is_command)
- {}
- virtual ~BotBaseRequest() = default;
- virtual BotBaseMessage message() const = 0;
-
- bool is_command() const{ return m_is_command; }
-
-private:
- bool m_is_command;
-};
-
-
-
-
-
-class BotBaseMessageType{
-public:
- template
- static const BotBaseMessageType& instance(){
- static const ChildType type;
- return type;
- }
-
- BotBaseMessageType(const char* name, uint8_t type, uint8_t body_size)
- : m_name(name)
- , m_type(type)
- , m_size(body_size)
- {}
-
- uint8_t type() const{
- return m_type;
- }
-
- friend bool operator<(const BotBaseMessageType& x, const BotBaseMessageType& y){
- return x.m_type < y.m_type;
- }
-
-
-public:
- virtual bool should_print(const std::string& body) const{
- if (LOG_EVERYTHING()){
- return true;
- }
- if (PABB_MSG_IS_ACK(m_type)){
- return false;
- }
- return true;
- }
- virtual bool is_valid(const std::string& body) const{
- return body.size() == m_size;
- }
- virtual std::string tostr(const std::string& body) const{
- std::string ret;
- ret += "(0x" + tostr_hex(m_type) + ") ";
- ret += m_name;
- if (!is_valid(body)){
- ret += ": (Invalid: Size = " + std::to_string(body.size()) + ")";
- }
- return ret;
- }
-
-
-private:
- const char* m_name;
- const uint8_t m_type;
- const uint8_t m_size; // Excluding header and CRC.
-};
-
-
-
-
-
-
-
-
-}
-#endif
diff --git a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/MessageSniffer.h b/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/MessageSniffer.h
deleted file mode 100644
index 0e43bb03d1..0000000000
--- a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/MessageSniffer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Message Sniffer
- *
- * From: https://github.com/PokemonAutomation/
- *
- */
-
-#ifndef PokemonAutomation_MessageSniffer_H
-#define PokemonAutomation_MessageSniffer_H
-
-#include
-#include "Common/Compiler.h"
-
-namespace PokemonAutomation{
-
-struct BotBaseMessage;
-
-
-class MessageSniffer{
-public:
- virtual void on_send(const BotBaseMessage& message, bool is_retransmit){}
- virtual void on_recv(const BotBaseMessage& message){}
-};
-
-
-
-}
-#endif
diff --git a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/PABotBase.cpp b/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/PABotBase.cpp
deleted file mode 100644
index 804ec64426..0000000000
--- a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/PABotBase.cpp
+++ /dev/null
@@ -1,1022 +0,0 @@
-/* Pokemon Automation Bot Base
- *
- * From: https://github.com/PokemonAutomation/
- *
- */
-
-#include
-#include "Common/Cpp/Exceptions.h"
-#include "Common/Cpp/PanicDump.h"
-#include "Common/Cpp/Concurrency/SpinPause.h"
-#include "Common/SerialPABotBase/SerialPABotBase_Protocol.h"
-#include "Controllers/SerialPABotBase/Messages/SerialPABotBase_MessageWrappers_BaseProtocol_StaticRequests.h"
-#include "Controllers/SerialPABotBase/Messages/SerialPABotBase_MessageWrappers_BaseProtocol_CommandQueue.h"
-#include "PABotBase.h"
-
-//#include
-//using std::cout;
-//using std::endl;
-
-
-// Intentionally drop some messages to test self-recovery.
-//#define INTENTIONALLY_DROP_MESSAGES
-
-
-
-// #define DEBUG_STACK_TRACE
-
-#ifdef DEBUG_STACK_TRACE
-
-#if defined(__APPLE__)
-#include
-#include
-#endif
-
-#endif // DEBUG_STACK_TRACE
-
-namespace PokemonAutomation{
-
-
-
-PABotBase::PABotBase(
- Logger& logger,
- ThreadPool& thread_pool,
- std::unique_ptr connection,
- std::chrono::milliseconds retransmit_delay
-)
- : PABotBaseConnection(logger, std::move(connection))
- , m_logger(logger)
- , m_max_pending_requests(PABB_DEVICE_MINIMUM_QUEUE_SIZE)
- , m_send_seq(1)
- , m_retransmit_delay(retransmit_delay)
- , m_last_ack(current_time())
- , m_state(State::RUNNING)
- , m_error(false)
-{
- // We must initialize this last because it will trigger the lifetime
- // sanitizer if it beats it to construction.
- m_retransmit_thread = thread_pool.dispatch_now_blocking([this]{
- run_with_catch(
- "PABotBase::retransmit_thread()",
- [this]{
- try{
- retransmit_thread();
- }catch (ConnectionException& e){
- {
- ReadSpinLock lg(m_state_lock, "PABotBase::retransmit_thread()");
- m_error_message = e.to_str();
- }
- m_error.store(true, std::memory_order_release);
- m_cv.notify_all();
- }
- }
- );
- });
-}
-PABotBase::~PABotBase(){
- stop();
- while (m_state.load(std::memory_order_acquire) != State::STOPPED){
- pause();
- }
-}
-
-size_t PABotBase::inflight_requests(){
- auto scope_check = m_sanitizer.check_scope();
-
- // Must be called under m_state_lock.
-
- size_t ret = m_pending_requests.size();
- for (const auto& item : m_pending_commands){
- if (item.second.state == AckState::NOT_ACKED){
- ret++;
- }
- }
- return ret;
-}
-
-void PABotBase::connect(){
- auto scope_check = m_sanitizer.check_scope();
-
- pabb_MsgAckRequest response;
- issue_request_and_wait(
- SerialPABotBase::DeviceRequest_seqnum_reset(), nullptr
- ).convert(logger(), response);
-}
-void PABotBase::stop(std::string error_message) noexcept{
- auto scope_check = m_sanitizer.check_scope();
-
- // Make sure only one thread can get in here.
- State expected = State::RUNNING;
- if (!m_state.compare_exchange_strong(expected, State::STOPPING)){
- return;
- }
-
- if (!error_message.empty()){
- WriteSpinLock lg(m_state_lock, "PABotBase::stop()");
- m_error_message = std::move(error_message);
- }
-
- // Wake everyone up.
- {
- std::lock_guard lg(m_sleep_lock);
- }
- m_cv.notify_all();
- m_retransmit_thread.wait_and_ignore_exceptions();
-
- {
- ReadSpinLock lg(m_state_lock, "PABotBase::stop()");
-
- // Send a stop request, but don't wait for a response that we may never
- // receive.
- pabb_MsgRequestStop params;
- uint64_t seqnum = m_send_seq;
- seqnum_t seqnum_s = (seqnum_t)seqnum;
- memcpy(¶ms, &seqnum_s, sizeof(seqnum_t));
-// try_issue_request(params);
-// m_state.store(State::STOPPING, std::memory_order_release);
- BotBaseMessage stop_request(PABB_MSG_REQUEST_STOP, std::string((char*)¶ms, sizeof(params)));
- try{
- send_message(stop_request, false);
- }catch (...){
- m_logger.log("Unable to send stop signal.", COLOR_RED);
- }
- }
-
- // Must call this to stop the receiver thread from making any more async
- // calls into this class which touch its fields.
- safely_stop();
-
- // Now the receiver thread is dead. Nobody else is touching this class so
- // it is safe to destruct.
- m_state.store(State::STOPPED, std::memory_order_release);
-}
-void PABotBase::on_cancellable_cancel(
- Cancellable& cancellable,
- std::exception_ptr reason
-){
- {
- std::unique_lock lg(m_sleep_lock);
- }
- m_cv.notify_all();
-}
-
-void PABotBase::set_queue_limit(size_t queue_limit){
- m_max_pending_requests.store(queue_limit, std::memory_order_relaxed);
-}
-
-void PABotBase::wait_for_all_requests(Cancellable* cancelled){
- auto scope_check = m_sanitizer.check_scope();
-
- std::unique_lock lg(m_sleep_lock);
- m_logger.log("Waiting for all requests to finish...", COLOR_DARKGREEN);
- while (true){
- if (cancelled){
- cancelled->throw_if_cancelled();
- }
- if (m_state.load(std::memory_order_acquire) != State::RUNNING){
- ReadSpinLock lg0(m_state_lock, "PABotBase::wait_for_all_requests() - 0");
- throw InvalidConnectionStateException(m_error_message);
- }
- if (m_error.load(std::memory_order_acquire)){
- ReadSpinLock lg0(m_state_lock, "PABotBase::wait_for_all_requests() - 1");
- throw ConnectionException(&m_logger, m_error_message);
- }
- {
- ReadSpinLock lg1(m_state_lock, "PABotBase::wait_for_all_requests() - 2");
-#if 0
- m_logger.log(
- "Waiting for all requests to finish... (Requests: " +
- std::to_string(m_pending_requests.size()) +
- ", Commands: " + std::to_string(m_pending_commands.size()) + ")",
- COLOR_DARKGREEN
- );
-#endif
- if (m_pending_requests.empty() && m_pending_commands.empty()){
- break;
- }
- }
- cv_wait(cancelled, lg);
- }
-
-// m_logger.log("Waiting for all requests to finish... Completed.", COLOR_DARKGREEN);
-}
-void PABotBase::stop_all_commands(){
-
-#ifdef DEBUG_STACK_TRACE
- cout << __FILE__ << ":" << __LINE__ << " PABotBase::stop_all_commands()" << endl;
- cout << "-----------------------------------------------------------------------------------------" << endl;
-#if defined(__APPLE__)
- void* callstack[128];
- int i, frames = backtrace(callstack, 128);
- char** strs = backtrace_symbols(callstack, frames);
- for (i = 0; i < frames; ++i){
- cout << strs[i] << endl;
- }
- free(strs);
-#endif
- cout << "-----------------------------------------------------------------------------------------" << endl;
-#endif
-
- auto scope_check = m_sanitizer.check_scope();
-
- uint64_t seqnum = issue_request(nullptr, SerialPABotBase::DeviceRequest_request_stop(), true, true);
- clear_all_active_commands(seqnum);
-}
-void PABotBase::next_command_interrupt(){
- auto scope_check = m_sanitizer.check_scope();
-
- uint64_t seqnum = issue_request(nullptr, SerialPABotBase::DeviceRequest_next_command_interrupt(), true, true);
- clear_all_active_commands(seqnum);
-}
-void PABotBase::clear_all_active_commands(uint64_t seqnum){
- auto scope_check = m_sanitizer.check_scope();
- {
- // Remove all commands at or before the specified seqnum.
- std::lock_guard lg0(m_sleep_lock);
- WriteSpinLock lg1(m_state_lock, "PABotBase::next_command_interrupt()");
- m_logger.log(
- "Clearing all active commands... (Commands: " + std::to_string(m_pending_commands.size()) + ")",
- COLOR_DARKGREEN
- );
-
-
- if (m_pending_commands.empty()){
- return;
- }
-
- // Remove all active commands up to the seqnum.
- while (true){
- auto iter = m_pending_commands.begin();
- if (iter == m_pending_commands.end() || iter->first > seqnum){
- break;
- }
- iter->second.sanitizer.check_usage();
-
- // We cannot remove un-acked messages from our buffer. If an un-acked
- // message is dropped and the receiver is still waiting for it, it will
- // wait forever since we will never retransmit.
-
- if (iter->second.state == AckState::NOT_ACKED){
- // Convert the command into a no-op request.
- SerialPABotBase::DeviceRequest_program_id request;
- BotBaseMessage message = request.message();
- seqnum_t seqnum_s = (seqnum_t)iter->first;
- memcpy(&message.body[0], &seqnum_s, sizeof(seqnum_t));
-
-// cout << "removing = " << seqnum_s << ", " << (int)iter->second.state << endl;
-
- std::pair::iterator, bool> ret = m_pending_requests.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(iter->first),
- std::forward_as_tuple()
- );
- if (!ret.second){
- throw InternalProgramError(
- &m_logger,
- PA_CURRENT_FUNCTION,
- "Duplicate sequence number: " + std::to_string(seqnum)
- );
- }
-
- // This block will never throw.
- {
- PendingRequest& handle = ret.first->second;
- handle.silent_remove = true;
- handle.request = std::move(message);
- handle.first_sent = current_time();
- }
- }
-
- m_pending_commands.erase(iter);
- }
- }
- m_cv.notify_all();
-}
-template
-uint64_t PABotBase::infer_full_seqnum(const Map& map, seqnum_t seqnum) const{
- auto scope_check = m_sanitizer.check_scope();
-
- // The protocol uses a 32-bit seqnum that wraps around. For our purposes of
- // retransmits, we use a full 64-bit seqnum to maintain sorting order
- // across the wrap-arounds.
-
- // Since the oldest unacked messaged will never be more than 63 (MAX_SEQNUM_GAP)
- // requests old, there is no ambiguity on which request is being referred
- // to with just the lower 32 bits.
- // Here we infer the upper 32 bits of the seqnum to obtain the full 64-bit
- // seqnum that we need to index our map.
-
- // This needs to be called inside the lock. Furthermore, the map must not
- // be empty. If it is empty, we know we don't have it and can drop it
- // before we even call this function.
-
- // Figure out the upper 32 bits of the seqnum.
- uint64_t lo = map.begin()->first;
- uint64_t hi = map.rbegin()->first;
- uint64_t lo_candidate = (lo & 0xffffffff00000000) | seqnum;
- uint64_t hi_candidate = (hi & 0xffffffff00000000) | seqnum;
- return lo_candidate >= lo
- ? lo_candidate
- : hi_candidate;
-}
-
-uint64_t PABotBase::oldest_live_seqnum() const{
- auto scope_check = m_sanitizer.check_scope();
-
- // Must call under state lock.
- uint64_t oldest = m_send_seq;
- if (!m_pending_requests.empty()){
- oldest = std::min(oldest, m_pending_requests.begin()->first);
- }
- if (!m_pending_commands.empty()){
- oldest = std::min(oldest, m_pending_commands.begin()->first);
- }
- return oldest;
-}
-
-template
-void PABotBase::process_ack_request(BotBaseMessage message){
- auto scope_check = m_sanitizer.check_scope();
-
- if constexpr (!variable_length){
- if (message.body.size() != sizeof(Params)){
- m_logger.log("Ignoring message with invalid size.");
- return;
- }
- }
- const Params* params = (const Params*)message.body.c_str();
- seqnum_t seqnum = params->seqnum;
-
- AckState state;
- {
- WriteSpinLock lg(m_state_lock, "PABotBase::process_ack_request()");
-
- if (m_pending_requests.empty()){
- m_logger.log("Unexpected request ack message: seqnum = " + std::to_string(seqnum));
- return;
- }
-
- uint64_t full_seqnum = infer_full_seqnum(m_pending_requests, seqnum);
- std::map::iterator iter = m_pending_requests.find(full_seqnum);
- if (iter == m_pending_requests.end()){
- m_logger.log("Unexpected request ack message: seqnum = " + std::to_string(seqnum));
- return;
- }
- iter->second.sanitizer.check_usage();
-
- state = iter->second.state;
- if (state == AckState::NOT_ACKED){
- if (iter->second.silent_remove){
- m_pending_requests.erase(iter);
- }else{
- iter->second.state = AckState::ACKED;
- iter->second.ack = std::move(message);
- }
- }
- }
-
- m_last_ack.store(current_time(), std::memory_order_release);
-
- switch (state){
- case AckState::NOT_ACKED:
- {
- std::lock_guard lg(m_sleep_lock);
- }
- m_cv.notify_all();
- return;
- case AckState::ACKED:
- m_logger.log("Duplicate request ack message: seqnum = " + std::to_string(seqnum));
- return;
- case AckState::FINISHED:
- m_logger.log("Request ack on command finish: seqnum = " + std::to_string(seqnum));
- return;
- }
-}
-template
-void PABotBase::process_ack_command(BotBaseMessage message){
- auto scope_check = m_sanitizer.check_scope();
-
- if (message.body.size() != sizeof(Params)){
- m_logger.log("Ignoring message with invalid size.");
- return;
- }
- const Params* params = (const Params*)message.body.c_str();
- seqnum_t seqnum = params->seqnum;
-
- WriteSpinLock lg(m_state_lock, "PABotBase::process_ack_command()");
-
- if (m_pending_commands.empty()){
- m_logger.log("Unexpected command ack message: seqnum = " + std::to_string(seqnum));
- return;
- }
-
- uint64_t full_seqnum = infer_full_seqnum(m_pending_commands, seqnum);
- auto iter = m_pending_commands.find(full_seqnum);
- if (iter == m_pending_commands.end()){
- m_logger.log("Unexpected command ack message: seqnum = " + std::to_string(seqnum));
- return;
- }
- iter->second.sanitizer.check_usage();
-
- m_last_ack.store(current_time(), std::memory_order_release);
-
- switch (iter->second.state){
- case AckState::NOT_ACKED:
-// std::cout << "acked: " << full_seqnum << std::endl;
- iter->second.state = AckState::ACKED;
- iter->second.ack = std::move(message);
- return;
- case AckState::ACKED:
- m_logger.log("Duplicate command ack message: seqnum = " + std::to_string(seqnum));
- return;
- case AckState::FINISHED:
- m_logger.log("Command ack on finished command: seqnum = " + std::to_string(seqnum));
- return;
- }
-}
-template
-void PABotBase::process_command_finished(BotBaseMessage message){
- auto scope_check = m_sanitizer.check_scope();
-
- if (message.body.size() != sizeof(Params)){
- m_logger.log("Ignoring message with invalid size.");
- return;
- }
- const Params* params = (const Params*)message.body.c_str();
- seqnum_t seqnum = params->seqnum;
- seqnum_t command_seqnum = params->seq_of_original_command;
-
- // Send the ack first.
- pabb_MsgAckRequest ack;
- ack.seqnum = seqnum;
-// m_send_queue.emplace_back((uint8_t)PABB_MSG_ACK, std::string((char*)&ack, sizeof(ack)));
-
- {
- std::lock_guard lg0(m_sleep_lock);
- WriteSpinLock lg1(m_state_lock, "PABotBase::process_command_finished()");
-
-#ifdef INTENTIONALLY_DROP_MESSAGES
- if (rand() % 10 != 0){
- send_message(BotBaseMessage(PABB_MSG_ACK_REQUEST, std::string((char*)&ack, sizeof(ack))), false);
- }else{
- m_logger.log("Intentionally dropping finish ack: " + std::to_string(seqnum), COLOR_RED);
- }
-#else
- send_message(BotBaseMessage(PABB_MSG_ACK_REQUEST, std::string((char*)&ack, sizeof(ack))), false);
-#endif
-
- if (m_pending_commands.empty()){
- m_logger.log(
- "Unexpected command finished message: seqnum = " + std::to_string(seqnum) +
- ", command_seqnum = " + std::to_string(command_seqnum)
- );
- return;
- }
-
- uint64_t full_seqnum = infer_full_seqnum(m_pending_commands, command_seqnum);
- auto iter = m_pending_commands.find(full_seqnum);
- if (iter == m_pending_commands.end()){
- m_logger.log(
- "Unexpected command finished message: seqnum = " + std::to_string(seqnum) +
- ", command_seqnum = " + std::to_string(command_seqnum)
- );
- return;
- }
- iter->second.sanitizer.check_usage();
-
- switch (iter->second.state){
- case AckState::NOT_ACKED:
- case AckState::ACKED:
- iter->second.state = AckState::FINISHED;
- iter->second.ack = std::move(message);
- if (iter->second.silent_remove){
- m_pending_commands.erase(iter);
- }
- break;
- case AckState::FINISHED:
- m_logger.log("Duplicate command finish: seqnum = " + std::to_string(seqnum));
- return;
- }
- }
- m_cv.notify_all();
-}
-void PABotBase::on_recv_message(BotBaseMessage message){
- auto scope_check = m_sanitizer.check_scope();
-
- if (PABB_MSG_IS_INFO(message.type)){
- m_listeners.run_method(&Listener::on_info_message, message);
- }
- if (PABB_MSG_IS_ERROR(message.type)){
- m_listeners.run_method(&Listener::on_error_message, message);
- }
-
- switch (message.type){
- case PABB_MSG_ACK_COMMAND:
- process_ack_command(std::move(message));
- return;
- case PABB_MSG_ACK_REQUEST:
- process_ack_request(std::move(message));
- return;
- case PABB_MSG_ACK_REQUEST_I8:
- process_ack_request(std::move(message));
- return;
- case PABB_MSG_ACK_REQUEST_I16:
- process_ack_request(std::move(message));
- return;
- case PABB_MSG_ACK_REQUEST_I32:
- process_ack_request(std::move(message));
- return;
- case PABB_MSG_ACK_REQUEST_DATA:
- process_ack_request(std::move(message));
- return;
- case PABB_MSG_ERROR_INVALID_TYPE:{
- if (message.body.size() != sizeof(pabb_MsgInfoInvalidType)){
- m_logger.log("Ignoring message with invalid size.");
- return;
- }
- const pabb_MsgInfoInvalidType* params = (const pabb_MsgInfoInvalidType*)message.body.c_str();
- {
- WriteSpinLock lg(m_state_lock, "PABotBase::on_recv_message() - 0");
- m_error_message = "PABotBase incompatibility. Device does not recognize message type: " + std::to_string(params->type);
- m_logger.log(m_error_message, COLOR_RED);
- }
- m_error.store(true, std::memory_order_release);
- {
- std::lock_guard lg0(m_sleep_lock);
- }
- m_cv.notify_all();
- }
- case PABB_MSG_ERROR_MISSED_REQUEST:{
- if (message.body.size() != sizeof(pabb_MsgInfoMissedRequest)){
- m_logger.log("Ignoring message with invalid size.");
- return;
- }
- const pabb_MsgInfoMissedRequest* params = (const pabb_MsgInfoMissedRequest*)message.body.c_str();
- if (params->seqnum == 1){
- {
- WriteSpinLock lg(m_state_lock, "PABotBase::on_recv_message() = 1");
- m_error_message = "Serial connection has been interrupted.";
- m_logger.log(m_error_message, COLOR_RED);
- }
- m_error.store(true, std::memory_order_release);
- {
- std::lock_guard lg0(m_sleep_lock);
- }
- m_cv.notify_all();
- }
- return;
- }
- case PABB_MSG_ERROR_DISCONNECTED:{
- m_logger.log("The console has disconnected the controller.", COLOR_RED);
- {
- WriteSpinLock lg(m_state_lock, "PABotBase::on_recv_message() - 2");
- m_error_message = "Disconnected by console.";
- }
- m_error.store(true, std::memory_order_release);
- {
- std::lock_guard lg0(m_sleep_lock);
- }
- m_cv.notify_all();
- return;
- }
- case PABB_MSG_REQUEST_COMMAND_FINISHED:{
- process_command_finished(std::move(message));
- return;
- }
- }
-}
-
-void PABotBase::retransmit_thread(){
- auto scope_check = m_sanitizer.check_scope();
-
-// cout << "retransmit_thread()" << endl;
- auto last_sent = current_time();
- while (m_state.load(std::memory_order_acquire) == State::RUNNING){
- auto now = current_time();
-
- if (now - last_sent < m_retransmit_delay){
- std::unique_lock lg(m_sleep_lock);
- if (m_state.load(std::memory_order_acquire) != State::RUNNING){
- break;
- }
- if (m_error.load(std::memory_order_acquire)){
- break;
- }
- m_cv.wait_for(lg, m_retransmit_delay);
- continue;
- }
-
- // Process retransmits.
- WriteSpinLock lg(m_state_lock, "PABotBase::retransmit_thread()");
-// std::cout << "retransmit_thread - m_pending_messages.size(): " << m_pending_messages.size() << std::endl;
-// cout << "m_pending_messages.size()" << endl;
-
- // Retransmit
- // Iterate through all pending requests and retransmit them in
- // chronological order. ~~Skip the ones that are new.~~
- // (Don't skip the new ones since it will lead to gaps.)
-
- // Gather together all requests/commands. Sort them by seqnum and
- // resend everything.
-
- WallClock oldest = last_sent;
-
- std::map messages;
- for (auto& item : m_pending_requests){
- item.second.sanitizer.check_usage();
- if (item.second.state == AckState::NOT_ACKED){
- oldest = std::max(oldest, item.second.first_sent);
- messages[item.first] = &item.second.request;
- }
- }
- for (auto& item : m_pending_commands){
- item.second.sanitizer.check_usage();
- if (item.second.state == AckState::NOT_ACKED){
- oldest = std::max(oldest, item.second.first_sent);
- messages[item.first] = &item.second.request;
- }
- }
-
- if (!messages.empty() && now - oldest >= m_retransmit_delay){
- for (const auto& item : messages){
- send_message(*item.second, true);
- }
- }
-
-#if 0
- for (auto& item : m_pending_requests){
- item.second.sanitizer.check_usage();
- if (item.second.state == AckState::NOT_ACKED &&
- current_time() - item.second.first_sent >= m_retransmit_delay
- ){
- send_message(item.second.request, true);
- }
- }
- for (auto& item : m_pending_commands){
- item.second.sanitizer.check_usage();
- if (item.second.state == AckState::NOT_ACKED &&
- current_time() - item.second.first_sent >= m_retransmit_delay
- ){
- send_message(item.second.request, true);
- }
- }
-#endif
-
- last_sent = current_time();
- }
-// cout << "retransmit_thread() - exit" << endl;
-}
-
-
-
-
-uint64_t PABotBase::try_issue_request(
- Cancellable* cancelled,
- const BotBaseRequest& request,
- bool silent_remove, bool do_not_block
-){
- auto scope_check = m_sanitizer.check_scope();
-
- BotBaseMessage message = request.message();
- if (message.body.size() < sizeof(uint32_t)){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "Message is too short.");
- }
- if (message.body.size() > PABB_PROTOCOL_MAX_PACKET_SIZE){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "Message is too long.");
- }
-
- WriteSpinLock lg(m_state_lock, "PABotBase::try_issue_request()");
- if (cancelled){
- cancelled->throw_if_cancelled();
- }
-
- State state = m_state.load(std::memory_order_acquire);
- if (state != State::RUNNING){
- throw InvalidConnectionStateException(m_error_message);
- }
- if (m_error.load(std::memory_order_acquire)){
- throw ConnectionException(&m_logger, m_error_message);
- }
-
- size_t queue_limit = m_max_pending_requests.load(std::memory_order_relaxed);
-
- // Too many unacked requests in flight.
- if (!do_not_block && inflight_requests() >= queue_limit){
-// m_logger.log("Message throttled due to too many inflight requests.");
- return 0;
- }
-
- // Don't get too far ahead of the oldest seqnum.
- uint64_t seqnum = m_send_seq;
- if (seqnum - oldest_live_seqnum() > MAX_SEQNUM_GAP){
- if (do_not_block){
- throw ConnectionException(
- &m_logger,
- "Connection has stalled for a long time. Assuming it is dead."
- );
- }
- return 0;
- }
-
- seqnum_t seqnum_s = (seqnum_t)seqnum;
- memcpy(&message.body[0], &seqnum_s, sizeof(seqnum_t));
-
- std::pair::iterator, bool> ret = m_pending_requests.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(seqnum),
- std::forward_as_tuple()
- );
- if (!ret.second){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "Duplicate sequence number: " + std::to_string(seqnum));
- }
-
- m_send_seq = seqnum + 1;
-
- PendingRequest& handle = ret.first->second;
-
- handle.silent_remove = silent_remove;
- handle.request = std::move(message);
- handle.first_sent = current_time();
-
-#ifdef INTENTIONALLY_DROP_MESSAGES
- if (rand() % 10 != 0){
- send_message(handle.request, false);
- }else{
- m_logger.log("Intentionally dropping request: " + std::to_string(seqnum), COLOR_RED);
- }
-#else
- send_message(handle.request, false);
-#endif
-
- return seqnum;
-}
-uint64_t PABotBase::try_issue_command(
- Cancellable* cancelled,
- const BotBaseRequest& request,
- bool silent_remove
-){
- auto scope_check = m_sanitizer.check_scope();
-
- BotBaseMessage message = request.message();
- if (message.body.size() < sizeof(uint32_t)){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "Message is too short.");
- }
- if (message.body.size() > PABB_PROTOCOL_MAX_PACKET_SIZE){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "Message is too long.");
- }
-
- WriteSpinLock lg(m_state_lock, "PABotBase::try_issue_command()");
- if (cancelled){
- cancelled->throw_if_cancelled();
- }
-
- State state = m_state.load(std::memory_order_acquire);
- if (state != State::RUNNING){
- throw InvalidConnectionStateException(m_error_message);
- }
- if (m_error.load(std::memory_order_acquire)){
- throw ConnectionException(&m_logger, m_error_message);
- }
-
- size_t queue_limit = m_max_pending_requests.load(std::memory_order_relaxed);
-
- // Command queue is full.
- if (m_pending_commands.size() >= queue_limit){
-// cout << "Command queue is full" << endl;
- return 0;
- }
-
- // Too many unacked requests in flight.
- if (inflight_requests() >= queue_limit){
-// m_logger.log("Message throttled due to too many inflight requests.");
- return 0;
- }
-
- // Don't get too far ahead of the oldest seqnum.
- uint64_t seqnum = m_send_seq;
- if (seqnum - oldest_live_seqnum() > MAX_SEQNUM_GAP){
- return 0;
- }
-
- seqnum_t seqnum_s = (seqnum_t)seqnum;
- memcpy(&message.body[0], &seqnum_s, sizeof(seqnum_t));
-
- std::pair::iterator, bool> ret = m_pending_commands.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(seqnum),
- std::forward_as_tuple()
- );
- if (!ret.second){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "Duplicate sequence number: " + std::to_string(seqnum));
- }
-
- m_send_seq = seqnum + 1;
-
- PendingCommand& handle = ret.first->second;
-
- handle.silent_remove = silent_remove;
- handle.request = std::move(message);
- handle.first_sent = current_time();
-
-#ifdef INTENTIONALLY_DROP_MESSAGES
- if (rand() % 10 != 0){
- send_message(handle.request, false);
- }else{
- m_logger.log("Intentionally dropping command: " + std::to_string(seqnum), COLOR_RED);
- }
-#else
- send_message(handle.request, false);
-#endif
-
- return seqnum;
-}
-uint64_t PABotBase::issue_request(
- Cancellable* cancelled,
- const BotBaseRequest& request,
- bool silent_remove, bool do_not_block
-){
- auto scope_check = m_sanitizer.check_scope();
-
- // Issue a request and return.
- //
- // If it cannot be issued (because we're over the limits), this function
- // will wait until it can be issued.
- //
- // The "silent_remove" parameter determines what to do when the
- // ack (for a request) or a finish (for a command) is received.
- //
- // If (silent_remove = true), the receiving thread will remove the request
- // from the map and do nothing else. This is for async commands.
- //
- // If (silent_remove = false), the receiving thread will not remove the
- // request. Instead, it will notify whatever thread is waiting for the
- // result. That waiting thread will process the return value (if any) and
- // remove the request from the map. This is for synchronous commands where
- // the function waits for the command to finish before returning.
- //
-
- while (true){
- uint64_t seqnum = try_issue_request(cancelled, request, silent_remove, do_not_block);
- if (seqnum != 0){
- return seqnum;
- }
- std::unique_lock lg(m_sleep_lock);
- if (cancelled){
- cancelled->throw_if_cancelled();
- }
- if (m_state.load(std::memory_order_acquire) != State::RUNNING){
- ReadSpinLock lg0(m_state_lock, "PABotBase::issue_request() - 0");
- throw InvalidConnectionStateException(m_error_message);
- }
- if (m_error.load(std::memory_order_acquire)){
- ReadSpinLock lg0(m_state_lock, "PABotBase::issue_request() - 1");
- throw ConnectionException(&m_logger, m_error_message);
- }
- cv_wait(cancelled, lg);
- }
-}
-uint64_t PABotBase::issue_command(
- Cancellable* cancelled,
- const BotBaseRequest& request,
- bool silent_remove
-){
- auto scope_check = m_sanitizer.check_scope();
-
- // Issue a command and return.
- //
- // If it cannot be issued (because we're over the limits), this function
- // will wait until it can be issued.
- //
- // The "silent_remove" parameter determines what to do when the
- // ack (for a request) or a finish (for a command) is received.
- //
- // If (silent_remove = true), the receiving thread will remove the request
- // from the map and do nothing else. This is for async commands.
- //
- // If (silent_remove = false), the receiving thread will not remove the
- // request. Instead, it will notify whatever thread is waiting for the
- // result. That waiting thread will process the return value (if any) and
- // remove the request from the map. This is for synchronous commands where
- // the function waits for the command to finish before returning.
- //
-
- while (true){
- uint64_t seqnum = try_issue_command(cancelled, request, silent_remove);
- if (seqnum != 0){
- return seqnum;
- }
- std::unique_lock lg(m_sleep_lock);
- if (cancelled){
- cancelled->throw_if_cancelled();
- }
- if (m_state.load(std::memory_order_acquire) != State::RUNNING){
- ReadSpinLock lg0(m_state_lock, "PABotBase::issue_command() - 0");
- throw InvalidConnectionStateException(m_error_message);
- }
- if (m_error.load(std::memory_order_acquire)){
- ReadSpinLock lg0(m_state_lock, "PABotBase::issue_command() - 1");
- throw ConnectionException(&m_logger, m_error_message);
- }
- cv_wait(cancelled, lg);
- }
-}
-
-bool PABotBase::try_issue_request(
- const BotBaseRequest& request,
- Cancellable* cancelled
-){
- auto scope_check = m_sanitizer.check_scope();
-
- if (!request.is_command()){
- return try_issue_request(cancelled, request, true, false) != 0;
- }else{
- return try_issue_command(cancelled, request, true) != 0;
- }
-}
-void PABotBase::issue_request(
- const BotBaseRequest& request,
- Cancellable* cancelled
-){
- auto scope_check = m_sanitizer.check_scope();
-
- if (!request.is_command()){
- issue_request(cancelled, request, true, false);
- }else{
- issue_command(cancelled, request, true);
- }
-}
-
-BotBaseMessage PABotBase::issue_request_and_wait(
- const BotBaseRequest& request,
- Cancellable* cancelled
-){
- auto scope_check = m_sanitizer.check_scope();
-
- if (request.is_command()){
- throw InternalProgramError(&m_logger, PA_CURRENT_FUNCTION, "This function only supports requests.");
- }
-
- uint64_t seqnum = issue_request(cancelled, request, false, false);
- return wait_for_request(seqnum, cancelled);
-}
-BotBaseMessage PABotBase::wait_for_request(uint64_t seqnum, Cancellable* cancelled){
- auto scope_check = m_sanitizer.check_scope();
-
- std::unique_lock lg(m_sleep_lock);
- while (true){
- if (cancelled){
- cancelled->throw_if_cancelled();
- }
-
- {
- WriteSpinLock slg(m_state_lock, "PABotBase::issue_request_and_wait()");
- auto iter = m_pending_requests.find(seqnum);
- if (iter == m_pending_requests.end()){
- throw OperationCancelledException();
- }
- iter->second.sanitizer.check_usage();
-
- State state = m_state.load(std::memory_order_acquire);
- if (state != State::RUNNING){
- m_pending_requests.erase(iter);
- m_cv.notify_all();
- throw InvalidConnectionStateException(m_error_message);
- }
- if (m_error.load(std::memory_order_acquire)){
- m_pending_requests.erase(iter);
- m_cv.notify_all();
- throw ConnectionException(&m_logger, m_error_message);
- }
- if (iter->second.state == AckState::ACKED){
- BotBaseMessage ret = std::move(iter->second.ack);
- m_pending_requests.erase(iter);
- m_cv.notify_all();
- return ret;
- }
- }
- cv_wait(cancelled, lg);
- }
-}
-
-
-void PABotBase::cv_wait(Cancellable* cancellable, std::unique_lock& lg){
- if (cancellable == nullptr){
- m_cv.wait(lg);
- return;
- }
-
- cancellable->add_cancel_listener(*this);
- m_cv.wait(lg);
-
- // Unlock to remove. Otherwise, it may deadlock with "on_cancellable_cancel()"
- // being called from a listener callback.
- lg.unlock();
- cancellable->remove_cancel_listener(*this);
- lg.lock();
-}
-
-
-
-
-
-}
diff --git a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/PABotBase.h b/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/PABotBase.h
deleted file mode 100644
index 810deb6984..0000000000
--- a/SerialPrograms/Source/Controllers/SerialPABotBase/Connection/PABotBase.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Pokemon Automation Bot Base
- *
- * From: https://github.com/PokemonAutomation/
- *
- * This is the main PABotBase class.
- *
- * This class represents a connection to a single PABotBase instance running on
- * a user specified COM port. You can have multiple instances of this class if
- * you are connecting to multiple devices at once.
- *
- * This class implements the full communication protocol. So you directly
- * invoke commands from this class which will be passed on to the Arduino/Teensy.
- *
- * Requests and commands may be asynchronous. They may return before the device
- * executes it.
- *
- *
- * Note that button commands will only work if the device is running PABotBase
- * and is not already running a command. The regular programs do not listen to
- * button press requests since they are already running their own program.
- *
- */
-
-#ifndef PokemonAutomation_PABotBase_H
-#define PokemonAutomation_PABotBase_H
-
-#include
-#include