From 1b2358d990561ebdaa94109d963ec3a15e6d211f Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Sun, 28 Jan 2024 22:03:31 +0000 Subject: [PATCH] The great whitespace fix --- .gitattributes | 52 ++ source/.clang-format | 27 +- source/SPoverSLIP/CloseRequest.cpp | 52 +- source/SPoverSLIP/CloseRequest.h | 30 +- source/SPoverSLIP/CloseResponse.cpp | 20 +- source/SPoverSLIP/CloseResponse.h | 18 +- source/SPoverSLIP/Connection.cpp | 84 +-- source/SPoverSLIP/Connection.h | 78 +-- source/SPoverSLIP/ControlRequest.cpp | 62 +-- source/SPoverSLIP/ControlRequest.h | 44 +- source/SPoverSLIP/ControlResponse.cpp | 20 +- source/SPoverSLIP/ControlResponse.h | 18 +- source/SPoverSLIP/FormatRequest.cpp | 52 +- source/SPoverSLIP/FormatRequest.h | 30 +- source/SPoverSLIP/FormatResponse.cpp | 20 +- source/SPoverSLIP/FormatResponse.h | 18 +- source/SPoverSLIP/InitRequest.cpp | 52 +- source/SPoverSLIP/InitRequest.h | 30 +- source/SPoverSLIP/InitResponse.cpp | 20 +- source/SPoverSLIP/InitResponse.h | 18 +- source/SPoverSLIP/Listener.cpp | 665 +++++++++++------------ source/SPoverSLIP/Listener.h | 152 +++--- source/SPoverSLIP/OpenRequest.cpp | 52 +- source/SPoverSLIP/OpenRequest.h | 30 +- source/SPoverSLIP/OpenResponse.cpp | 20 +- source/SPoverSLIP/OpenResponse.h | 18 +- source/SPoverSLIP/Packet.h | 24 +- source/SPoverSLIP/ReadBlockRequest.cpp | 88 ++- source/SPoverSLIP/ReadBlockRequest.h | 46 +- source/SPoverSLIP/ReadBlockResponse.cpp | 42 +- source/SPoverSLIP/ReadBlockResponse.h | 32 +- source/SPoverSLIP/ReadRequest.cpp | 83 ++- source/SPoverSLIP/ReadRequest.h | 54 +- source/SPoverSLIP/ReadResponse.cpp | 42 +- source/SPoverSLIP/ReadResponse.h | 30 +- source/SPoverSLIP/Request.cpp | 19 +- source/SPoverSLIP/Request.h | 50 +- source/SPoverSLIP/Requestor.cpp | 69 ++- source/SPoverSLIP/Requestor.h | 38 +- source/SPoverSLIP/ResetRequest.cpp | 52 +- source/SPoverSLIP/ResetRequest.h | 30 +- source/SPoverSLIP/ResetResponse.cpp | 20 +- source/SPoverSLIP/ResetResponse.h | 18 +- source/SPoverSLIP/Response.cpp | 12 +- source/SPoverSLIP/Response.h | 32 +- source/SPoverSLIP/SLIP.cpp | 288 +++++----- source/SPoverSLIP/SLIP.h | 38 +- source/SPoverSLIP/SPoSLIP.h | 30 +- source/SPoverSLIP/SmartPortCodes.h | 32 +- source/SPoverSLIP/StatusRequest.cpp | 83 ++- source/SPoverSLIP/StatusRequest.h | 38 +- source/SPoverSLIP/StatusResponse.cpp | 48 +- source/SPoverSLIP/StatusResponse.h | 38 +- source/SPoverSLIP/TCPConnection.cpp | 272 ++++----- source/SPoverSLIP/TCPConnection.h | 42 +- source/SPoverSLIP/WriteBlockRequest.cpp | 95 ++-- source/SPoverSLIP/WriteBlockRequest.h | 54 +- source/SPoverSLIP/WriteBlockResponse.cpp | 20 +- source/SPoverSLIP/WriteBlockResponse.h | 18 +- source/SPoverSLIP/WriteRequest.cpp | 91 ++-- source/SPoverSLIP/WriteRequest.h | 62 +-- source/SPoverSLIP/WriteResponse.cpp | 20 +- source/SPoverSLIP/WriteResponse.h | 18 +- source/SmartPortOverSlip.cpp | 321 +++++------ source/SmartPortOverSlip.h | 212 ++++---- 65 files changed, 2168 insertions(+), 2115 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..114aea528 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,52 @@ +############################### +# Git Line Endings # +############################### + +# Set default behaviour to automatically normalize line endings. +* text=auto + +# Source files +*.cpp text +*.c text +*.h text + +# Force batch scripts to always use CRLF line endings so that if a repo is accessed +# in Windows via a file share from Linux, the scripts will work. +*.[cC][mM][dD] text eol=crlf +*.[bB][aA][tT] text eol=crlf + +# Force bash scripts to always use LF line endings so that if a repo is accessed +# in Unix via a file share from Windows, the scripts will work. +*.sh text eol=lf + +############################### +# Git Large File System (LFS) # +############################### + +# Archives +*.7z filter=lfs diff=lfs merge=lfs -text +*.br filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tz filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text + +# Documents +*.pdf filter=lfs diff=lfs merge=lfs -text + +# Images +*.gif filter=lfs diff=lfs merge=lfs -text +*.ico filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.psd filter=lfs diff=lfs merge=lfs -text +*.webp filter=lfs diff=lfs merge=lfs -text + +# Fonts +*.woff2 filter=lfs diff=lfs merge=lfs -text + +# Other +*.exe filter=lfs diff=lfs merge=lfs -text diff --git a/source/.clang-format b/source/.clang-format index 6e31f4ce2..2d12d9496 100644 --- a/source/.clang-format +++ b/source/.clang-format @@ -1,7 +1,30 @@ BasedOnStyle: LLVM -ColumnLimit: 160 -BreakBeforeBraces: Allman +ColumnLimit: 200 AllowShortBlocksOnASingleLine: true AlwaysBreakAfterReturnType: None IncludeBlocks: Preserve SortIncludes: false +UseTab: Always +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: -4 +AlwaysBreakTemplateDeclarations: Yes +BreakInheritanceList: AfterColon +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +IndentPPDirectives: BeforeHash \ No newline at end of file diff --git a/source/SPoverSLIP/CloseRequest.cpp b/source/SPoverSLIP/CloseRequest.cpp index d8bac5432..7638eeb8b 100644 --- a/source/SPoverSLIP/CloseRequest.cpp +++ b/source/SPoverSLIP/CloseRequest.cpp @@ -1,26 +1,26 @@ -#include "CloseRequest.h" - -#include "CloseResponse.h" -#include "SmartPortCodes.h" - -CloseRequest::CloseRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_CLOSE, sp_unit) {} - -std::vector CloseRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - return request_data; -} - -std::unique_ptr CloseRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize CloseResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} +#include "CloseRequest.h" + +#include "CloseResponse.h" +#include "SmartPortCodes.h" + +CloseRequest::CloseRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_CLOSE, sp_unit) {} + +std::vector CloseRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + return request_data; +} + +std::unique_ptr CloseRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize CloseResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} diff --git a/source/SPoverSLIP/CloseRequest.h b/source/SPoverSLIP/CloseRequest.h index 9c9491a7a..ad0aef2c8 100644 --- a/source/SPoverSLIP/CloseRequest.h +++ b/source/SPoverSLIP/CloseRequest.h @@ -1,15 +1,15 @@ -#pragma once - -#include -#include - -#include "Request.h" -#include "Response.h" - -class CloseRequest : public Request -{ -public: - CloseRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; -}; +#pragma once + +#include +#include + +#include "Request.h" +#include "Response.h" + +class CloseRequest : public Request +{ +public: + CloseRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; +}; diff --git a/source/SPoverSLIP/CloseResponse.cpp b/source/SPoverSLIP/CloseResponse.cpp index b001ca387..f1bef058e 100644 --- a/source/SPoverSLIP/CloseResponse.cpp +++ b/source/SPoverSLIP/CloseResponse.cpp @@ -1,11 +1,11 @@ -#include "CloseResponse.h" - -CloseResponse::CloseResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector CloseResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "CloseResponse.h" + +CloseResponse::CloseResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector CloseResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/CloseResponse.h b/source/SPoverSLIP/CloseResponse.h index 8fee7841c..5b921fe64 100644 --- a/source/SPoverSLIP/CloseResponse.h +++ b/source/SPoverSLIP/CloseResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class CloseResponse : public Response -{ -public: - explicit CloseResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class CloseResponse : public Response +{ +public: + explicit CloseResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/Connection.cpp b/source/SPoverSLIP/Connection.cpp index 7cc4907ca..2691432a9 100644 --- a/source/SPoverSLIP/Connection.cpp +++ b/source/SPoverSLIP/Connection.cpp @@ -1,42 +1,42 @@ -#include "Connection.h" -#include -#include -#include -#include -#include - -// This is called after AppleWin sends a request to a device, and is waiting for the response -std::vector Connection::wait_for_response(uint8_t request_id, std::chrono::seconds timeout) -{ - std::unique_lock lock(data_mutex_); - // mutex is unlocked as it goes into a wait, so then the inserting thread can - // add to map, and this can then pick it up when notified, or timeout. - if (!data_cv_.wait_for(lock, timeout, [this, request_id]() { return data_map_.count(request_id) > 0; })) - { - throw std::runtime_error("Timeout waiting for response"); - } - std::vector response_data = data_map_[request_id]; - data_map_.erase(request_id); - return response_data; -} - -// This is used by devices that are waiting for requests from AppleWin. -// The codebase is used both sides of the connection. -std::vector Connection::wait_for_request() -{ - std::unique_lock lock(data_mutex_); - data_cv_.wait(lock, [this]() { return !data_map_.empty(); }); - const auto it = data_map_.begin(); - std::vector request_data = it->second; - data_map_.erase(it); - - return request_data; -} - -void Connection::join() -{ - if (reading_thread_.joinable()) - { - reading_thread_.join(); - } -} +#include "Connection.h" +#include +#include +#include +#include +#include + +// This is called after AppleWin sends a request to a device, and is waiting for the response +std::vector Connection::wait_for_response(uint8_t request_id, std::chrono::seconds timeout) +{ + std::unique_lock lock(data_mutex_); + // mutex is unlocked as it goes into a wait, so then the inserting thread can + // add to map, and this can then pick it up when notified, or timeout. + if (!data_cv_.wait_for(lock, timeout, [this, request_id]() { return data_map_.count(request_id) > 0; })) + { + throw std::runtime_error("Timeout waiting for response"); + } + std::vector response_data = data_map_[request_id]; + data_map_.erase(request_id); + return response_data; +} + +// This is used by devices that are waiting for requests from AppleWin. +// The codebase is used both sides of the connection. +std::vector Connection::wait_for_request() +{ + std::unique_lock lock(data_mutex_); + data_cv_.wait(lock, [this]() { return !data_map_.empty(); }); + const auto it = data_map_.begin(); + std::vector request_data = it->second; + data_map_.erase(it); + + return request_data; +} + +void Connection::join() +{ + if (reading_thread_.joinable()) + { + reading_thread_.join(); + } +} diff --git a/source/SPoverSLIP/Connection.h b/source/SPoverSLIP/Connection.h index 6bc042b6c..8f703e95e 100644 --- a/source/SPoverSLIP/Connection.h +++ b/source/SPoverSLIP/Connection.h @@ -1,39 +1,39 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class Connection -{ -public: - virtual ~Connection() = default; - virtual void send_data(const std::vector &data) = 0; - - virtual void create_read_channel() = 0; - virtual void close_connection() = 0; - - bool is_connected() const { return is_connected_; } - void set_is_connected(const bool is_connected) { is_connected_ = is_connected; } - - std::vector wait_for_response(uint8_t request_id, std::chrono::seconds timeout); - std::vector wait_for_request(); - - void join(); - -private: - std::atomic is_connected_{false}; - -protected: - std::map> data_map_; - std::thread reading_thread_; - - std::mutex data_mutex_; - std::condition_variable data_cv_; -}; +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Connection +{ +public: + virtual ~Connection() = default; + virtual void send_data(const std::vector &data) = 0; + + virtual void create_read_channel() = 0; + virtual void close_connection() = 0; + + bool is_connected() const { return is_connected_; } + void set_is_connected(const bool is_connected) { is_connected_ = is_connected; } + + std::vector wait_for_response(uint8_t request_id, std::chrono::seconds timeout); + std::vector wait_for_request(); + + void join(); + +private: + std::atomic is_connected_{false}; + +protected: + std::map> data_map_; + std::thread reading_thread_; + + std::mutex data_mutex_; + std::condition_variable data_cv_; +}; diff --git a/source/SPoverSLIP/ControlRequest.cpp b/source/SPoverSLIP/ControlRequest.cpp index 0df9fb35a..a923b598b 100644 --- a/source/SPoverSLIP/ControlRequest.cpp +++ b/source/SPoverSLIP/ControlRequest.cpp @@ -1,31 +1,31 @@ -#include "ControlRequest.h" - -#include "ControlResponse.h" -#include "SmartPortCodes.h" - -ControlRequest::ControlRequest(const uint8_t request_sequence_number, const uint8_t sp_unit, const uint8_t control_code, std::vector &data) - : Request(request_sequence_number, SP_CONTROL, sp_unit), control_code_(control_code), data_(std::move(data)) -{ -} - -std::vector ControlRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - request_data.push_back(this->get_control_code()); - request_data.insert(request_data.end(), get_data().begin(), get_data().end()); - return request_data; -} - -std::unique_ptr ControlRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize ControlResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} +#include "ControlRequest.h" + +#include "ControlResponse.h" +#include "SmartPortCodes.h" + +ControlRequest::ControlRequest(const uint8_t request_sequence_number, const uint8_t sp_unit, const uint8_t control_code, std::vector &data) + : Request(request_sequence_number, SP_CONTROL, sp_unit), control_code_(control_code), data_(std::move(data)) +{ +} + +std::vector ControlRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + request_data.push_back(this->get_control_code()); + request_data.insert(request_data.end(), get_data().begin(), get_data().end()); + return request_data; +} + +std::unique_ptr ControlRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize ControlResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} diff --git a/source/SPoverSLIP/ControlRequest.h b/source/SPoverSLIP/ControlRequest.h index 5e7147d86..0716df2a2 100644 --- a/source/SPoverSLIP/ControlRequest.h +++ b/source/SPoverSLIP/ControlRequest.h @@ -1,22 +1,22 @@ -#pragma once - -#include -#include - -#include "Request.h" -#include "Response.h" - -class ControlRequest : public Request -{ -public: - ControlRequest(const uint8_t request_sequence_number, const uint8_t sp_unit, const uint8_t control_code, std::vector &data); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; - - const std::vector &get_data() const { return data_; } - uint8_t get_control_code() const { return control_code_; } - -private: - uint8_t control_code_; - std::vector data_; -}; +#pragma once + +#include +#include + +#include "Request.h" +#include "Response.h" + +class ControlRequest : public Request +{ +public: + ControlRequest(const uint8_t request_sequence_number, const uint8_t sp_unit, const uint8_t control_code, std::vector &data); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; + + const std::vector &get_data() const { return data_; } + uint8_t get_control_code() const { return control_code_; } + +private: + uint8_t control_code_; + std::vector data_; +}; diff --git a/source/SPoverSLIP/ControlResponse.cpp b/source/SPoverSLIP/ControlResponse.cpp index c2f5fc543..1b0bb5a21 100644 --- a/source/SPoverSLIP/ControlResponse.cpp +++ b/source/SPoverSLIP/ControlResponse.cpp @@ -1,11 +1,11 @@ -#include "ControlResponse.h" - -ControlResponse::ControlResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector ControlResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "ControlResponse.h" + +ControlResponse::ControlResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector ControlResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/ControlResponse.h b/source/SPoverSLIP/ControlResponse.h index 97eb8ebd1..bcff3af9b 100644 --- a/source/SPoverSLIP/ControlResponse.h +++ b/source/SPoverSLIP/ControlResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class ControlResponse : public Response -{ -public: - explicit ControlResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class ControlResponse : public Response +{ +public: + explicit ControlResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/FormatRequest.cpp b/source/SPoverSLIP/FormatRequest.cpp index ee2c24031..e56befebf 100644 --- a/source/SPoverSLIP/FormatRequest.cpp +++ b/source/SPoverSLIP/FormatRequest.cpp @@ -1,26 +1,26 @@ -#include "FormatRequest.h" - -#include "FormatResponse.h" -#include "SmartPortCodes.h" - -FormatRequest::FormatRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_FORMAT, sp_unit) {} - -std::vector FormatRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - return request_data; -} - -std::unique_ptr FormatRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize FormatResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} +#include "FormatRequest.h" + +#include "FormatResponse.h" +#include "SmartPortCodes.h" + +FormatRequest::FormatRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_FORMAT, sp_unit) {} + +std::vector FormatRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + return request_data; +} + +std::unique_ptr FormatRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize FormatResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} diff --git a/source/SPoverSLIP/FormatRequest.h b/source/SPoverSLIP/FormatRequest.h index 08b4ed98d..d45afd10a 100644 --- a/source/SPoverSLIP/FormatRequest.h +++ b/source/SPoverSLIP/FormatRequest.h @@ -1,15 +1,15 @@ -#pragma once - -#include -#include - -#include "Request.h" -#include "Response.h" - -class FormatRequest : public Request -{ -public: - FormatRequest(const uint8_t request_sequence_number, const uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; -}; +#pragma once + +#include +#include + +#include "Request.h" +#include "Response.h" + +class FormatRequest : public Request +{ +public: + FormatRequest(const uint8_t request_sequence_number, const uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; +}; diff --git a/source/SPoverSLIP/FormatResponse.cpp b/source/SPoverSLIP/FormatResponse.cpp index fef7845be..58e266d92 100644 --- a/source/SPoverSLIP/FormatResponse.cpp +++ b/source/SPoverSLIP/FormatResponse.cpp @@ -1,11 +1,11 @@ -#include "FormatResponse.h" - -FormatResponse::FormatResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector FormatResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "FormatResponse.h" + +FormatResponse::FormatResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector FormatResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/FormatResponse.h b/source/SPoverSLIP/FormatResponse.h index 932300b62..04b785f7a 100644 --- a/source/SPoverSLIP/FormatResponse.h +++ b/source/SPoverSLIP/FormatResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class FormatResponse : public Response -{ -public: - explicit FormatResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class FormatResponse : public Response +{ +public: + explicit FormatResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/InitRequest.cpp b/source/SPoverSLIP/InitRequest.cpp index 925a90011..24e69a001 100644 --- a/source/SPoverSLIP/InitRequest.cpp +++ b/source/SPoverSLIP/InitRequest.cpp @@ -1,26 +1,26 @@ -#include "InitRequest.h" - -#include "InitResponse.h" -#include "SmartPortCodes.h" - -InitRequest::InitRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_INIT, sp_unit) {} - -std::vector InitRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - return request_data; -} - -std::unique_ptr InitRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize InitResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} +#include "InitRequest.h" + +#include "InitResponse.h" +#include "SmartPortCodes.h" + +InitRequest::InitRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_INIT, sp_unit) {} + +std::vector InitRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + return request_data; +} + +std::unique_ptr InitRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize InitResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} diff --git a/source/SPoverSLIP/InitRequest.h b/source/SPoverSLIP/InitRequest.h index ef75559eb..3e34b1dc5 100644 --- a/source/SPoverSLIP/InitRequest.h +++ b/source/SPoverSLIP/InitRequest.h @@ -1,15 +1,15 @@ -#pragma once - -#include -#include - -#include "Request.h" -#include "Response.h" - -class InitRequest : public Request -{ -public: - InitRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; -}; +#pragma once + +#include +#include + +#include "Request.h" +#include "Response.h" + +class InitRequest : public Request +{ +public: + InitRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; +}; diff --git a/source/SPoverSLIP/InitResponse.cpp b/source/SPoverSLIP/InitResponse.cpp index 43790235e..7c8628420 100644 --- a/source/SPoverSLIP/InitResponse.cpp +++ b/source/SPoverSLIP/InitResponse.cpp @@ -1,11 +1,11 @@ -#include "InitResponse.h" - -InitResponse::InitResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector InitResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "InitResponse.h" + +InitResponse::InitResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector InitResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/InitResponse.h b/source/SPoverSLIP/InitResponse.h index a6cd578b7..f539564c3 100644 --- a/source/SPoverSLIP/InitResponse.h +++ b/source/SPoverSLIP/InitResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class InitResponse : public Response -{ -public: - explicit InitResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class InitResponse : public Response +{ +public: + explicit InitResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/Listener.cpp b/source/SPoverSLIP/Listener.cpp index 494ae6fd7..d48b37911 100644 --- a/source/SPoverSLIP/Listener.cpp +++ b/source/SPoverSLIP/Listener.cpp @@ -1,333 +1,332 @@ - -#include -#include -#include -#include - -#include "Listener.h" - -#include "InitRequest.h" -#include "InitResponse.h" -#include "SLIP.h" -#include "TCPConnection.h" -#include "StatusRequest.h" -#include "StatusResponse.h" - -#include "Log.h" -#include "Requestor.h" - -// clang-format off -#ifdef WIN32 - #include - #include - #pragma comment(lib, "ws2_32.lib") - #define CLOSE_SOCKET closesocket - #define SOCKET_ERROR_CODE WSAGetLastError() -#else - #include - #include - #include - #include - #include - #include -#include "StatusRequest.h" -#include "StatusRequest.h" - #define CLOSE_SOCKET close - #define SOCKET_ERROR_CODE errno - #define INVALID_SOCKET -1 - #define SOCKET_ERROR -1 -#endif -// clang-format off - -uint8_t Listener::next_device_id_ = 1; -const std::regex Listener::ipPattern("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); - -Listener& GetSPoverSLIPListener(void) -{ - static Listener listener; - return listener; -} - -Listener::Listener() : is_listening_(false) {} - -void Listener::Initialize(std::string ip_address, const uint16_t port) -{ - ip_address_ = std::move(ip_address); - port_ = port; -} - -bool Listener::get_is_listening() const { return is_listening_; } - -void Listener::insert_connection(uint8_t start_id, uint8_t end_id, const std::shared_ptr &conn) -{ - connection_map_[{start_id, end_id}] = conn; -} - -uint8_t Listener::get_total_device_count() { return next_device_id_ - 1; } - -Listener::~Listener() { stop(); } - -std::thread Listener::create_listener_thread() { return std::thread(&Listener::listener_function, this); } - -void Listener::listener_function() -{ - LogFileOutput("Listener::listener_function - RUNNING\n"); - int server_fd, new_socket; - struct sockaddr_in address; -#ifdef WIN32 - int address_length = sizeof(address); -#else - socklen_t address_length = sizeof(address); -#endif - -#ifdef WIN32 - WSADATA wsa_data; - if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { - LogFileOutput("WSAStartup failed: %d\n", WSAGetLastError()); - } -#endif - - if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) - { - LogFileOutput("Listener::listener_function - Socket creation failed\n"); - return; - } - - address.sin_family = AF_INET; - address.sin_port = htons(port_); - inet_pton(AF_INET, ip_address_.c_str(), &(address.sin_addr)); - -#ifdef WIN32 - char opt = 1; -#else - int opt = 1; -#endif - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == SOCKET_ERROR) - { - LogFileOutput("Listener::listener_function - setsockopt failed\n"); - return; - } -#ifdef WIN32 - if (bind(server_fd, reinterpret_cast(&address), sizeof(address)) == SOCKET_ERROR) -#else - if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) == SOCKET_ERROR) -#endif - { - LogFileOutput("Listener::listener_function - bind failed\n"); - return; - } - - if (listen(server_fd, 3) < 0) - { - LogFileOutput("Listener::listener_function - listen failed\n"); - return; - } - - while (is_listening_) - { - fd_set sock_set; - FD_ZERO(&sock_set); - FD_SET(server_fd, &sock_set); - - timeval timeout; - timeout.tv_sec = 2; - timeout.tv_usec = 0; - - const int activity = select(server_fd + 1, &sock_set, nullptr, nullptr, &timeout); - - if (activity == SOCKET_ERROR) - { - LogFileOutput("Listener::listener_function - select failed\n"); - is_listening_ = false; - break; - } - - if (activity == 0) - { - // timeout occurred, no client connection. Still need to check is_listening_ - continue; - } - -#ifdef WIN32 - if ((new_socket = accept(server_fd, reinterpret_cast(&address), &address_length)) == INVALID_SOCKET) -#else - if ((new_socket = accept(server_fd, (struct sockaddr *)&address, &address_length)) == INVALID_SOCKET) -#endif - { - LogFileOutput("Listener::listener_function - accept failed\n"); - is_listening_ = false; - break; - } - - create_connection(new_socket); - } - - LogFileOutput("Listener::listener_function - listener closing down\n"); - - CLOSE_SOCKET(server_fd); -} - -// Creates a Connection object, which is how SP device(s) will register itself with our listener. -void Listener::create_connection(unsigned int socket) -{ - // Create a connection, give it some time to settle, else exit without creating listener to connection - const std::shared_ptr conn = std::make_shared(socket); - conn->create_read_channel(); - - const auto start = std::chrono::steady_clock::now(); - // Give the connection a generous 10 seconds to work. - constexpr auto timeout = std::chrono::seconds(10); - - while (!conn->is_connected()) - { - auto now = std::chrono::steady_clock::now(); - if (std::chrono::duration_cast(now - start) > timeout) - { - LogFileOutput("Listener::create_connection() - Failed to establish " - "connection, timed out.\n"); - return; - } - } - - // We need to send an INIT to device 01 for this connection, then 02, ... - // until we get an error back This will determine the number of devices - // attached. - - bool still_scanning = true; - uint8_t unit_id = 1; - - // send init requests to find all the devices on this connection, or we have too many devices. - while (still_scanning && (unit_id + next_device_id_) < 255) - { - LogFileOutput("SmartPortOverSlip listener sending request for unit_id: %d\n", unit_id); - InitRequest request(Requestor::next_request_number(), unit_id); - const auto response = Requestor::send_request(request, conn.get()); - const auto init_response = dynamic_cast(response.get()); - if (init_response == nullptr) - { - LogFileOutput("SmartPortOverSlip listener ERROR, no response data found\n"); - break; - } - still_scanning = init_response->get_status() == 0; - if (still_scanning) - unit_id++; - } - - const auto start_id = next_device_id_; - const auto end_id = static_cast(start_id + unit_id - 1); - next_device_id_ = end_id + 1; - // track the connection and device ranges it reported. Further connections can add to the devices we can target. - LogFileOutput("SmartPortOverSlip listener creating connection for start: %d, end: %d\n", start_id, end_id); - insert_connection(start_id, end_id, conn); -} - -void Listener::start() -{ - is_listening_ = true; - listening_thread_ = std::thread(&Listener::listener_function, this); -} - -void Listener::stop() -{ - LogFileOutput("Listener::stop()\n"); - if (is_listening_) - { - // Stop listener first, otherwise the PC might reboot too fast and be picked up - is_listening_ = false; - LogFileOutput("Listener::stop() ... joining listener until it stops\n"); - listening_thread_.join(); - - LogFileOutput("Listener::stop() - closing %ld connections\n", connection_map_.size()); - for (auto &pair : connection_map_) - { - const auto &connection = pair.second; - connection->set_is_connected(false); - connection->close_connection(); - connection->join(); - } - } - next_device_id_ = 1; - connection_map_.clear(); - -#ifdef WIN32 - WSACleanup(); -#endif - - LogFileOutput("Listener::stop() ... finished\n"); -} - -// Returns the ADJUSTED lower bound of the device id, and connection. -// i.e. the ID that the target thinks the device index is. -// We store (for example) device_ids in applewin with values 1-5 for connection 1, 6-8 for connection 2, but each device things they are 1-5, and 1-3 (not 6-8). -// However the apple side sees 1-8, and so we have to convert 6, 7, 8 into the target's 1, 2, 3 -std::pair> Listener::find_connection_with_device(const uint8_t device_id) const -{ - std::pair> result; - for (const auto &kv : connection_map_) - { - if (device_id >= kv.first.first && device_id <= kv.first.second) - { - result = std::make_pair(device_id - kv.first.first + 1, kv.second); - break; - } - } - return result; -} - -std::vector> Listener::get_all_connections() const -{ - std::vector> connections; - for (const auto &kv : connection_map_) - { - for (uint8_t id = kv.first.first; id <= kv.first.second; ++id) - { - connections.emplace_back(id, kv.second.get()); - } - } - return connections; -} - -std::pair Listener::first_two_disk_devices() const { - if (cache_valid) { - return cached_disk_devices; - } - - cached_disk_devices = {-1, -1}; // Initialize with invalid device ids - - for (uint8_t unit_number = 1; unit_number < next_device_id_; ++unit_number) { - const auto id_and_connection = GetSPoverSLIPListener().find_connection_with_device(unit_number); - if (id_and_connection.second == nullptr) continue; - - // ids from the map need adjusting down to their real ids on the device - - - // DIB request to get information block - const StatusRequest request(Requestor::next_request_number(), unit_number, 3); - - - std::unique_ptr response = Requestor::send_request(request, id_and_connection.second.get()); - - // Cast the Response to a StatusResponse - StatusResponse* statusResponse = dynamic_cast(response.get()); - - if (statusResponse) { - const std::vector& data = statusResponse->get_data(); - - // Check if data size is at least 22 and the device type is a disk, and that the disk status is ONLINE (status[0] bit 4) - if (data.size() >= 22 && (data[21] == 0x01 || data[21] == 0x02 || data[21] == 0x0A) && ((data[0] & 0x10) == 0x10)) { - // If first disk device id is not set, set it - if (cached_disk_devices.first == -1) { - cached_disk_devices.first = unit_number; - } - // Else if second disk device id is not set, set it and break the loop - else if (cached_disk_devices.second == -1) { - cached_disk_devices.second = unit_number; - break; - } - } - } - } - - cache_valid = true; - return cached_disk_devices; -} +#include +#include +#include +#include + +#include "Listener.h" + +#include "InitRequest.h" +#include "InitResponse.h" +#include "SLIP.h" +#include "TCPConnection.h" +#include "StatusRequest.h" +#include "StatusResponse.h" + +#include "Log.h" +#include "Requestor.h" + +// clang-format off +#ifdef WIN32 + #include + #include + #pragma comment(lib, "ws2_32.lib") + #define CLOSE_SOCKET closesocket + #define SOCKET_ERROR_CODE WSAGetLastError() +#else + #include + #include + #include + #include + #include + #include +#include "StatusRequest.h" +#include "StatusRequest.h" + #define CLOSE_SOCKET close + #define SOCKET_ERROR_CODE errno + #define INVALID_SOCKET -1 + #define SOCKET_ERROR -1 +#endif +// clang-format off + +uint8_t Listener::next_device_id_ = 1; +const std::regex Listener::ipPattern("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); + +Listener& GetSPoverSLIPListener(void) +{ + static Listener listener; + return listener; +} + +Listener::Listener() : is_listening_(false) {} + +void Listener::Initialize(std::string ip_address, const uint16_t port) +{ + ip_address_ = std::move(ip_address); + port_ = port; +} + +bool Listener::get_is_listening() const { return is_listening_; } + +void Listener::insert_connection(uint8_t start_id, uint8_t end_id, const std::shared_ptr &conn) +{ + connection_map_[{start_id, end_id}] = conn; +} + +uint8_t Listener::get_total_device_count() { return next_device_id_ - 1; } + +Listener::~Listener() { stop(); } + +std::thread Listener::create_listener_thread() { return std::thread(&Listener::listener_function, this); } + +void Listener::listener_function() +{ + LogFileOutput("Listener::listener_function - RUNNING\n"); + int server_fd, new_socket; + struct sockaddr_in address; +#ifdef WIN32 + int address_length = sizeof(address); +#else + socklen_t address_length = sizeof(address); +#endif + +#ifdef WIN32 + WSADATA wsa_data; + if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { + LogFileOutput("WSAStartup failed: %d\n", WSAGetLastError()); + } +#endif + + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) + { + LogFileOutput("Listener::listener_function - Socket creation failed\n"); + return; + } + + address.sin_family = AF_INET; + address.sin_port = htons(port_); + inet_pton(AF_INET, ip_address_.c_str(), &(address.sin_addr)); + +#ifdef WIN32 + char opt = 1; +#else + int opt = 1; +#endif + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == SOCKET_ERROR) + { + LogFileOutput("Listener::listener_function - setsockopt failed\n"); + return; + } +#ifdef WIN32 + if (bind(server_fd, reinterpret_cast(&address), sizeof(address)) == SOCKET_ERROR) +#else + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) == SOCKET_ERROR) +#endif + { + LogFileOutput("Listener::listener_function - bind failed\n"); + return; + } + + if (listen(server_fd, 3) < 0) + { + LogFileOutput("Listener::listener_function - listen failed\n"); + return; + } + + while (is_listening_) + { + fd_set sock_set; + FD_ZERO(&sock_set); + FD_SET(server_fd, &sock_set); + + timeval timeout; + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + const int activity = select(server_fd + 1, &sock_set, nullptr, nullptr, &timeout); + + if (activity == SOCKET_ERROR) + { + LogFileOutput("Listener::listener_function - select failed\n"); + is_listening_ = false; + break; + } + + if (activity == 0) + { + // timeout occurred, no client connection. Still need to check is_listening_ + continue; + } + +#ifdef WIN32 + if ((new_socket = accept(server_fd, reinterpret_cast(&address), &address_length)) == INVALID_SOCKET) +#else + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, &address_length)) == INVALID_SOCKET) +#endif + { + LogFileOutput("Listener::listener_function - accept failed\n"); + is_listening_ = false; + break; + } + + create_connection(new_socket); + } + + LogFileOutput("Listener::listener_function - listener closing down\n"); + + CLOSE_SOCKET(server_fd); +} + +// Creates a Connection object, which is how SP device(s) will register itself with our listener. +void Listener::create_connection(unsigned int socket) +{ + // Create a connection, give it some time to settle, else exit without creating listener to connection + const std::shared_ptr conn = std::make_shared(socket); + conn->create_read_channel(); + + const auto start = std::chrono::steady_clock::now(); + // Give the connection a generous 10 seconds to work. + constexpr auto timeout = std::chrono::seconds(10); + + while (!conn->is_connected()) + { + auto now = std::chrono::steady_clock::now(); + if (std::chrono::duration_cast(now - start) > timeout) + { + LogFileOutput("Listener::create_connection() - Failed to establish " + "connection, timed out.\n"); + return; + } + } + + // We need to send an INIT to device 01 for this connection, then 02, ... + // until we get an error back This will determine the number of devices + // attached. + + bool still_scanning = true; + uint8_t unit_id = 1; + + // send init requests to find all the devices on this connection, or we have too many devices. + while (still_scanning && (unit_id + next_device_id_) < 255) + { + LogFileOutput("SmartPortOverSlip listener sending request for unit_id: %d\n", unit_id); + InitRequest request(Requestor::next_request_number(), unit_id); + const auto response = Requestor::send_request(request, conn.get()); + const auto init_response = dynamic_cast(response.get()); + if (init_response == nullptr) + { + LogFileOutput("SmartPortOverSlip listener ERROR, no response data found\n"); + break; + } + still_scanning = init_response->get_status() == 0; + if (still_scanning) + unit_id++; + } + + const auto start_id = next_device_id_; + const auto end_id = static_cast(start_id + unit_id - 1); + next_device_id_ = end_id + 1; + // track the connection and device ranges it reported. Further connections can add to the devices we can target. + LogFileOutput("SmartPortOverSlip listener creating connection for start: %d, end: %d\n", start_id, end_id); + insert_connection(start_id, end_id, conn); +} + +void Listener::start() +{ + is_listening_ = true; + listening_thread_ = std::thread(&Listener::listener_function, this); +} + +void Listener::stop() +{ + LogFileOutput("Listener::stop()\n"); + if (is_listening_) + { + // Stop listener first, otherwise the PC might reboot too fast and be picked up + is_listening_ = false; + LogFileOutput("Listener::stop() ... joining listener until it stops\n"); + listening_thread_.join(); + + LogFileOutput("Listener::stop() - closing %ld connections\n", connection_map_.size()); + for (auto &pair : connection_map_) + { + const auto &connection = pair.second; + connection->set_is_connected(false); + connection->close_connection(); + connection->join(); + } + } + next_device_id_ = 1; + connection_map_.clear(); + +#ifdef WIN32 + WSACleanup(); +#endif + + LogFileOutput("Listener::stop() ... finished\n"); +} + +// Returns the ADJUSTED lower bound of the device id, and connection. +// i.e. the ID that the target thinks the device index is. +// We store (for example) device_ids in applewin with values 1-5 for connection 1, 6-8 for connection 2, but each device things they are 1-5, and 1-3 (not 6-8). +// However the apple side sees 1-8, and so we have to convert 6, 7, 8 into the target's 1, 2, 3 +std::pair> Listener::find_connection_with_device(const uint8_t device_id) const +{ + std::pair> result; + for (const auto &kv : connection_map_) + { + if (device_id >= kv.first.first && device_id <= kv.first.second) + { + result = std::make_pair(device_id - kv.first.first + 1, kv.second); + break; + } + } + return result; +} + +std::vector> Listener::get_all_connections() const +{ + std::vector> connections; + for (const auto &kv : connection_map_) + { + for (uint8_t id = kv.first.first; id <= kv.first.second; ++id) + { + connections.emplace_back(id, kv.second.get()); + } + } + return connections; +} + +std::pair Listener::first_two_disk_devices() const { + if (cache_valid) { + return cached_disk_devices; + } + + cached_disk_devices = {-1, -1}; // Initialize with invalid device ids + + for (uint8_t unit_number = 1; unit_number < next_device_id_; ++unit_number) { + const auto id_and_connection = GetSPoverSLIPListener().find_connection_with_device(unit_number); + if (id_and_connection.second == nullptr) continue; + + // ids from the map need adjusting down to their real ids on the device + + + // DIB request to get information block + const StatusRequest request(Requestor::next_request_number(), unit_number, 3); + + + std::unique_ptr response = Requestor::send_request(request, id_and_connection.second.get()); + + // Cast the Response to a StatusResponse + StatusResponse* statusResponse = dynamic_cast(response.get()); + + if (statusResponse) { + const std::vector& data = statusResponse->get_data(); + + // Check if data size is at least 22 and the device type is a disk, and that the disk status is ONLINE (status[0] bit 4) + if (data.size() >= 22 && (data[21] == 0x01 || data[21] == 0x02 || data[21] == 0x0A) && ((data[0] & 0x10) == 0x10)) { + // If first disk device id is not set, set it + if (cached_disk_devices.first == -1) { + cached_disk_devices.first = unit_number; + } + // Else if second disk device id is not set, set it and break the loop + else if (cached_disk_devices.second == -1) { + cached_disk_devices.second = unit_number; + break; + } + } + } + } + + cache_valid = true; + return cached_disk_devices; +} diff --git a/source/SPoverSLIP/Listener.h b/source/SPoverSLIP/Listener.h index 84d4b0e00..81678d779 100644 --- a/source/SPoverSLIP/Listener.h +++ b/source/SPoverSLIP/Listener.h @@ -1,75 +1,77 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "Connection.h" - -class Listener -{ -public: - // Listener(std::string ip_address, const uint16_t port); - Listener(); - ~Listener(); - - void Initialize(std::string ip_address, const uint16_t port); - - void start(); - void stop(); - - std::thread create_listener_thread(); - bool get_is_listening() const; - - std::pair> find_connection_with_device(const uint8_t device_id) const; - std::vector> get_all_connections() const; - - void insert_connection(uint8_t start_id, uint8_t end_id, const std::shared_ptr &conn); - - static uint8_t get_total_device_count(); - void set_start_on_init(bool should_start) { should_start_ = should_start; } - bool get_start_on_init() { return should_start_; } - std::pair first_two_disk_devices() const; - - // default values for listener - bool default_start_listener = true; - std::string default_listener_address = "0.0.0.0"; - //std::array default_listener_address_array = { "0.0.0.0" }; - uint16_t default_port = 1985; - - std::string get_ip_address() const { return ip_address_; } - std::string check_and_set_ip_address(const std::string& ip_address) { - if (is_valid_ip_address(ip_address)) { - ip_address_ = ip_address; - } else { - ip_address_ = default_listener_address; - } - return ip_address_; - } - - uint16_t get_port() const { return port_; } - void set_port(uint16_t port) { port_ = port; } - - -private: - std::string ip_address_; - uint16_t port_; - std::mutex mtx_; - std::thread listening_thread_; - static uint8_t next_device_id_; - std::map, std::shared_ptr> connection_map_; - mutable std::pair cached_disk_devices; - mutable bool cache_valid = false; - - bool is_listening_; - bool should_start_; - void create_connection(unsigned int socket); - void listener_function(); - bool is_valid_ip_address(const std::string &ipAddress) { return std::regex_match(ipAddress, ipPattern); } - - static const std::regex ipPattern; - -}; +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Connection.h" + +class Listener +{ +public: + // Listener(std::string ip_address, const uint16_t port); + Listener(); + ~Listener(); + + void Initialize(std::string ip_address, const uint16_t port); + + void start(); + void stop(); + + std::thread create_listener_thread(); + bool get_is_listening() const; + + std::pair> find_connection_with_device(const uint8_t device_id) const; + std::vector> get_all_connections() const; + + void insert_connection(uint8_t start_id, uint8_t end_id, const std::shared_ptr &conn); + + static uint8_t get_total_device_count(); + void set_start_on_init(bool should_start) { should_start_ = should_start; } + bool get_start_on_init() { return should_start_; } + std::pair first_two_disk_devices() const; + + // default values for listener + bool default_start_listener = true; + std::string default_listener_address = "0.0.0.0"; + // std::array default_listener_address_array = { "0.0.0.0" }; + uint16_t default_port = 1985; + + std::string get_ip_address() const { return ip_address_; } + std::string check_and_set_ip_address(const std::string &ip_address) + { + if (is_valid_ip_address(ip_address)) + { + ip_address_ = ip_address; + } + else + { + ip_address_ = default_listener_address; + } + return ip_address_; + } + + uint16_t get_port() const { return port_; } + void set_port(uint16_t port) { port_ = port; } + +private: + std::string ip_address_; + uint16_t port_; + std::mutex mtx_; + std::thread listening_thread_; + static uint8_t next_device_id_; + std::map, std::shared_ptr> connection_map_; + mutable std::pair cached_disk_devices; + mutable bool cache_valid = false; + + bool is_listening_; + bool should_start_; + void create_connection(unsigned int socket); + void listener_function(); + bool is_valid_ip_address(const std::string &ipAddress) { return std::regex_match(ipAddress, ipPattern); } + + static const std::regex ipPattern; +}; diff --git a/source/SPoverSLIP/OpenRequest.cpp b/source/SPoverSLIP/OpenRequest.cpp index 8494492d9..c2c93bbe7 100644 --- a/source/SPoverSLIP/OpenRequest.cpp +++ b/source/SPoverSLIP/OpenRequest.cpp @@ -1,26 +1,26 @@ -#include "OpenRequest.h" - -#include "OpenResponse.h" -#include "SmartPortCodes.h" - -OpenRequest::OpenRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_OPEN, sp_unit) {} - -std::vector OpenRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - return request_data; -} - -std::unique_ptr OpenRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize OpenResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} +#include "OpenRequest.h" + +#include "OpenResponse.h" +#include "SmartPortCodes.h" + +OpenRequest::OpenRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_OPEN, sp_unit) {} + +std::vector OpenRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + return request_data; +} + +std::unique_ptr OpenRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize OpenResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} diff --git a/source/SPoverSLIP/OpenRequest.h b/source/SPoverSLIP/OpenRequest.h index fe9e518c5..745b5f29f 100644 --- a/source/SPoverSLIP/OpenRequest.h +++ b/source/SPoverSLIP/OpenRequest.h @@ -1,15 +1,15 @@ -#pragma once - -#include -#include - -#include "Request.h" -#include "Response.h" - -class OpenRequest : public Request -{ -public: - OpenRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; -}; +#pragma once + +#include +#include + +#include "Request.h" +#include "Response.h" + +class OpenRequest : public Request +{ +public: + OpenRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; +}; diff --git a/source/SPoverSLIP/OpenResponse.cpp b/source/SPoverSLIP/OpenResponse.cpp index 4df26e29a..76a631812 100644 --- a/source/SPoverSLIP/OpenResponse.cpp +++ b/source/SPoverSLIP/OpenResponse.cpp @@ -1,11 +1,11 @@ -#include "OpenResponse.h" - -OpenResponse::OpenResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector OpenResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "OpenResponse.h" + +OpenResponse::OpenResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector OpenResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/OpenResponse.h b/source/SPoverSLIP/OpenResponse.h index f7e61be37..d544e1692 100644 --- a/source/SPoverSLIP/OpenResponse.h +++ b/source/SPoverSLIP/OpenResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class OpenResponse : public Response -{ -public: - explicit OpenResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class OpenResponse : public Response +{ +public: + explicit OpenResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/Packet.h b/source/SPoverSLIP/Packet.h index 9a8bc6de3..aa650f6dc 100644 --- a/source/SPoverSLIP/Packet.h +++ b/source/SPoverSLIP/Packet.h @@ -1,12 +1,12 @@ -#pragma once - -#include "SPoSLIP.h" -#include -#include - -class Packet : public SPoSLIP -{ -public: - explicit Packet(const uint8_t request_sequence_number) : SPoSLIP(request_sequence_number) {} - virtual std::vector serialize() const = 0; -}; +#pragma once + +#include "SPoSLIP.h" +#include +#include + +class Packet : public SPoSLIP +{ +public: + explicit Packet(const uint8_t request_sequence_number) : SPoSLIP(request_sequence_number) {} + virtual std::vector serialize() const = 0; +}; diff --git a/source/SPoverSLIP/ReadBlockRequest.cpp b/source/SPoverSLIP/ReadBlockRequest.cpp index 1d5ff223b..a782f02b4 100644 --- a/source/SPoverSLIP/ReadBlockRequest.cpp +++ b/source/SPoverSLIP/ReadBlockRequest.cpp @@ -1,48 +1,42 @@ -#include "ReadBlockRequest.h" - -#include "ReadBlockResponse.h" -#include "SmartPortCodes.h" - -ReadBlockRequest::ReadBlockRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) - : Request(request_sequence_number, SP_READ_BLOCK, sp_unit), block_number_{} -{ -} - -std::vector ReadBlockRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - request_data.insert(request_data.end(), block_number_.begin(), block_number_.end()); - return request_data; -} - -std::unique_ptr ReadBlockRequest::deserialize(const std::vector &data) const -{ - if (data.size() != 514) - { - throw std::runtime_error("Not enough data to deserialize ReadBlockResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - if (response->get_status() == 0) - { - response->set_block_data(data.begin() + 2, data.end()); - } - return response; -} - -const std::array &ReadBlockRequest::get_block_number() const { return block_number_; } - -void ReadBlockRequest::set_block_number_from_ptr(const uint8_t *ptr, const size_t offset) -{ - std::copy_n(ptr + offset, block_number_.size(), block_number_.begin()); -} - -void ReadBlockRequest::set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h) -{ - block_number_[0] = l; - block_number_[1] = m; - block_number_[2] = h; +#include "ReadBlockRequest.h" + +#include "ReadBlockResponse.h" +#include "SmartPortCodes.h" + +ReadBlockRequest::ReadBlockRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_READ_BLOCK, sp_unit), block_number_{} {} + +std::vector ReadBlockRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + request_data.insert(request_data.end(), block_number_.begin(), block_number_.end()); + return request_data; +} + +std::unique_ptr ReadBlockRequest::deserialize(const std::vector &data) const +{ + if (data.size() != 514) + { + throw std::runtime_error("Not enough data to deserialize ReadBlockResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + if (response->get_status() == 0) + { + response->set_block_data(data.begin() + 2, data.end()); + } + return response; +} + +const std::array &ReadBlockRequest::get_block_number() const { return block_number_; } + +void ReadBlockRequest::set_block_number_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, block_number_.size(), block_number_.begin()); } + +void ReadBlockRequest::set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h) +{ + block_number_[0] = l; + block_number_[1] = m; + block_number_[2] = h; } \ No newline at end of file diff --git a/source/SPoverSLIP/ReadBlockRequest.h b/source/SPoverSLIP/ReadBlockRequest.h index 8b4d3e07f..55e130ab3 100644 --- a/source/SPoverSLIP/ReadBlockRequest.h +++ b/source/SPoverSLIP/ReadBlockRequest.h @@ -1,23 +1,23 @@ -#pragma once - -#include -#include -#include -#include - -#include "Request.h" -#include "Response.h" - -class ReadBlockRequest : public Request -{ -public: - ReadBlockRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; - const std::array &get_block_number() const; - void set_block_number_from_ptr(const uint8_t *ptr, size_t offset); - void set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h); - -private: - std::array block_number_; -}; +#pragma once + +#include +#include +#include +#include + +#include "Request.h" +#include "Response.h" + +class ReadBlockRequest : public Request +{ +public: + ReadBlockRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; + const std::array &get_block_number() const; + void set_block_number_from_ptr(const uint8_t *ptr, size_t offset); + void set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h); + +private: + std::array block_number_; +}; diff --git a/source/SPoverSLIP/ReadBlockResponse.cpp b/source/SPoverSLIP/ReadBlockResponse.cpp index 5adb050b1..a487b6a83 100644 --- a/source/SPoverSLIP/ReadBlockResponse.cpp +++ b/source/SPoverSLIP/ReadBlockResponse.cpp @@ -1,22 +1,22 @@ -// ReSharper disable CppPassValueParameterByConstReference -#include - -#include "ReadBlockResponse.h" - -ReadBlockResponse::ReadBlockResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status), block_data_{} {} - -std::vector ReadBlockResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - data.insert(data.end(), block_data_.begin(), block_data_.end()); - return data; -} - -void ReadBlockResponse::set_block_data(std::vector::const_iterator begin, std::vector::const_iterator end) -{ - std::copy(begin, end, block_data_.begin()); // NOLINT(performance-unnecessary-value-param) -} - +// ReSharper disable CppPassValueParameterByConstReference +#include + +#include "ReadBlockResponse.h" + +ReadBlockResponse::ReadBlockResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status), block_data_{} {} + +std::vector ReadBlockResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + data.insert(data.end(), block_data_.begin(), block_data_.end()); + return data; +} + +void ReadBlockResponse::set_block_data(std::vector::const_iterator begin, std::vector::const_iterator end) +{ + std::copy(begin, end, block_data_.begin()); // NOLINT(performance-unnecessary-value-param) +} + const std::array &ReadBlockResponse::get_block_data() const { return block_data_; } \ No newline at end of file diff --git a/source/SPoverSLIP/ReadBlockResponse.h b/source/SPoverSLIP/ReadBlockResponse.h index ac8c9819f..1fe689018 100644 --- a/source/SPoverSLIP/ReadBlockResponse.h +++ b/source/SPoverSLIP/ReadBlockResponse.h @@ -1,16 +1,16 @@ -#pragma once -#include "Response.h" -#include - -class ReadBlockResponse : public Response -{ -public: - explicit ReadBlockResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; - - void set_block_data(std::vector::const_iterator begin, std::vector::const_iterator end); - const std::array &get_block_data() const; - -private: - std::array block_data_; -}; +#pragma once +#include "Response.h" +#include + +class ReadBlockResponse : public Response +{ +public: + explicit ReadBlockResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; + + void set_block_data(std::vector::const_iterator begin, std::vector::const_iterator end); + const std::array &get_block_data() const; + +private: + std::array block_data_; +}; diff --git a/source/SPoverSLIP/ReadRequest.cpp b/source/SPoverSLIP/ReadRequest.cpp index cf960567e..a29474c30 100644 --- a/source/SPoverSLIP/ReadRequest.cpp +++ b/source/SPoverSLIP/ReadRequest.cpp @@ -1,43 +1,40 @@ -#include "ReadRequest.h" - -#include "ReadResponse.h" -#include "SmartPortCodes.h" - -ReadRequest::ReadRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) - : Request(request_sequence_number, SP_READ, sp_unit), byte_count_(), address_() -{ -} - -std::vector ReadRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - request_data.insert(request_data.end(), get_byte_count().begin(), get_byte_count().end()); - request_data.insert(request_data.end(), get_address().begin(), get_address().end()); - return request_data; -} - -std::unique_ptr ReadRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 3) - { - throw std::runtime_error("Not enough data to deserialize ReadResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - if (response->get_status() == 0) - { - response->set_data(data.begin() + 2, data.end()); - } - return response; -} - -const std::array &ReadRequest::get_byte_count() const { return byte_count_; } - -const std::array &ReadRequest::get_address() const { return address_; } - -void ReadRequest::set_byte_count_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, byte_count_.size(), byte_count_.begin()); } - -void ReadRequest::set_address_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, address_.size(), address_.begin()); } +#include "ReadRequest.h" + +#include "ReadResponse.h" +#include "SmartPortCodes.h" + +ReadRequest::ReadRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_READ, sp_unit), byte_count_(), address_() {} + +std::vector ReadRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + request_data.insert(request_data.end(), get_byte_count().begin(), get_byte_count().end()); + request_data.insert(request_data.end(), get_address().begin(), get_address().end()); + return request_data; +} + +std::unique_ptr ReadRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 3) + { + throw std::runtime_error("Not enough data to deserialize ReadResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + if (response->get_status() == 0) + { + response->set_data(data.begin() + 2, data.end()); + } + return response; +} + +const std::array &ReadRequest::get_byte_count() const { return byte_count_; } + +const std::array &ReadRequest::get_address() const { return address_; } + +void ReadRequest::set_byte_count_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, byte_count_.size(), byte_count_.begin()); } + +void ReadRequest::set_address_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, address_.size(), address_.begin()); } diff --git a/source/SPoverSLIP/ReadRequest.h b/source/SPoverSLIP/ReadRequest.h index 0606a860a..8396c1393 100644 --- a/source/SPoverSLIP/ReadRequest.h +++ b/source/SPoverSLIP/ReadRequest.h @@ -1,27 +1,27 @@ -#pragma once - -#include -#include -#include -#include - -#include "Request.h" -#include "Response.h" - -class ReadRequest : public Request -{ -public: - ReadRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; - - const std::array &get_byte_count() const; - void set_byte_count_from_ptr(const uint8_t *ptr, size_t offset); - - const std::array &get_address() const; - void set_address_from_ptr(const uint8_t *ptr, size_t offset); - -private: - std::array byte_count_; - std::array address_; -}; +#pragma once + +#include +#include +#include +#include + +#include "Request.h" +#include "Response.h" + +class ReadRequest : public Request +{ +public: + ReadRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; + + const std::array &get_byte_count() const; + void set_byte_count_from_ptr(const uint8_t *ptr, size_t offset); + + const std::array &get_address() const; + void set_address_from_ptr(const uint8_t *ptr, size_t offset); + +private: + std::array byte_count_; + std::array address_; +}; diff --git a/source/SPoverSLIP/ReadResponse.cpp b/source/SPoverSLIP/ReadResponse.cpp index e0698d485..635f92102 100644 --- a/source/SPoverSLIP/ReadResponse.cpp +++ b/source/SPoverSLIP/ReadResponse.cpp @@ -1,21 +1,21 @@ -// ReSharper disable CppPassValueParameterByConstReference -#include "ReadResponse.h" -#include - -ReadResponse::ReadResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector ReadResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - data.insert(data.end(), get_data().begin(), get_data().end()); - return data; -} - -void ReadResponse::set_data(const std::vector::const_iterator &begin, const std::vector::const_iterator &end) -{ - const size_t new_size = std::distance(begin, end); - data_.resize(new_size); - std::copy(begin, end, data_.begin()); // NOLINT(performance-unnecessary-value-param) -} +// ReSharper disable CppPassValueParameterByConstReference +#include "ReadResponse.h" +#include + +ReadResponse::ReadResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector ReadResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + data.insert(data.end(), get_data().begin(), get_data().end()); + return data; +} + +void ReadResponse::set_data(const std::vector::const_iterator &begin, const std::vector::const_iterator &end) +{ + const size_t new_size = std::distance(begin, end); + data_.resize(new_size); + std::copy(begin, end, data_.begin()); // NOLINT(performance-unnecessary-value-param) +} diff --git a/source/SPoverSLIP/ReadResponse.h b/source/SPoverSLIP/ReadResponse.h index 017389d1b..4fb00429c 100644 --- a/source/SPoverSLIP/ReadResponse.h +++ b/source/SPoverSLIP/ReadResponse.h @@ -1,15 +1,15 @@ -#pragma once -#include "Response.h" - -class ReadResponse : public Response -{ -public: - explicit ReadResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; - - const std::vector &get_data() const { return data_; } - void set_data(const std::vector::const_iterator &begin, const std::vector::const_iterator &end); - -private: - std::vector data_; -}; +#pragma once +#include "Response.h" + +class ReadResponse : public Response +{ +public: + explicit ReadResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; + + const std::vector &get_data() const { return data_; } + void set_data(const std::vector::const_iterator &begin, const std::vector::const_iterator &end); + +private: + std::vector data_; +}; diff --git a/source/SPoverSLIP/Request.cpp b/source/SPoverSLIP/Request.cpp index 9a890b6e1..de0f38eb9 100644 --- a/source/SPoverSLIP/Request.cpp +++ b/source/SPoverSLIP/Request.cpp @@ -1,11 +1,8 @@ - -#include "Request.h" - -Request::Request(const uint8_t request_sequence_number, const uint8_t command_number, const uint8_t sp_unit) - : Packet(request_sequence_number), command_number_(command_number), sp_unit_(sp_unit) -{ -} - -uint8_t Request::get_command_number() const { return command_number_; } - -uint8_t Request::get_sp_unit() const { return sp_unit_; } + +#include "Request.h" + +Request::Request(const uint8_t request_sequence_number, const uint8_t command_number, const uint8_t sp_unit) : Packet(request_sequence_number), command_number_(command_number), sp_unit_(sp_unit) {} + +uint8_t Request::get_command_number() const { return command_number_; } + +uint8_t Request::get_sp_unit() const { return sp_unit_; } diff --git a/source/SPoverSLIP/Request.h b/source/SPoverSLIP/Request.h index e0ce04e33..688ed7d54 100644 --- a/source/SPoverSLIP/Request.h +++ b/source/SPoverSLIP/Request.h @@ -1,25 +1,25 @@ -#pragma once - -#include "Packet.h" -#include -#include -#include -#include - -// Forward reference to break circular dependency -class Response; - -class Request : public Packet -{ -public: - Request(uint8_t request_sequence_number, uint8_t command_number, uint8_t sp_unit); - std::vector serialize() const override = 0; - virtual std::unique_ptr deserialize(const std::vector &data) const = 0; - - uint8_t get_command_number() const; - uint8_t get_sp_unit() const; - -private: - uint8_t command_number_ = 0; - uint8_t sp_unit_ = 0; -}; +#pragma once + +#include "Packet.h" +#include +#include +#include +#include + +// Forward reference to break circular dependency +class Response; + +class Request : public Packet +{ +public: + Request(uint8_t request_sequence_number, uint8_t command_number, uint8_t sp_unit); + std::vector serialize() const override = 0; + virtual std::unique_ptr deserialize(const std::vector &data) const = 0; + + uint8_t get_command_number() const; + uint8_t get_sp_unit() const; + +private: + uint8_t command_number_ = 0; + uint8_t sp_unit_ = 0; +}; diff --git a/source/SPoverSLIP/Requestor.cpp b/source/SPoverSLIP/Requestor.cpp index 4dfc23a0d..826469bc0 100644 --- a/source/SPoverSLIP/Requestor.cpp +++ b/source/SPoverSLIP/Requestor.cpp @@ -1,36 +1,35 @@ - -#include "Requestor.h" -#include "Listener.h" -#include - -uint8_t Requestor::request_number_ = 0; - -Requestor::Requestor() = default; - -std::unique_ptr Requestor::send_request(const Request &request, Connection *connection) -{ - // Send the serialized request - connection->send_data(request.serialize()); - - std::vector response_data; - try - { - response_data = connection->wait_for_response(request.get_request_sequence_number(), std::chrono::seconds(5)); - } - catch (const std::runtime_error &e) - { - std::cerr << "Requestor::send_request did not get response, error = " << e.what() << std::endl; - return nullptr; - } - - // Deserialize the response data into a Response object. - // Each Request type (e.g. StatusRequest) is able to deserialize into its twin Response (e.g. StatusResponse). - return request.deserialize(response_data); -} - -uint8_t Requestor::next_request_number() -{ - const uint8_t current_number = request_number_; - request_number_ = (request_number_ + 1) % 256; - return current_number; + +#include "Requestor.h" +#include "Listener.h" +#include + +uint8_t Requestor::request_number_ = 0; + +Requestor::Requestor() = default; + +std::unique_ptr Requestor::send_request(const Request &request, Connection *connection) +{ + // Send the serialized request + connection->send_data(request.serialize()); + + std::vector response_data; + try + { + response_data = connection->wait_for_response(request.get_request_sequence_number(), std::chrono::seconds(5)); + } catch (const std::runtime_error &e) + { + std::cerr << "Requestor::send_request did not get response, error = " << e.what() << std::endl; + return nullptr; + } + + // Deserialize the response data into a Response object. + // Each Request type (e.g. StatusRequest) is able to deserialize into its twin Response (e.g. StatusResponse). + return request.deserialize(response_data); +} + +uint8_t Requestor::next_request_number() +{ + const uint8_t current_number = request_number_; + request_number_ = (request_number_ + 1) % 256; + return current_number; } \ No newline at end of file diff --git a/source/SPoverSLIP/Requestor.h b/source/SPoverSLIP/Requestor.h index ed4461c73..9a6453864 100644 --- a/source/SPoverSLIP/Requestor.h +++ b/source/SPoverSLIP/Requestor.h @@ -1,19 +1,19 @@ -#pragma once - -#include "Connection.h" -#include "Request.h" -#include "Response.h" -#include - -class Requestor -{ -public: - Requestor(); - - // The Request's deserialize function will always return a Response, e.g. StatusRequest -> StatusResponse - static std::unique_ptr send_request(const Request &request, Connection *connection); - static uint8_t next_request_number(); - -private: - static uint8_t request_number_; -}; +#pragma once + +#include "Connection.h" +#include "Request.h" +#include "Response.h" +#include + +class Requestor +{ +public: + Requestor(); + + // The Request's deserialize function will always return a Response, e.g. StatusRequest -> StatusResponse + static std::unique_ptr send_request(const Request &request, Connection *connection); + static uint8_t next_request_number(); + +private: + static uint8_t request_number_; +}; diff --git a/source/SPoverSLIP/ResetRequest.cpp b/source/SPoverSLIP/ResetRequest.cpp index 9f22b0f47..11cbf6e67 100644 --- a/source/SPoverSLIP/ResetRequest.cpp +++ b/source/SPoverSLIP/ResetRequest.cpp @@ -1,26 +1,26 @@ -#include "ResetRequest.h" - -#include "ResetResponse.h" -#include "SmartPortCodes.h" - -ResetRequest::ResetRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_RESET, sp_unit) {} - -std::vector ResetRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - return request_data; -} - -std::unique_ptr ResetRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize ResetResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} +#include "ResetRequest.h" + +#include "ResetResponse.h" +#include "SmartPortCodes.h" + +ResetRequest::ResetRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_RESET, sp_unit) {} + +std::vector ResetRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + return request_data; +} + +std::unique_ptr ResetRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize ResetResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} diff --git a/source/SPoverSLIP/ResetRequest.h b/source/SPoverSLIP/ResetRequest.h index d0d0d9dff..6bb2151d8 100644 --- a/source/SPoverSLIP/ResetRequest.h +++ b/source/SPoverSLIP/ResetRequest.h @@ -1,15 +1,15 @@ -#pragma once - -#include -#include - -#include "Request.h" -#include "Response.h" - -class ResetRequest : public Request -{ -public: - ResetRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; -}; +#pragma once + +#include +#include + +#include "Request.h" +#include "Response.h" + +class ResetRequest : public Request +{ +public: + ResetRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; +}; diff --git a/source/SPoverSLIP/ResetResponse.cpp b/source/SPoverSLIP/ResetResponse.cpp index 2feef5d37..ccc7e39d4 100644 --- a/source/SPoverSLIP/ResetResponse.cpp +++ b/source/SPoverSLIP/ResetResponse.cpp @@ -1,11 +1,11 @@ -#include "ResetResponse.h" - -ResetResponse::ResetResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector ResetResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "ResetResponse.h" + +ResetResponse::ResetResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector ResetResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/ResetResponse.h b/source/SPoverSLIP/ResetResponse.h index a99cb9d89..a11dae72f 100644 --- a/source/SPoverSLIP/ResetResponse.h +++ b/source/SPoverSLIP/ResetResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class ResetResponse : public Response -{ -public: - explicit ResetResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class ResetResponse : public Response +{ +public: + explicit ResetResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/Response.cpp b/source/SPoverSLIP/Response.cpp index 344a227bb..d212ae0f6 100644 --- a/source/SPoverSLIP/Response.cpp +++ b/source/SPoverSLIP/Response.cpp @@ -1,6 +1,6 @@ - -#include "Response.h" - -Response::Response(const uint8_t request_sequence_number, const uint8_t status) : Packet(request_sequence_number), status_(status) {} - -uint8_t Response::get_status() const { return status_; } + +#include "Response.h" + +Response::Response(const uint8_t request_sequence_number, const uint8_t status) : Packet(request_sequence_number), status_(status) {} + +uint8_t Response::get_status() const { return status_; } diff --git a/source/SPoverSLIP/Response.h b/source/SPoverSLIP/Response.h index d532fdb14..a87ad1ecf 100644 --- a/source/SPoverSLIP/Response.h +++ b/source/SPoverSLIP/Response.h @@ -1,17 +1,17 @@ -#pragma once - -#include "Packet.h" -#include -#include - -class Response : public Packet -{ -public: - Response(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override = 0; - - uint8_t get_status() const; - -private: - uint8_t status_ = 0; +#pragma once + +#include "Packet.h" +#include +#include + +class Response : public Packet +{ +public: + Response(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override = 0; + + uint8_t get_status() const; + +private: + uint8_t status_ = 0; }; \ No newline at end of file diff --git a/source/SPoverSLIP/SLIP.cpp b/source/SPoverSLIP/SLIP.cpp index 20b5d3429..0781729bf 100644 --- a/source/SPoverSLIP/SLIP.cpp +++ b/source/SPoverSLIP/SLIP.cpp @@ -1,144 +1,144 @@ - -#include "SLIP.h" -#include - -std::vector SLIP::encode(const std::vector &data) -{ - std::vector encoded_data; - - // start with SLIP_END - encoded_data.push_back(SLIP_END); - - // Escape any SLIP special characters in the packet data - for (uint8_t byte : data) - { - if (byte == SLIP_END || byte == SLIP_ESC) - { - encoded_data.push_back(SLIP_ESC); - encoded_data.push_back(byte == SLIP_END ? SLIP_ESC_END : SLIP_ESC_ESC); - } - else - { - encoded_data.push_back(byte); - } - } - - // Add the SLIP END byte to the end of the encoded data - encoded_data.push_back(SLIP_END); - - return encoded_data; -} - -std::vector SLIP::decode(const std::vector &data) -{ - std::vector decoded_data; - auto bytes_read = data.size(); - - size_t i = 0; - while (i < bytes_read) - { - if (data[i] == SLIP_END) - { - // Start of a SLIP packet - i++; - - // Decode the SLIP packet data - while (i < bytes_read && data[i] != SLIP_END) - { - if (data[i] == SLIP_ESC) - { - // Escaped byte - i++; - - if (data[i] == SLIP_ESC_END) - { - // Escaped END byte - decoded_data.push_back(SLIP_END); - } - else if (data[i] == SLIP_ESC_ESC) - { - // Escaped ESC byte - decoded_data.push_back(SLIP_ESC); - } - else - { - // Invalid escape sequence - return std::vector(); - } - } - else - { - // Non-escaped byte - decoded_data.push_back(data[i]); - } - - i++; - } - - // Check for end of packet - if (i == bytes_read || data[i] != SLIP_END) - { - // Incomplete SLIP packet - return std::vector(); - } - } - else - { - // Invalid SLIP packet - return std::vector(); - } - - i++; - } - - return decoded_data; -} - -// This breaks up a vector of data into a list of decoded vectors of serialized objects. -// The returned data is already "SLIP::decode"d -std::vector> SLIP::split_into_packets(const uint8_t *data, size_t bytes_read) -{ - // The list of decoded SLIP packets - std::vector> decoded_packets; - - enum class State - { - NotParsing, - Parsing - } state = State::NotParsing; - - // Iterate over the data and find the SLIP packet boundaries - size_t i = 0; - const uint8_t *packet_start = nullptr; // Keep track of where the packet starts - while (i < bytes_read) - { - switch (state) - { - case State::NotParsing: - // If we are not yet parsing and see a SLIP_END byte (which also marks start), start parsing a new SLIP packet - if (data[i] == SLIP_END) - { - state = State::Parsing; - packet_start = data + i; // Mark the start of the packet - } - break; - case State::Parsing: - // If we see another SLIP_END byte, we have reached the end of the SLIP packet - if (data[i] == SLIP_END) - { - // Extract the SLIP packet data - std::vector slip_packet_data(packet_start, data + i + 1); // Include all bytes in the packet - - // Add the data to the list of SLIP decoded packets - decoded_packets.push_back(SLIP::decode(slip_packet_data)); - - // Transition back to the NotParsing state - state = State::NotParsing; - } - break; - } - i++; - } - - return decoded_packets; -} + +#include "SLIP.h" +#include + +std::vector SLIP::encode(const std::vector &data) +{ + std::vector encoded_data; + + // start with SLIP_END + encoded_data.push_back(SLIP_END); + + // Escape any SLIP special characters in the packet data + for (uint8_t byte : data) + { + if (byte == SLIP_END || byte == SLIP_ESC) + { + encoded_data.push_back(SLIP_ESC); + encoded_data.push_back(byte == SLIP_END ? SLIP_ESC_END : SLIP_ESC_ESC); + } + else + { + encoded_data.push_back(byte); + } + } + + // Add the SLIP END byte to the end of the encoded data + encoded_data.push_back(SLIP_END); + + return encoded_data; +} + +std::vector SLIP::decode(const std::vector &data) +{ + std::vector decoded_data; + auto bytes_read = data.size(); + + size_t i = 0; + while (i < bytes_read) + { + if (data[i] == SLIP_END) + { + // Start of a SLIP packet + i++; + + // Decode the SLIP packet data + while (i < bytes_read && data[i] != SLIP_END) + { + if (data[i] == SLIP_ESC) + { + // Escaped byte + i++; + + if (data[i] == SLIP_ESC_END) + { + // Escaped END byte + decoded_data.push_back(SLIP_END); + } + else if (data[i] == SLIP_ESC_ESC) + { + // Escaped ESC byte + decoded_data.push_back(SLIP_ESC); + } + else + { + // Invalid escape sequence + return std::vector(); + } + } + else + { + // Non-escaped byte + decoded_data.push_back(data[i]); + } + + i++; + } + + // Check for end of packet + if (i == bytes_read || data[i] != SLIP_END) + { + // Incomplete SLIP packet + return std::vector(); + } + } + else + { + // Invalid SLIP packet + return std::vector(); + } + + i++; + } + + return decoded_data; +} + +// This breaks up a vector of data into a list of decoded vectors of serialized objects. +// The returned data is already "SLIP::decode"d +std::vector> SLIP::split_into_packets(const uint8_t *data, size_t bytes_read) +{ + // The list of decoded SLIP packets + std::vector> decoded_packets; + + enum class State + { + NotParsing, + Parsing + } state = State::NotParsing; + + // Iterate over the data and find the SLIP packet boundaries + size_t i = 0; + const uint8_t *packet_start = nullptr; // Keep track of where the packet starts + while (i < bytes_read) + { + switch (state) + { + case State::NotParsing: + // If we are not yet parsing and see a SLIP_END byte (which also marks start), start parsing a new SLIP packet + if (data[i] == SLIP_END) + { + state = State::Parsing; + packet_start = data + i; // Mark the start of the packet + } + break; + case State::Parsing: + // If we see another SLIP_END byte, we have reached the end of the SLIP packet + if (data[i] == SLIP_END) + { + // Extract the SLIP packet data + std::vector slip_packet_data(packet_start, data + i + 1); // Include all bytes in the packet + + // Add the data to the list of SLIP decoded packets + decoded_packets.push_back(SLIP::decode(slip_packet_data)); + + // Transition back to the NotParsing state + state = State::NotParsing; + } + break; + } + i++; + } + + return decoded_packets; +} diff --git a/source/SPoverSLIP/SLIP.h b/source/SPoverSLIP/SLIP.h index 60fb547d8..aaff7bd24 100644 --- a/source/SPoverSLIP/SLIP.h +++ b/source/SPoverSLIP/SLIP.h @@ -1,19 +1,19 @@ -#pragma once - -#include -#include -#include - -#define SLIP_END 0300 /* indicates end of packet */ -#define SLIP_ESC 0333 /* indicates byte stuffing */ -#define SLIP_ESC_END 0334 /* ESC ESC_END means END data byte */ -#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */ - -class SLIP -{ -public: - // these encode and decode exactly one SLIP frame, and expect it to be sane. - static std::vector encode(const std::vector &data); - static std::vector decode(const std::vector &data); - static std::vector> split_into_packets(const uint8_t *data, size_t bytes_read); -}; +#pragma once + +#include +#include +#include + +#define SLIP_END 0300 /* indicates end of packet */ +#define SLIP_ESC 0333 /* indicates byte stuffing */ +#define SLIP_ESC_END 0334 /* ESC ESC_END means END data byte */ +#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */ + +class SLIP +{ +public: + // these encode and decode exactly one SLIP frame, and expect it to be sane. + static std::vector encode(const std::vector &data); + static std::vector decode(const std::vector &data); + static std::vector> split_into_packets(const uint8_t *data, size_t bytes_read); +}; diff --git a/source/SPoverSLIP/SPoSLIP.h b/source/SPoverSLIP/SPoSLIP.h index 061d8ad66..db8cf8dd8 100644 --- a/source/SPoverSLIP/SPoSLIP.h +++ b/source/SPoverSLIP/SPoSLIP.h @@ -1,15 +1,15 @@ -#pragma once - -#include - -class SPoSLIP -{ -private: - uint8_t request_sequence_number_ = 0; - -public: - explicit SPoSLIP(const uint8_t request_sequence_number) : request_sequence_number_(request_sequence_number) {} - virtual ~SPoSLIP() = default; - - uint8_t get_request_sequence_number() const { return request_sequence_number_; } -}; +#pragma once + +#include + +class SPoSLIP +{ +private: + uint8_t request_sequence_number_ = 0; + +public: + explicit SPoSLIP(const uint8_t request_sequence_number) : request_sequence_number_(request_sequence_number) {} + virtual ~SPoSLIP() = default; + + uint8_t get_request_sequence_number() const { return request_sequence_number_; } +}; diff --git a/source/SPoverSLIP/SmartPortCodes.h b/source/SPoverSLIP/SmartPortCodes.h index 68ba5d51c..bb328b689 100644 --- a/source/SPoverSLIP/SmartPortCodes.h +++ b/source/SPoverSLIP/SmartPortCodes.h @@ -1,16 +1,16 @@ -#pragma once - -enum -{ - SP_STATUS = 0, - SP_READ_BLOCK = 1, - SP_WRITE_BLOCK = 2, - SP_FORMAT = 3, - SP_CONTROL = 4, - SP_INIT = 5, - SP_OPEN = 6, - SP_CLOSE = 7, - SP_READ = 8, - SP_WRITE = 9, - SP_RESET = 10 -}; +#pragma once + +enum +{ + SP_STATUS = 0, + SP_READ_BLOCK = 1, + SP_WRITE_BLOCK = 2, + SP_FORMAT = 3, + SP_CONTROL = 4, + SP_INIT = 5, + SP_OPEN = 6, + SP_CLOSE = 7, + SP_READ = 8, + SP_WRITE = 9, + SP_RESET = 10 +}; diff --git a/source/SPoverSLIP/StatusRequest.cpp b/source/SPoverSLIP/StatusRequest.cpp index 6cc600966..022109ced 100644 --- a/source/SPoverSLIP/StatusRequest.cpp +++ b/source/SPoverSLIP/StatusRequest.cpp @@ -1,42 +1,41 @@ - -#include - -#include "SmartPortCodes.h" -#include "StatusRequest.h" -#include "StatusResponse.h" - -StatusRequest::StatusRequest(const uint8_t request_sequence_number, const uint8_t sp_unit, const uint8_t status_code) - : Request(request_sequence_number, SP_STATUS, sp_unit), status_code_(status_code) -{ -} - -std::vector StatusRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - request_data.push_back(this->get_status_code()); - - return request_data; -} - -std::unique_ptr StatusRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize StatusResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - - if (response->get_status() == 0 && data.size() > 2) - { - for (size_t i = 2; i < data.size(); ++i) - { - response->add_data(data[i]); - } - } - - return response; -} + +#include + +#include "SmartPortCodes.h" +#include "StatusRequest.h" +#include "StatusResponse.h" + +StatusRequest::StatusRequest(const uint8_t request_sequence_number, const uint8_t sp_unit, const uint8_t status_code) : Request(request_sequence_number, SP_STATUS, sp_unit), status_code_(status_code) +{ +} + +std::vector StatusRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + request_data.push_back(this->get_status_code()); + + return request_data; +} + +std::unique_ptr StatusRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize StatusResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + + if (response->get_status() == 0 && data.size() > 2) + { + for (size_t i = 2; i < data.size(); ++i) + { + response->add_data(data[i]); + } + } + + return response; +} diff --git a/source/SPoverSLIP/StatusRequest.h b/source/SPoverSLIP/StatusRequest.h index 00c34df76..18a86098e 100644 --- a/source/SPoverSLIP/StatusRequest.h +++ b/source/SPoverSLIP/StatusRequest.h @@ -1,19 +1,19 @@ -#pragma once - -#include "Request.h" -#include "Response.h" -#include -#include - -class StatusRequest : public Request -{ -public: - StatusRequest(uint8_t request_sequence_number, uint8_t sp_unit, uint8_t status_code); - virtual std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; - - uint8_t get_status_code() const { return status_code_; } - -private: - uint8_t status_code_; -}; +#pragma once + +#include "Request.h" +#include "Response.h" +#include +#include + +class StatusRequest : public Request +{ +public: + StatusRequest(uint8_t request_sequence_number, uint8_t sp_unit, uint8_t status_code); + virtual std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; + + uint8_t get_status_code() const { return status_code_; } + +private: + uint8_t status_code_; +}; diff --git a/source/SPoverSLIP/StatusResponse.cpp b/source/SPoverSLIP/StatusResponse.cpp index f07d06d6b..d4a003bd9 100644 --- a/source/SPoverSLIP/StatusResponse.cpp +++ b/source/SPoverSLIP/StatusResponse.cpp @@ -1,24 +1,24 @@ - -#include "StatusResponse.h" -#include "StatusRequest.h" - -StatusResponse::StatusResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -const std::vector &StatusResponse::get_data() const { return data_; } - -void StatusResponse::add_data(const uint8_t d) { data_.push_back(d); } - -void StatusResponse::set_data(const std::vector &data) { data_ = data; } - -std::vector StatusResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - - for (uint8_t b : get_data()) - { - data.push_back(b); - } - return data; -} + +#include "StatusResponse.h" +#include "StatusRequest.h" + +StatusResponse::StatusResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +const std::vector &StatusResponse::get_data() const { return data_; } + +void StatusResponse::add_data(const uint8_t d) { data_.push_back(d); } + +void StatusResponse::set_data(const std::vector &data) { data_ = data; } + +std::vector StatusResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + + for (uint8_t b : get_data()) + { + data.push_back(b); + } + return data; +} diff --git a/source/SPoverSLIP/StatusResponse.h b/source/SPoverSLIP/StatusResponse.h index 25d46be84..2e88bb559 100644 --- a/source/SPoverSLIP/StatusResponse.h +++ b/source/SPoverSLIP/StatusResponse.h @@ -1,19 +1,19 @@ -#pragma once - -#include "Response.h" -#include -#include - -class StatusResponse : public Response -{ -public: - explicit StatusResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; - - const std::vector &get_data() const; - void add_data(uint8_t d); - void set_data(const std::vector &data); - -private: - std::vector data_; -}; +#pragma once + +#include "Response.h" +#include +#include + +class StatusResponse : public Response +{ +public: + explicit StatusResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; + + const std::vector &get_data() const; + void add_data(uint8_t d); + void set_data(const std::vector &data); + +private: + std::vector data_; +}; diff --git a/source/SPoverSLIP/TCPConnection.cpp b/source/SPoverSLIP/TCPConnection.cpp index 93cf5e9dc..939032275 100644 --- a/source/SPoverSLIP/TCPConnection.cpp +++ b/source/SPoverSLIP/TCPConnection.cpp @@ -1,136 +1,136 @@ -#include "TCPConnection.h" - -#include -#include -#include - -// clang-format off -#ifdef WIN32 - #include - #pragma comment(lib, "ws2_32.lib") - #define CLOSE_SOCKET closesocket - #define SHUTDOWN_SOCKET(s) shutdown(s, SD_SEND) - #define SOCKET_ERROR_CODE WSAGetLastError() -#else - #include - #include - #include - #define CLOSE_SOCKET close - #define SHUTDOWN_SOCKET(s) shutdown(s, SHUT_WR) - #define SOCKET_ERROR_CODE errno - #define INVALID_SOCKET -1 - #define SOCKET_ERROR -1 -#endif -// clang-format off - -#include "Log.h" -#include "SLIP.h" - -void TCPConnection::close_connection() -{ - if (socket_ != 0) - { - LogFileOutput("Closing TCPConnection socket\n"); - if (SHUTDOWN_SOCKET(socket_) == SOCKET_ERROR) - { - LogFileOutput("Error shutting down socket, error code: %d\n", SOCKET_ERROR_CODE); - } - if (CLOSE_SOCKET(socket_) == SOCKET_ERROR) - { - LogFileOutput("Error closing socket, error code: %d\n", SOCKET_ERROR_CODE); - } - } - socket_ = 0; -} - -void TCPConnection::send_data(const std::vector &data) -{ - if (data.empty()) - { - return; - } - - const auto slip_data = SLIP::encode(data); - send(socket_, reinterpret_cast(slip_data.data()), slip_data.size(), 0); -} - -void TCPConnection::create_read_channel() -{ - // Start a new thread to listen for incoming data - reading_thread_ = std::thread( - [self = shared_from_this()]() - { - std::vector complete_data; - std::vector buffer(1024); - bool is_initialising = true; - - // Set a timeout on the socket - timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - setsockopt(self->get_socket(), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeout), sizeof(timeout)); - - while (self->is_connected() || is_initialising) - { - int valread = 0; - do - { - if (is_initialising) - { - is_initialising = false; - LogFileOutput("SmartPortOverSlip TCPConnection: connected\n"); - self->set_is_connected(true); - } - - valread = recv(self->get_socket(), reinterpret_cast(buffer.data()), static_cast(buffer.size()), 0); - const int errsv = errno; - if (valread < 0) - { - // timeout is fine, just reloop. - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == 0) - { - continue; - } - // otherwise it was a genuine error. - LogFileOutput("Error in read thread for connection, errno: %d = %s\n", errsv, strerror(errsv)); - self->set_is_connected(false); - } - if (valread == 0) - { - // disconnected, close connection, should remove it too: TODO - LogFileOutput("TCPConnection: recv == 0, disconnecting\n"); - self->set_is_connected(false); - } - if (valread > 0) - { - // LogFileOutput("SmartPortOverSlip TCPConnection, inserting data, valread: %d\n", valread); - complete_data.insert(complete_data.end(), buffer.begin(), buffer.begin() + valread); - } - } while (valread == 1024); - - if (!complete_data.empty()) - { - std::vector> decoded_packets = - SLIP::split_into_packets(complete_data.data(), complete_data.size()); - // LogFileOutput("SmartPortOverSlip TCPConnection, packets decoded: %d\n", decoded_packets.size()); - - if (!decoded_packets.empty()) - { - for (const auto &packet : decoded_packets) - { - if (!packet.empty()) - { - { - std::lock_guard lock(self->data_mutex_); - self->data_map_[packet[0]] = packet; - } - self->data_cv_.notify_all(); - } - } - } - complete_data.clear(); - } - } - LogFileOutput("TCPConnection::create_read_channel - thread is EXITING\n"); - }); -} +#include "TCPConnection.h" + +#include +#include +#include + +// clang-format off +#ifdef WIN32 + #include + #pragma comment(lib, "ws2_32.lib") + #define CLOSE_SOCKET closesocket + #define SHUTDOWN_SOCKET(s) shutdown(s, SD_SEND) + #define SOCKET_ERROR_CODE WSAGetLastError() +#else + #include + #include + #include + #define CLOSE_SOCKET close + #define SHUTDOWN_SOCKET(s) shutdown(s, SHUT_WR) + #define SOCKET_ERROR_CODE errno + #define INVALID_SOCKET -1 + #define SOCKET_ERROR -1 +#endif +// clang-format off + +#include "Log.h" +#include "SLIP.h" + +void TCPConnection::close_connection() +{ + if (socket_ != 0) + { + LogFileOutput("Closing TCPConnection socket\n"); + if (SHUTDOWN_SOCKET(socket_) == SOCKET_ERROR) + { + LogFileOutput("Error shutting down socket, error code: %d\n", SOCKET_ERROR_CODE); + } + if (CLOSE_SOCKET(socket_) == SOCKET_ERROR) + { + LogFileOutput("Error closing socket, error code: %d\n", SOCKET_ERROR_CODE); + } + } + socket_ = 0; +} + +void TCPConnection::send_data(const std::vector &data) +{ + if (data.empty()) + { + return; + } + + const auto slip_data = SLIP::encode(data); + send(socket_, reinterpret_cast(slip_data.data()), slip_data.size(), 0); +} + +void TCPConnection::create_read_channel() +{ + // Start a new thread to listen for incoming data + reading_thread_ = std::thread( + [self = shared_from_this()]() + { + std::vector complete_data; + std::vector buffer(1024); + bool is_initialising = true; + + // Set a timeout on the socket + timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + setsockopt(self->get_socket(), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeout), sizeof(timeout)); + + while (self->is_connected() || is_initialising) + { + int valread = 0; + do + { + if (is_initialising) + { + is_initialising = false; + LogFileOutput("SmartPortOverSlip TCPConnection: connected\n"); + self->set_is_connected(true); + } + + valread = recv(self->get_socket(), reinterpret_cast(buffer.data()), static_cast(buffer.size()), 0); + const int errsv = errno; + if (valread < 0) + { + // timeout is fine, just reloop. + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == 0) + { + continue; + } + // otherwise it was a genuine error. + LogFileOutput("Error in read thread for connection, errno: %d = %s\n", errsv, strerror(errsv)); + self->set_is_connected(false); + } + if (valread == 0) + { + // disconnected, close connection, should remove it too: TODO + LogFileOutput("TCPConnection: recv == 0, disconnecting\n"); + self->set_is_connected(false); + } + if (valread > 0) + { + // LogFileOutput("SmartPortOverSlip TCPConnection, inserting data, valread: %d\n", valread); + complete_data.insert(complete_data.end(), buffer.begin(), buffer.begin() + valread); + } + } while (valread == 1024); + + if (!complete_data.empty()) + { + std::vector> decoded_packets = + SLIP::split_into_packets(complete_data.data(), complete_data.size()); + // LogFileOutput("SmartPortOverSlip TCPConnection, packets decoded: %d\n", decoded_packets.size()); + + if (!decoded_packets.empty()) + { + for (const auto &packet : decoded_packets) + { + if (!packet.empty()) + { + { + std::lock_guard lock(self->data_mutex_); + self->data_map_[packet[0]] = packet; + } + self->data_cv_.notify_all(); + } + } + } + complete_data.clear(); + } + } + LogFileOutput("TCPConnection::create_read_channel - thread is EXITING\n"); + }); +} diff --git a/source/SPoverSLIP/TCPConnection.h b/source/SPoverSLIP/TCPConnection.h index a82b50295..982a99c5e 100644 --- a/source/SPoverSLIP/TCPConnection.h +++ b/source/SPoverSLIP/TCPConnection.h @@ -1,21 +1,21 @@ -#pragma once - -#include "Connection.h" -#include -#include - -class TCPConnection : public Connection, public std::enable_shared_from_this -{ -public: - TCPConnection(int socket) : socket_(socket) {} - - virtual void send_data(const std::vector &data) override; - virtual void create_read_channel() override; - virtual void close_connection() override; - - int get_socket() const { return socket_; } - void set_socket(int socket) { this->socket_ = socket; } - -private: - int socket_; -}; +#pragma once + +#include "Connection.h" +#include +#include + +class TCPConnection : public Connection, public std::enable_shared_from_this +{ +public: + TCPConnection(int socket) : socket_(socket) {} + + virtual void send_data(const std::vector &data) override; + virtual void create_read_channel() override; + virtual void close_connection() override; + + int get_socket() const { return socket_; } + void set_socket(int socket) { this->socket_ = socket; } + +private: + int socket_; +}; diff --git a/source/SPoverSLIP/WriteBlockRequest.cpp b/source/SPoverSLIP/WriteBlockRequest.cpp index bcfc6ed65..2f854fb2f 100644 --- a/source/SPoverSLIP/WriteBlockRequest.cpp +++ b/source/SPoverSLIP/WriteBlockRequest.cpp @@ -1,53 +1,44 @@ -#include "WriteBlockRequest.h" - -#include "SmartPortCodes.h" -#include "WriteBlockResponse.h" - -WriteBlockRequest::WriteBlockRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) - : Request(request_sequence_number, SP_WRITE_BLOCK, sp_unit), block_number_{}, block_data_{} -{ -} - -std::vector WriteBlockRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - request_data.insert(request_data.end(), block_number_.begin(), block_number_.end()); - request_data.insert(request_data.end(), block_data_.begin(), block_data_.end()); - - return request_data; -} - -std::unique_ptr WriteBlockRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize WriteBlockResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} - -const std::array &WriteBlockRequest::get_block_number() const { return block_number_; } - -const std::array &WriteBlockRequest::get_block_data() const { return block_data_; } - -void WriteBlockRequest::set_block_number_from_ptr(const uint8_t *ptr, const size_t offset) -{ - std::copy_n(ptr + offset, block_number_.size(), block_number_.begin()); -} - -void WriteBlockRequest::set_block_data_from_ptr(const uint8_t *ptr, const size_t offset) -{ - std::copy_n(ptr + offset, block_data_.size(), block_data_.begin()); -} - -void WriteBlockRequest::set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h) -{ - block_number_[0] = l; - block_number_[1] = m; - block_number_[2] = h; +#include "WriteBlockRequest.h" + +#include "SmartPortCodes.h" +#include "WriteBlockResponse.h" + +WriteBlockRequest::WriteBlockRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_WRITE_BLOCK, sp_unit), block_number_{}, block_data_{} {} + +std::vector WriteBlockRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + request_data.insert(request_data.end(), block_number_.begin(), block_number_.end()); + request_data.insert(request_data.end(), block_data_.begin(), block_data_.end()); + + return request_data; +} + +std::unique_ptr WriteBlockRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize WriteBlockResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} + +const std::array &WriteBlockRequest::get_block_number() const { return block_number_; } + +const std::array &WriteBlockRequest::get_block_data() const { return block_data_; } + +void WriteBlockRequest::set_block_number_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, block_number_.size(), block_number_.begin()); } + +void WriteBlockRequest::set_block_data_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, block_data_.size(), block_data_.begin()); } + +void WriteBlockRequest::set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h) +{ + block_number_[0] = l; + block_number_[1] = m; + block_number_[2] = h; } \ No newline at end of file diff --git a/source/SPoverSLIP/WriteBlockRequest.h b/source/SPoverSLIP/WriteBlockRequest.h index b32591b97..f88c969cb 100644 --- a/source/SPoverSLIP/WriteBlockRequest.h +++ b/source/SPoverSLIP/WriteBlockRequest.h @@ -1,27 +1,27 @@ -#pragma once - -#include -#include -#include -#include - -#include "Request.h" -#include "Response.h" - -class WriteBlockRequest : public Request -{ -public: - WriteBlockRequest(uint8_t request_sequence_number, uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; - const std::array &get_block_number() const; - void set_block_number_from_ptr(const uint8_t *ptr, size_t offset); - - const std::array &get_block_data() const; - void set_block_data_from_ptr(const uint8_t *ptr, size_t offset); - void set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h); - -private: - std::array block_number_; - std::array block_data_; -}; +#pragma once + +#include +#include +#include +#include + +#include "Request.h" +#include "Response.h" + +class WriteBlockRequest : public Request +{ +public: + WriteBlockRequest(uint8_t request_sequence_number, uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; + const std::array &get_block_number() const; + void set_block_number_from_ptr(const uint8_t *ptr, size_t offset); + + const std::array &get_block_data() const; + void set_block_data_from_ptr(const uint8_t *ptr, size_t offset); + void set_block_number_from_bytes(uint8_t l, uint8_t m, uint8_t h); + +private: + std::array block_number_; + std::array block_data_; +}; diff --git a/source/SPoverSLIP/WriteBlockResponse.cpp b/source/SPoverSLIP/WriteBlockResponse.cpp index 665c2d8e5..458a16806 100644 --- a/source/SPoverSLIP/WriteBlockResponse.cpp +++ b/source/SPoverSLIP/WriteBlockResponse.cpp @@ -1,11 +1,11 @@ -#include "WriteBlockResponse.h" - -WriteBlockResponse::WriteBlockResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector WriteBlockResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "WriteBlockResponse.h" + +WriteBlockResponse::WriteBlockResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector WriteBlockResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/WriteBlockResponse.h b/source/SPoverSLIP/WriteBlockResponse.h index ff8cc6a3b..c8a942da3 100644 --- a/source/SPoverSLIP/WriteBlockResponse.h +++ b/source/SPoverSLIP/WriteBlockResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class WriteBlockResponse : public Response -{ -public: - explicit WriteBlockResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class WriteBlockResponse : public Response +{ +public: + explicit WriteBlockResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SPoverSLIP/WriteRequest.cpp b/source/SPoverSLIP/WriteRequest.cpp index 92e009ffc..4086dfe5c 100644 --- a/source/SPoverSLIP/WriteRequest.cpp +++ b/source/SPoverSLIP/WriteRequest.cpp @@ -1,48 +1,45 @@ -// ReSharper disable CppPassValueParameterByConstReference - -#include "WriteRequest.h" - -#include "SmartPortCodes.h" -#include "WriteResponse.h" - -WriteRequest::WriteRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) - : Request(request_sequence_number, SP_WRITE, sp_unit), byte_count_(), address_() -{ -} - -std::vector WriteRequest::serialize() const -{ - std::vector request_data; - request_data.push_back(this->get_request_sequence_number()); - request_data.push_back(this->get_command_number()); - request_data.push_back(this->get_sp_unit()); - request_data.insert(request_data.end(), get_byte_count().begin(), get_byte_count().end()); - request_data.insert(request_data.end(), get_address().begin(), get_address().end()); - request_data.insert(request_data.end(), get_data().begin(), get_data().end()); - return request_data; -} - -std::unique_ptr WriteRequest::deserialize(const std::vector &data) const -{ - if (data.size() < 2) - { - throw std::runtime_error("Not enough data to deserialize WriteResponse"); - } - - auto response = std::make_unique(data[0], data[1]); - return response; -} - -const std::array &WriteRequest::get_byte_count() const { return byte_count_; } - -const std::array &WriteRequest::get_address() const { return address_; } - -void WriteRequest::set_byte_count_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, byte_count_.size(), byte_count_.begin()); } - -void WriteRequest::set_address_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, address_.size(), address_.begin()); } - -void WriteRequest::set_data_from_ptr(const uint8_t *ptr, const size_t offset, const size_t length) -{ - data_.clear(); - data_.insert(data_.end(), ptr + offset, ptr + offset + length); +// ReSharper disable CppPassValueParameterByConstReference + +#include "WriteRequest.h" + +#include "SmartPortCodes.h" +#include "WriteResponse.h" + +WriteRequest::WriteRequest(const uint8_t request_sequence_number, const uint8_t sp_unit) : Request(request_sequence_number, SP_WRITE, sp_unit), byte_count_(), address_() {} + +std::vector WriteRequest::serialize() const +{ + std::vector request_data; + request_data.push_back(this->get_request_sequence_number()); + request_data.push_back(this->get_command_number()); + request_data.push_back(this->get_sp_unit()); + request_data.insert(request_data.end(), get_byte_count().begin(), get_byte_count().end()); + request_data.insert(request_data.end(), get_address().begin(), get_address().end()); + request_data.insert(request_data.end(), get_data().begin(), get_data().end()); + return request_data; +} + +std::unique_ptr WriteRequest::deserialize(const std::vector &data) const +{ + if (data.size() < 2) + { + throw std::runtime_error("Not enough data to deserialize WriteResponse"); + } + + auto response = std::make_unique(data[0], data[1]); + return response; +} + +const std::array &WriteRequest::get_byte_count() const { return byte_count_; } + +const std::array &WriteRequest::get_address() const { return address_; } + +void WriteRequest::set_byte_count_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, byte_count_.size(), byte_count_.begin()); } + +void WriteRequest::set_address_from_ptr(const uint8_t *ptr, const size_t offset) { std::copy_n(ptr + offset, address_.size(), address_.begin()); } + +void WriteRequest::set_data_from_ptr(const uint8_t *ptr, const size_t offset, const size_t length) +{ + data_.clear(); + data_.insert(data_.end(), ptr + offset, ptr + offset + length); } \ No newline at end of file diff --git a/source/SPoverSLIP/WriteRequest.h b/source/SPoverSLIP/WriteRequest.h index fadabf3ba..0e16abed8 100644 --- a/source/SPoverSLIP/WriteRequest.h +++ b/source/SPoverSLIP/WriteRequest.h @@ -1,31 +1,31 @@ -#pragma once - -#include -#include -#include -#include - -#include "Request.h" -#include "Response.h" - -class WriteRequest : public Request -{ -public: - WriteRequest(const uint8_t request_sequence_number, const uint8_t sp_unit); - std::vector serialize() const override; - std::unique_ptr deserialize(const std::vector &data) const override; - - const std::array &get_byte_count() const; - void set_byte_count_from_ptr(const uint8_t *ptr, size_t offset); - - const std::array &get_address() const; - void set_address_from_ptr(const uint8_t *ptr, size_t offset); - - const std::vector &get_data() const { return data_; } - void set_data_from_ptr(const uint8_t *ptr, size_t offset, size_t length); - -private: - std::array byte_count_; - std::array address_; - std::vector data_; -}; +#pragma once + +#include +#include +#include +#include + +#include "Request.h" +#include "Response.h" + +class WriteRequest : public Request +{ +public: + WriteRequest(const uint8_t request_sequence_number, const uint8_t sp_unit); + std::vector serialize() const override; + std::unique_ptr deserialize(const std::vector &data) const override; + + const std::array &get_byte_count() const; + void set_byte_count_from_ptr(const uint8_t *ptr, size_t offset); + + const std::array &get_address() const; + void set_address_from_ptr(const uint8_t *ptr, size_t offset); + + const std::vector &get_data() const { return data_; } + void set_data_from_ptr(const uint8_t *ptr, size_t offset, size_t length); + +private: + std::array byte_count_; + std::array address_; + std::vector data_; +}; diff --git a/source/SPoverSLIP/WriteResponse.cpp b/source/SPoverSLIP/WriteResponse.cpp index 67047e509..4a448de6c 100644 --- a/source/SPoverSLIP/WriteResponse.cpp +++ b/source/SPoverSLIP/WriteResponse.cpp @@ -1,11 +1,11 @@ -#include "WriteResponse.h" - -WriteResponse::WriteResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} - -std::vector WriteResponse::serialize() const -{ - std::vector data; - data.push_back(this->get_request_sequence_number()); - data.push_back(this->get_status()); - return data; +#include "WriteResponse.h" + +WriteResponse::WriteResponse(const uint8_t request_sequence_number, const uint8_t status) : Response(request_sequence_number, status) {} + +std::vector WriteResponse::serialize() const +{ + std::vector data; + data.push_back(this->get_request_sequence_number()); + data.push_back(this->get_status()); + return data; } \ No newline at end of file diff --git a/source/SPoverSLIP/WriteResponse.h b/source/SPoverSLIP/WriteResponse.h index 2f9445cd5..8fb9eb000 100644 --- a/source/SPoverSLIP/WriteResponse.h +++ b/source/SPoverSLIP/WriteResponse.h @@ -1,9 +1,9 @@ -#pragma once -#include "Response.h" - -class WriteResponse : public Response -{ -public: - explicit WriteResponse(uint8_t request_sequence_number, uint8_t status); - std::vector serialize() const override; -}; +#pragma once +#include "Response.h" + +class WriteResponse : public Response +{ +public: + explicit WriteResponse(uint8_t request_sequence_number, uint8_t status); + std::vector serialize() const override; +}; diff --git a/source/SmartPortOverSlip.cpp b/source/SmartPortOverSlip.cpp index 4a902724d..c33bbe5a5 100644 --- a/source/SmartPortOverSlip.cpp +++ b/source/SmartPortOverSlip.cpp @@ -61,7 +61,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA int SmartPortOverSlip::active_instances = 0; -const std::string& SmartPortOverSlip::GetSnapshotCardName() +const std::string &SmartPortOverSlip::GetSnapshotCardName() { static const std::string name("SmartPortOverSlip"); LogFileOutput("SmartPortOverSlip Returning name SmartPortOverSlip\n"); @@ -70,7 +70,8 @@ const std::string& SmartPortOverSlip::GetSnapshotCardName() SmartPortOverSlip::SmartPortOverSlip(const UINT slot) : Card(CT_SmartPortOverSlip, slot) { - if (active_instances > 0) { + if (active_instances > 0) + { throw std::runtime_error("There is an existing slot active for SP over SLIP. You can only have 1 of these cards active."); } active_instances++; @@ -91,8 +92,9 @@ void SmartPortOverSlip::Reset(const bool powerCycle) if (powerCycle) { // send RESET to all devices - const auto connections = GetSPoverSLIPListener().get_all_connections(); - for (const auto& id_and_connection : connections) { + const auto connections = GetSPoverSLIPListener().get_all_connections(); + for (const auto &id_and_connection : connections) + { reset(id_and_connection.first, id_and_connection.second); } } @@ -110,7 +112,7 @@ void SmartPortOverSlip::handle_smartport_call() const WORD params_loc = cmd_list_loc + 4; // LogFileOutput("SmartPortOverSlip processing SP command: 0x%02x, unit: " - // "0x%02x, cmdList: 0x%04x, spPayLoad: 0x%04x, p1: 0x%02x\n", + // "0x%02x, cmdList: 0x%04x, spPayLoad: 0x%04x, p1: 0x%02x\n", // command, unit_number, cmd_list_loc, sp_payload_loc, mem[params_loc]); // Fix the stack so the RTS in the firmware returns to the instruction after the data @@ -128,7 +130,7 @@ void SmartPortOverSlip::handle_smartport_call() const auto id_and_connection = GetSPoverSLIPListener().find_connection_with_device(unit_number); if (id_and_connection.second == nullptr) { - regs.a = 1; // TODO: what value should we error with? + regs.a = 1; // TODO: what value should we error with? regs.x = 0; regs.y = 0; unset_processor_status(AF_ZERO); @@ -138,7 +140,8 @@ void SmartPortOverSlip::handle_smartport_call() const auto device_id = id_and_connection.first; const auto connection = id_and_connection.second.get(); - switch (command) { + switch (command) + { case SP_CMD_STATUS: status_sp(device_id, connection, sp_payload_loc, mem[params_loc]); break; @@ -175,7 +178,6 @@ void SmartPortOverSlip::handle_smartport_call() default: break; } - } void SmartPortOverSlip::handle_prodos_call() @@ -197,155 +199,162 @@ void SmartPortOverSlip::handle_prodos_call() // $2B = Write Protected // Let's get the Drive Num and Slot first - const uint8_t drive_num = (mem[0x43] & 0x80) == 0 ? 1 : 2; - const uint8_t slot_num = (mem[0x43] & 0x70) >> 4; - const uint8_t command = mem[0x42]; + const uint8_t drive_num = (mem[0x43] & 0x80) == 0 ? 1 : 2; + const uint8_t slot_num = (mem[0x43] & 0x70) >> 4; + const uint8_t command = mem[0x42]; LogFileOutput("SmartPortOverSlip prodos, drive_num: %d, slot_num: %d, command: %d\n", drive_num, slot_num, command); - if (slot_num != m_slot) { + if (slot_num != m_slot) + { // not for us... could be mirroring/moving? ignoring for now. see https://www.1000bit.it/support/manuali/apple/technotes/pdos/tn.pdos.20.html - regs.a = 0x28; - regs.x = 0; - regs.y = 0; - return; + regs.a = 0x28; + regs.x = 0; + regs.y = 0; + return; } // The Listener currently holds the information about mappings for device ids to devices. // We need to look for the first registered device of all connections to us that are disks, and use first 2 as our drives. // we can call the listener to do this for us, and it can cache the results so we can keep calling it - std::pair disk_devices = GetSPoverSLIPListener().first_two_disk_devices(); - if ((drive_num == 1 && disk_devices.first == -1) || (drive_num == 2 && disk_devices.second == -1)) { + std::pair disk_devices = GetSPoverSLIPListener().first_two_disk_devices(); + if ((drive_num == 1 && disk_devices.first == -1) || (drive_num == 2 && disk_devices.second == -1)) + { // there is no drive to support this request, so return an error - regs.a = 0x28; - regs.x = 0; - regs.y = 0; - return; + regs.a = 0x28; + regs.x = 0; + regs.y = 0; + return; } - switch (command) - { - case 0x00: - handle_prodos_status(drive_num, disk_devices); + switch (command) + { + case 0x00: + handle_prodos_status(drive_num, disk_devices); + break; + case 0x01: + handle_prodos_read(drive_num, disk_devices); break; - case 0x01: - handle_prodos_read(drive_num, disk_devices); - break; - case 0x02: + case 0x02: handle_prodos_write(drive_num, disk_devices); break; - case 0x03: + case 0x03: // format, TBD - send IO error for now regs.a = 0x27; regs.x = 0; regs.y = 0; - break; - default: + break; + default: // error, unknown command regs.a = 0x28; regs.x = 0; regs.y = 0; - break; + break; } - } void SmartPortOverSlip::handle_prodos_status(uint8_t drive_num, std::pair disk_devices) { - /* - From: https://prodos8.com/docs/techref/adding-routines-to-prodos/ - The STATUS call should perform a check to verify that the device is ready for a READ or WRITE. If it is not, the carry should - be set and the appropriate error code returned in the accumulator. If the device is ready for a READ or WRITE, then the driver - should clear the carry, place a zero in the accumulator, and return the number of blocks on the device in the - X-register (low-byte) and Y-register (high-byte). - */ - auto device_id = drive_num == 1 ? disk_devices.first : disk_devices.second; - auto id_connection = GetSPoverSLIPListener().find_connection_with_device(device_id); - std::unique_ptr response = status_pd(id_connection.first, id_connection.second.get(), 0); - // the first byte of the data in the status response: - /* - // Bit 7: Block device - // Bit 6: Write allowed - // Bit 5: Read allowed - // Bit 4: Device online or disk in drive - // Bit 3: Format allowed - // Bit 2: Media write protected (block devices only) - // Bit 1: Currently interrupting (//c only) - // Bit 0: Disk switched - */ - const auto& status_data = response->get_data(); - if (status_data.size() < 4) - { - // check bits 5/6 set for R/W, and the disk is online bit 4. - uint8_t c = status_data[0] & 0x70; - if (c == 0x70) - { - // we're good, clear carry, set a = 0, and set x/y - LogFileOutput("SmartPortOverSlip Prodos Status OK x: %02x, y: %02x\n", status_data[1], status_data[2]); - regs.a = 0; - regs.x = status_data[1]; - regs.y = status_data[2]; - unset_processor_status(AF_ZERO); - } - else - { - LogFileOutput("SmartPortOverSlip Prodos, Status bits did not match 0x70, found: 0x%02x\n", c); - regs.a = 0x27; - regs.x = 0; - regs.y = 0; - } - } - else - { - // status wasn't long enough, return an IO error - LogFileOutput("SmartPortOverSlip Prodos Status, Bad DIB returned\n"); - regs.a = 0x27; - regs.x = 0; - regs.y = 0; - } + /* + From: https://prodos8.com/docs/techref/adding-routines-to-prodos/ + The STATUS call should perform a check to verify that the device is ready for a READ or WRITE. If it is not, the carry should + be set and the appropriate error code returned in the accumulator. If the device is ready for a READ or WRITE, then the driver + should clear the carry, place a zero in the accumulator, and return the number of blocks on the device in the + X-register (low-byte) and Y-register (high-byte). + */ + auto device_id = drive_num == 1 ? disk_devices.first : disk_devices.second; + auto id_connection = GetSPoverSLIPListener().find_connection_with_device(device_id); + std::unique_ptr response = status_pd(id_connection.first, id_connection.second.get(), 0); + // the first byte of the data in the status response: + /* + // Bit 7: Block device + // Bit 6: Write allowed + // Bit 5: Read allowed + // Bit 4: Device online or disk in drive + // Bit 3: Format allowed + // Bit 2: Media write protected (block devices only) + // Bit 1: Currently interrupting (//c only) + // Bit 0: Disk switched + */ + const auto &status_data = response->get_data(); + if (status_data.size() < 4) + { + // check bits 5/6 set for R/W, and the disk is online bit 4. + uint8_t c = status_data[0] & 0x70; + if (c == 0x70) + { + // we're good, clear carry, set a = 0, and set x/y + LogFileOutput("SmartPortOverSlip Prodos Status OK x: %02x, y: %02x\n", status_data[1], status_data[2]); + regs.a = 0; + regs.x = status_data[1]; + regs.y = status_data[2]; + unset_processor_status(AF_ZERO); + } + else + { + LogFileOutput("SmartPortOverSlip Prodos, Status bits did not match 0x70, found: 0x%02x\n", c); + regs.a = 0x27; + regs.x = 0; + regs.y = 0; + } + } + else + { + // status wasn't long enough, return an IO error + LogFileOutput("SmartPortOverSlip Prodos Status, Bad DIB returned\n"); + regs.a = 0x27; + regs.x = 0; + regs.y = 0; + } } void SmartPortOverSlip::handle_prodos_read(uint8_t drive_num, std::pair disk_devices) { // $44-$45 = buffer pointer - WORD buffer_location = static_cast(mem[0x44]) + static_cast(mem[0x45] << 8); - auto device_id = drive_num == 1 ? disk_devices.first : disk_devices.second; - auto id_connection = GetSPoverSLIPListener().find_connection_with_device(device_id); + WORD buffer_location = static_cast(mem[0x44]) + static_cast(mem[0x45] << 8); + auto device_id = drive_num == 1 ? disk_devices.first : disk_devices.second; + auto id_connection = GetSPoverSLIPListener().find_connection_with_device(device_id); // Do a ReadRequest, and shove the 512 byte block into the required memory - ReadBlockRequest request(Requestor::next_request_number(), id_connection.first); + ReadBlockRequest request(Requestor::next_request_number(), id_connection.first); // $46-47 = Block Number - request.set_block_number_from_bytes(mem[0x46], mem[0x47], 0); - auto response = Requestor::send_request(request, id_connection.second.get()); - - handle_response(std::move(response), [this, buffer_location](const ReadBlockResponse *rbr) { - memcpy(mem + buffer_location, rbr->get_block_data().data(), 512); - regs.a = 0; - regs.x = 0; - regs.y = 2; // 512 bytes - }, 0x27); + request.set_block_number_from_bytes(mem[0x46], mem[0x47], 0); + auto response = Requestor::send_request(request, id_connection.second.get()); + + handle_response( + std::move(response), + [this, buffer_location](const ReadBlockResponse *rbr) { + memcpy(mem + buffer_location, rbr->get_block_data().data(), 512); + regs.a = 0; + regs.x = 0; + regs.y = 2; // 512 bytes + }, + 0x27); } void SmartPortOverSlip::handle_prodos_write(uint8_t drive_num, std::pair disk_devices) { // $44-$45 = buffer pointer - WORD buffer_location = static_cast(mem[0x44]) + static_cast(mem[0x45] << 8); - auto device_id = drive_num == 1 ? disk_devices.first : disk_devices.second; - auto id_connection = GetSPoverSLIPListener().find_connection_with_device(device_id); + WORD buffer_location = static_cast(mem[0x44]) + static_cast(mem[0x45] << 8); + auto device_id = drive_num == 1 ? disk_devices.first : disk_devices.second; + auto id_connection = GetSPoverSLIPListener().find_connection_with_device(device_id); - WriteBlockRequest request(Requestor::next_request_number(), id_connection.first); + WriteBlockRequest request(Requestor::next_request_number(), id_connection.first); // $46-47 = Block Number - request.set_block_number_from_bytes(mem[0x46], mem[0x47], 0); + request.set_block_number_from_bytes(mem[0x46], mem[0x47], 0); // put data into the request we're sending request.set_block_data_from_ptr(mem, buffer_location); - auto response = Requestor::send_request(request, id_connection.second.get()); - - handle_response(std::move(response), [this, buffer_location](const WriteBlockResponse *rbr) { - regs.a = 0; - regs.x = 0; - regs.y = 2; // 512 bytes - }, 0x27); + auto response = Requestor::send_request(request, id_connection.second.get()); + + handle_response( + std::move(response), + [this, buffer_location](const WriteBlockResponse *rbr) { + regs.a = 0; + regs.x = 0; + regs.y = 2; // 512 bytes + }, + 0x27); } BYTE SmartPortOverSlip::io_write0(WORD programCounter, const WORD address, const BYTE value, ULONG nCycles) @@ -355,11 +364,11 @@ BYTE SmartPortOverSlip::io_write0(WORD programCounter, const WORD address, const if (value == 0x65 && loc == 0x02) { handle_smartport_call(); - } + } // ProDos = $66 in $02 else if (value == 0x66 && loc == 0x02) { - handle_prodos_call(); + handle_prodos_call(); } return 0; } @@ -371,9 +380,9 @@ void SmartPortOverSlip::device_count(const WORD sp_payload_loc) const BYTE deviceCount = Listener::get_total_device_count(); mem[sp_payload_loc] = deviceCount; mem[sp_payload_loc + 1] = 1 << 6; // no interrupt - mem[sp_payload_loc + 2] = 0x4D; // 0x4D46 == MF for vendor ID + mem[sp_payload_loc + 2] = 0x4D; // 0x4D46 == MF for vendor ID mem[sp_payload_loc + 3] = 0x46; - mem[sp_payload_loc + 4] = 0x0A; // version 1.00 Alpha = $100A + mem[sp_payload_loc + 4] = 0x0A; // version 1.00 Alpha = $100A mem[sp_payload_loc + 5] = 0x10; regs.a = 0; regs.x = 6; @@ -381,14 +390,14 @@ void SmartPortOverSlip::device_count(const WORD sp_payload_loc) set_processor_status(AF_ZERO); } -void SmartPortOverSlip::read_block(const BYTE unit_number, Connection* connection, const WORD buffer_location, const WORD block_count_address) +void SmartPortOverSlip::read_block(const BYTE unit_number, Connection *connection, const WORD buffer_location, const WORD block_count_address) { ReadBlockRequest request(Requestor::next_request_number(), unit_number); // Assume that (cmd_list_loc + 4 == block_count_address) holds 3 bytes for the block number. If it's in the payload, this is wrong and will have to be fixed. request.set_block_number_from_ptr(mem, block_count_address); auto response = Requestor::send_request(request, connection); - handle_response(std::move(response), [this, buffer_location](const ReadBlockResponse* rbr) { + handle_response(std::move(response), [this, buffer_location](const ReadBlockResponse *rbr) { memcpy(mem + buffer_location, rbr->get_block_data().data(), 512); regs.a = 0; regs.x = 0; @@ -396,7 +405,7 @@ void SmartPortOverSlip::read_block(const BYTE unit_number, Connection* connectio }); } -void SmartPortOverSlip::write_block(const BYTE unit_number, Connection* connection, const WORD sp_payload_loc, const WORD params_loc) +void SmartPortOverSlip::write_block(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const WORD params_loc) { WriteBlockRequest request(Requestor::next_request_number(), unit_number); // Assume that (cmd_list_loc + 4 == params_loc) holds 3 bytes for the block number. The payload contains the data to write @@ -407,14 +416,14 @@ void SmartPortOverSlip::write_block(const BYTE unit_number, Connection* connecti handle_simple_response(std::move(response)); } -void SmartPortOverSlip::read(const BYTE unit_number, Connection* connection, const WORD sp_payload_loc, const WORD params_loc) +void SmartPortOverSlip::read(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const WORD params_loc) { ReadRequest request(Requestor::next_request_number(), unit_number); request.set_byte_count_from_ptr(mem, params_loc); request.set_address_from_ptr(mem, params_loc + 2); // move along by byte_count size. would be better to get its size rather than hard code it here. auto response = Requestor::send_request(request, connection); - handle_response(std::move(response), [sp_payload_loc](const ReadResponse* rr) { + handle_response(std::move(response), [sp_payload_loc](const ReadResponse *rr) { const auto response_size = rr->get_data().size(); memcpy(mem + sp_payload_loc, rr->get_data().data(), response_size); regs.a = 0; @@ -423,7 +432,7 @@ void SmartPortOverSlip::read(const BYTE unit_number, Connection* connection, con }); } -void SmartPortOverSlip::write(const BYTE unit_number, Connection* connection, const WORD sp_payload_loc, const WORD params_loc) +void SmartPortOverSlip::write(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const WORD params_loc) { WriteRequest request(Requestor::next_request_number(), unit_number); request.set_byte_count_from_ptr(mem, params_loc); @@ -438,8 +447,8 @@ void SmartPortOverSlip::write(const BYTE unit_number, Connection* connection, co void SmartPortOverSlip::status_sp(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const BYTE status_code) { - auto response = status(unit_number, connection, status_code); - handle_response(std::move(response), [sp_payload_loc](const StatusResponse* sr) { + auto response = status(unit_number, connection, status_code); + handle_response(std::move(response), [sp_payload_loc](const StatusResponse *sr) { const auto response_size = sr->get_data().size(); memcpy(mem + sp_payload_loc, sr->get_data().data(), response_size); regs.a = 0; @@ -451,30 +460,27 @@ void SmartPortOverSlip::status_sp(const BYTE unit_number, Connection *connection std::unique_ptr SmartPortOverSlip::status(const BYTE unit_number, Connection *connection, const BYTE status_code) { // see https://www.1000bit.it/support/manuali/apple/technotes/smpt/tn.smpt.2.html - const StatusRequest request(Requestor::next_request_number(), unit_number, status_code); - return Requestor::send_request(request, connection); - + const StatusRequest request(Requestor::next_request_number(), unit_number, status_code); + return Requestor::send_request(request, connection); } std::unique_ptr SmartPortOverSlip::status_pd(const BYTE unit_number, Connection *connection, const BYTE status_code) { - auto response = status(unit_number, connection, status_code); - - // Cast the Response to a StatusResponse. We need to release ownership. As ChatGPT explains: - /* - You have a std::unique_ptr and you want to return a std::unique_ptr. - You can't simply cast the std::unique_ptr to std::unique_ptr, because this would create two std::unique_ptrs - (the original one and the cast one) that own the same object, which is not allowed. - */ + auto response = status(unit_number, connection, status_code); + + // Cast the Response to a StatusResponse. We need to release ownership. As ChatGPT explains: + /* + You have a std::unique_ptr and you want to return a std::unique_ptr. + You can't simply cast the std::unique_ptr to std::unique_ptr, because this would create two std::unique_ptrs + (the original one and the cast one) that own the same object, which is not allowed. + */ return std::unique_ptr(static_cast(response.release())); - - } -void SmartPortOverSlip::control(const BYTE unit_number, Connection* connection, const WORD sp_payload_loc, const BYTE control_code) +void SmartPortOverSlip::control(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const BYTE control_code) { const auto length = mem[sp_payload_loc] + (mem[sp_payload_loc + 1] << 8) + 2; - uint8_t* start_ptr = &mem[sp_payload_loc]; + uint8_t *start_ptr = &mem[sp_payload_loc]; std::vector payload(start_ptr, start_ptr + length); const ControlRequest request(Requestor::next_request_number(), unit_number, control_code, payload); @@ -482,49 +488,50 @@ void SmartPortOverSlip::control(const BYTE unit_number, Connection* connection, handle_simple_response(std::move(response)); } -void SmartPortOverSlip::init(const BYTE unit_number, Connection* connection) +void SmartPortOverSlip::init(const BYTE unit_number, Connection *connection) { const InitRequest request(Requestor::next_request_number(), unit_number); auto response = Requestor::send_request(request, connection); handle_simple_response(std::move(response)); } -void SmartPortOverSlip::open(const BYTE unit_number, Connection* connection) +void SmartPortOverSlip::open(const BYTE unit_number, Connection *connection) { const OpenRequest request(Requestor::next_request_number(), unit_number); auto response = Requestor::send_request(request, connection); handle_simple_response(std::move(response)); } -void SmartPortOverSlip::close(const BYTE unit_number, Connection* connection) +void SmartPortOverSlip::close(const BYTE unit_number, Connection *connection) { const CloseRequest request(Requestor::next_request_number(), unit_number); auto response = Requestor::send_request(request, connection); handle_simple_response(std::move(response)); } -void SmartPortOverSlip::reset(const BYTE unit_number, Connection* connection) +void SmartPortOverSlip::reset(const BYTE unit_number, Connection *connection) { const ResetRequest request(Requestor::next_request_number(), unit_number); auto response = Requestor::send_request(request, connection); handle_simple_response(std::move(response)); } -void SmartPortOverSlip::format(const BYTE unit_number, Connection* connection) +void SmartPortOverSlip::format(const BYTE unit_number, Connection *connection) { const FormatRequest request(Requestor::next_request_number(), unit_number); auto response = Requestor::send_request(request, connection); handle_simple_response(std::move(response)); } - BYTE __stdcall c0Handler(const WORD programCounter, const WORD address, const BYTE write, const BYTE value, const ULONG nCycles) { const UINT uSlot = ((address & 0xf0) >> 4) - 8; - if (uSlot < 8) { - auto* pCard = static_cast(MemGetSlotParameters(uSlot)); - if (write) { + if (uSlot < 8) + { + auto *pCard = static_cast(MemGetSlotParameters(uSlot)); + if (write) + { return pCard->io_write0(programCounter, address, value, nCycles); } } @@ -536,7 +543,7 @@ void SmartPortOverSlip::InitializeIO(LPBYTE pCxRomPeripheral) LogFileOutput("SmartPortOverSlip InitialiseIO\n"); // Load firmware into chosen slot - const BYTE* pData = GetFrame().GetResource(IDR_SPOVERSLIP_FW, "FIRMWARE", APPLE_SLOT_SIZE); + const BYTE *pData = GetFrame().GetResource(IDR_SPOVERSLIP_FW, "FIRMWARE", APPLE_SLOT_SIZE); if (pData == nullptr) return; @@ -544,11 +551,11 @@ void SmartPortOverSlip::InitializeIO(LPBYTE pCxRomPeripheral) std::memcpy(pCxRomPeripheral + m_slot * APPLE_SLOT_SIZE, pData, APPLE_SLOT_SIZE); // Set location in firmware that need to know the slot number for reading/writing to the card - const BYTE locCN1 = pData[0xF9]; // location of where to put $n2 - const BYTE locCN2 = pData[0xFA]; // location of where to put $n2 + const BYTE locCN1 = pData[0xF9]; // location of where to put $n2 + const BYTE locCN2 = pData[0xFA]; // location of where to put $n2 const BYTE cn = ((m_slot & 0xff) | 0xC0); // slot(n) || 0xC0 = 0xCn - const BYTE locN2 = pData[0xFB]; // location of where to put $n2 + const BYTE locN2 = pData[0xFB]; // location of where to put $n2 const BYTE n2 = static_cast(((m_slot & 0xff) | 0x08) << 4) + 0x02; // (slot + 8) * 16 + 2, giving low byte of $C0n2 // Modify the destination memory to hold the slot information needed by the firmware. @@ -566,18 +573,12 @@ void SmartPortOverSlip::Update(const ULONG nExecutedCycles) // LogFileOutput("SmartPortOverSlip Update\n"); } +void SmartPortOverSlip::SaveSnapshot(YamlSaveHelper &yamlSaveHelper) { LogFileOutput("SmartPortOverSlip SaveSnapshot\n"); } -void SmartPortOverSlip::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) -{ - LogFileOutput("SmartPortOverSlip SaveSnapshot\n"); -} - -bool SmartPortOverSlip::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) +bool SmartPortOverSlip::LoadSnapshot(YamlLoadHelper &yamlLoadHelper, UINT version) { LogFileOutput("SmartPortOverSlip LoadSnapshot\n"); return true; } -void SmartPortOverSlip::Destroy() -{ -} +void SmartPortOverSlip::Destroy() {} diff --git a/source/SmartPortOverSlip.h b/source/SmartPortOverSlip.h index 1ea3fa61e..65f08ed80 100644 --- a/source/SmartPortOverSlip.h +++ b/source/SmartPortOverSlip.h @@ -15,115 +15,117 @@ class InitResponse; enum { - SP_CMD_STATUS = 0, - SP_CMD_READBLOCK = 1, - SP_CMD_WRITEBLOCK = 2, - SP_CMD_FORMAT = 3, - SP_CMD_CONTROL = 4, - SP_CMD_INIT = 5, - SP_CMD_OPEN = 6, - SP_CMD_CLOSE = 7, - SP_CMD_READ = 8, - SP_CMD_WRITE = 9, - SP_CMD_RESET = 10 + SP_CMD_STATUS = 0, + SP_CMD_READBLOCK = 1, + SP_CMD_WRITEBLOCK = 2, + SP_CMD_FORMAT = 3, + SP_CMD_CONTROL = 4, + SP_CMD_INIT = 5, + SP_CMD_OPEN = 6, + SP_CMD_CLOSE = 7, + SP_CMD_READ = 8, + SP_CMD_WRITE = 9, + SP_CMD_RESET = 10 }; - class SmartPortOverSlip : public Card { public: - static const std::string& GetSnapshotCardName(); - - explicit SmartPortOverSlip(UINT slot); - ~SmartPortOverSlip() override; - - void Destroy() override; - void InitializeIO(LPBYTE pCxRomPeripheral) override; - void Reset(bool powerCycle) override; - void Update(ULONG nExecutedCycles) override; - void SaveSnapshot(YamlSaveHelper& yamlSaveHelper) override; - bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) override; - - BYTE io_write0(WORD programCounter, WORD address, BYTE value, ULONG nCycles); - static void device_count(WORD sp_payload_loc); - void handle_smartport_call(); - void handle_prodos_call(); - void control(BYTE unit_number, Connection* connection, WORD sp_payload_loc, BYTE control_code); - void init(BYTE unit_number, Connection* connection); - void open(BYTE unit_number, Connection* connection); - void close(BYTE unit_number, Connection* connection); - void format(BYTE unit_number, Connection* connection); - void reset(BYTE unit_number, Connection* connection); - void read_block(BYTE unit_number, Connection* connection, WORD sp_payload_loc, WORD params_loc); - void write_block(BYTE unit_number, Connection* connection, WORD sp_payload_loc, WORD params_loc); - void read(BYTE unit_number, Connection* connection, WORD sp_payload_loc, WORD params_loc); - void write(BYTE unit_number, Connection* connection, WORD sp_payload_loc, WORD params_loc); - - std::unique_ptr status(BYTE unit_number, Connection *connection, BYTE status_code); - std::unique_ptr status_pd(const BYTE unit_number, Connection *connection, const BYTE status_code); - void status_sp(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const BYTE status_code); - - void handle_prodos_status(uint8_t drive_num, std::pair disk_devices); - void handle_prodos_read(uint8_t drive_num, std::pair disk_devices); - void handle_prodos_write(uint8_t drive_num, std::pair disk_devices); - - static void set_processor_status(const uint8_t flags) { regs.ps |= flags; } - static void unset_processor_status(const uint8_t flags) { regs.ps &= (0xFF - flags); } - // if condition is true then set the flags given, else remove them. - static void update_processor_status(const bool condition, const uint8_t flags) { condition ? set_processor_status(flags) : unset_processor_status(flags); } - - template - void handle_simple_response(const std::unique_ptr response) { - static_assert(std::is_base_of::value, "T must be a subclass of Response"); - auto specific_response = dynamic_cast(response.get()); - - if (specific_response != nullptr) - { - const BYTE status = specific_response->get_status(); - regs.a = status; - regs.x = 0; - regs.y = 0; - update_processor_status(status == 0, AF_ZERO); - } - else - { - regs.a = 1; // TODO: what error should we return? - regs.x = 0; - regs.y = 0; - unset_processor_status(AF_ZERO); - } - } - - template - void handle_response(const std::unique_ptr response, Func call_back, int error_code = 1) { - auto specific_response = dynamic_cast(response.get()); - - if (specific_response != nullptr) - { - if (specific_response->get_status() == 0) - { - call_back(specific_response); - set_processor_status(AF_ZERO); - } - else - { - // An error in the response - regs.a = specific_response->get_status(); - regs.x = 0; - regs.y = 0; - unset_processor_status(AF_ZERO); - } - } - else - { - // An error trying to do the request, as there was no response - regs.a = error_code; - regs.x = 0; - regs.y = 0; - unset_processor_status(AF_ZERO); - } - } + static const std::string &GetSnapshotCardName(); + + explicit SmartPortOverSlip(UINT slot); + ~SmartPortOverSlip() override; + + void Destroy() override; + void InitializeIO(LPBYTE pCxRomPeripheral) override; + void Reset(bool powerCycle) override; + void Update(ULONG nExecutedCycles) override; + void SaveSnapshot(YamlSaveHelper &yamlSaveHelper) override; + bool LoadSnapshot(YamlLoadHelper &yamlLoadHelper, UINT version) override; + + BYTE io_write0(WORD programCounter, WORD address, BYTE value, ULONG nCycles); + static void device_count(WORD sp_payload_loc); + void handle_smartport_call(); + void handle_prodos_call(); + void control(BYTE unit_number, Connection *connection, WORD sp_payload_loc, BYTE control_code); + void init(BYTE unit_number, Connection *connection); + void open(BYTE unit_number, Connection *connection); + void close(BYTE unit_number, Connection *connection); + void format(BYTE unit_number, Connection *connection); + void reset(BYTE unit_number, Connection *connection); + void read_block(BYTE unit_number, Connection *connection, WORD sp_payload_loc, WORD params_loc); + void write_block(BYTE unit_number, Connection *connection, WORD sp_payload_loc, WORD params_loc); + void read(BYTE unit_number, Connection *connection, WORD sp_payload_loc, WORD params_loc); + void write(BYTE unit_number, Connection *connection, WORD sp_payload_loc, WORD params_loc); + + std::unique_ptr status(BYTE unit_number, Connection *connection, BYTE status_code); + std::unique_ptr status_pd(const BYTE unit_number, Connection *connection, const BYTE status_code); + void status_sp(const BYTE unit_number, Connection *connection, const WORD sp_payload_loc, const BYTE status_code); + + void handle_prodos_status(uint8_t drive_num, std::pair disk_devices); + void handle_prodos_read(uint8_t drive_num, std::pair disk_devices); + void handle_prodos_write(uint8_t drive_num, std::pair disk_devices); + + static void set_processor_status(const uint8_t flags) { regs.ps |= flags; } + static void unset_processor_status(const uint8_t flags) { regs.ps &= (0xFF - flags); } + // if condition is true then set the flags given, else remove them. + static void update_processor_status(const bool condition, const uint8_t flags) { condition ? set_processor_status(flags) : unset_processor_status(flags); } + + template + void handle_simple_response(const std::unique_ptr response) + { + static_assert(std::is_base_of::value, "T must be a subclass of Response"); + auto specific_response = dynamic_cast(response.get()); + + if (specific_response != nullptr) + { + const BYTE status = specific_response->get_status(); + regs.a = status; + regs.x = 0; + regs.y = 0; + update_processor_status(status == 0, AF_ZERO); + } + else + { + regs.a = 1; // TODO: what error should we return? + regs.x = 0; + regs.y = 0; + unset_processor_status(AF_ZERO); + } + } + + template + void handle_response(const std::unique_ptr response, Func call_back, int error_code = 1) + { + auto specific_response = dynamic_cast(response.get()); + + if (specific_response != nullptr) + { + if (specific_response->get_status() == 0) + { + call_back(specific_response); + set_processor_status(AF_ZERO); + } + else + { + // An error in the response + regs.a = specific_response->get_status(); + regs.x = 0; + regs.y = 0; + unset_processor_status(AF_ZERO); + } + } + else + { + // An error trying to do the request, as there was no response + regs.a = error_code; + regs.x = 0; + regs.y = 0; + unset_processor_status(AF_ZERO); + } + } + private: - // Ensure no more than 1 card is active as it can cater for all connections to external devices - static int active_instances; + // Ensure no more than 1 card is active as it can cater for all connections to external devices + static int active_instances; }; \ No newline at end of file