From a84e784846978b452187eb7a1f928845784b6fa7 Mon Sep 17 00:00:00 2001 From: aexzhou Date: Sat, 17 Jan 2026 15:17:25 -0800 Subject: [PATCH 01/12] Initial Implementation of the buffer template class --- client/CMakeLists.txt | 1 + client/include/client/buffer_base.hpp | 89 +++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 client/include/client/buffer_base.hpp diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 17574455..274a991b 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -24,6 +24,7 @@ set(CLIENT_HEADERS include/client/message_model.hpp include/client/tcp_client.hpp include/client/json_reader.hpp + include/client/buffer_base.hpp include/client/DataBuffer.hpp include/client/sensor_manager.hpp include/client/sensor_data_panel.h diff --git a/client/include/client/buffer_base.hpp b/client/include/client/buffer_base.hpp new file mode 100644 index 00000000..dfa079c2 --- /dev/null +++ b/client/include/client/buffer_base.hpp @@ -0,0 +1,89 @@ +// #pragma once +#include +#include +#include + +/** + * @brief Base class for buffers with templated data type + * @tparam T The type of data stored in the buffer + * + * This template class provides thread-safe buffer operations + * (e.g., writes, reads ...) + * that can be customized by child classes + * to work with any data type. + */ +template +class BufferBase { +public: + BufferBase() = default; + virtual ~BufferBase() = default; + + /** + * @brief Write data to the buffer + * @param data The data to append to the buffer + */ + virtual void write(T data) { + std::lock_guard lock(mutex_); + buffer_.push_back(std::move(data)); + } + + /** + * @brief Replace the entire buffer with new data + * @param data The data to set as the new buffer content + */ + virtual void setData(T data) { + std::lock_guard lock(mutex_); + buffer_.clear(); + buffer_.push_back(std::move(data)); + } + + /** + * @brief Read all data from the buffer without clearing it + * @return A copy of all data in the buffer + */ + virtual std::list readAll() const { + std::lock_guard lock(mutex_); + return buffer_; + } + + /** + * @brief Read and clear all data from the buffer + * @return All data that was in the buffer + */ + virtual std::list consume() { + std::lock_guard lock(mutex_); + std::list result = std::move(buffer_); + buffer_.clear(); + return result; + } + + /** + * @brief Get the number of elements in the buffer + * @return The number of elements + */ + virtual size_t size() const { + std::lock_guard lock(mutex_); + return buffer_.size(); + } + + /** + * @brief Check if the buffer is empty + * @return true if the buffer is empty, false otherwise + */ + virtual bool empty() const { + std::lock_guard lock(mutex_); + return buffer_.empty(); + } + + /** + * @brief Clear all data from the buffer + */ + virtual void clear() { + std::lock_guard lock(mutex_); + buffer_.clear(); + } + +protected: + std::list buffer_; + mutable std::mutex mutex_; +}; From a866e42fd58406975f62d46f23d5ee4910403e4d Mon Sep 17 00:00:00 2001 From: Henry van Weelderen Date: Sat, 24 Jan 2026 15:05:36 -0800 Subject: [PATCH 02/12] read buffer works about to start implementation and adding to buffer --- client/src/json_reader.cpp | 28 ++++++++++++++++++++-------- client/src/main.cpp | 2 +- tools/pserver/pserver.py | 2 +- tools/pserver/pstream_json.py | 6 ++++++ tools/pserver/pstreamer.py | 2 ++ 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/client/src/json_reader.cpp b/client/src/json_reader.cpp index d79b536b..7e265507 100644 --- a/client/src/json_reader.cpp +++ b/client/src/json_reader.cpp @@ -41,24 +41,36 @@ buffer_data_t JsonReader::exportToBuffer(std::string json) { rapidjson::Document doc; rapidjson::ParseResult ok = doc.Parse(json.c_str()); - std::cout << json; + // if (doc.IsArray()) { + // std::cout << "dwda"; + // } + //std::cout << json << std::endl; if (!ok) { std::cerr << "JSON parse error at offset " << ok.Offset() << ": " << rapidjson::GetParseError_En(ok.Code()) << std::endl; + //std::cout << json; return ret; // return default-initialized struct - } + } if (!doc.IsObject()) { std::cerr << "JSON is not an object!\n"; return ret; } - if (doc["sensor"].GetString() == "temperature") { - ret.a_data = doc["value"].GetFloat(); - } else if (doc["sensor"].GetString() == "pressure") { - ret.b_data = doc["value"].GetFloat(); - std::cout << ret.b_data << "B DATA"; - } + std::string sensorTypeString ( + doc["sensor"].GetString(), + doc["sensor"].GetStringLength() + ); + std::string sensorUnitString ( + doc["unit"].GetString(), + doc["unit"].GetStringLength() + ); + + double sensorValue = doc["value"].GetDouble(); + + std::cout << sensorTypeString << sensorValue << sensorUnitString << std::endl; + + return ret; } \ No newline at end of file diff --git a/client/src/main.cpp b/client/src/main.cpp index 049fa83a..ebc2a124 100644 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -36,7 +36,7 @@ class PanoramaClient : public wxApp { model_ = std::make_shared(); // --- Create and start TCP client on separate thread --- - tcpClient_ = std::make_unique("127.0.0.1", 3000, model_); + tcpClient_ = std::make_unique("127.0.0.1", 4000, model_); tcpClient_->start(); // For running without a gui diff --git a/tools/pserver/pserver.py b/tools/pserver/pserver.py index 3bf80d83..6560595e 100644 --- a/tools/pserver/pserver.py +++ b/tools/pserver/pserver.py @@ -41,7 +41,7 @@ def send_stream(self, client_socket, client_address, streamer: PStreamer): def main(): host = '127.0.0.1' - port = 3000 + port = 4000 if len(sys.argv) > 1: port = int(sys.argv[1]) diff --git a/tools/pserver/pstream_json.py b/tools/pserver/pstream_json.py index 926424d2..79972295 100644 --- a/tools/pserver/pstream_json.py +++ b/tools/pserver/pstream_json.py @@ -24,6 +24,11 @@ def __init__(self): "sensor": "pressure", "value": 1013.25, "unit": "hPa" + }, + { + "sensor": "light", + "value": 0.2, + "unit": "nm" } ] @@ -50,6 +55,7 @@ def get_next_data(self) -> bytes: # Convert to JSON string with newline delimiter ('\n') json_str = json.dumps(json_obj) message = json_str + '\n' + return message.encode('utf-8') \ No newline at end of file diff --git a/tools/pserver/pstreamer.py b/tools/pserver/pstreamer.py index aefcb45d..0aa1af38 100644 --- a/tools/pserver/pstreamer.py +++ b/tools/pserver/pstreamer.py @@ -63,6 +63,8 @@ def _stream_worker(self): # Wait for the specified interval or until stop is requested self._stop_event.wait(timeout=self.stream_interval) + #print(data) + except Exception as e: print(f"[PStreamer] Error in stream worker: {e}") finally: From cab37208578768dd9aa21df6a3de9400d2b78921 Mon Sep 17 00:00:00 2001 From: aexzhou Date: Sat, 24 Jan 2026 15:21:22 -0800 Subject: [PATCH 03/12] [Buffer, General] Initial integration of Buffer class into main code --- client/include/client/DataBuffer.hpp | 7 ++++-- client/include/client/mainframe.hpp | 8 ++++++- client/include/client/tcp_client.hpp | 14 ++++++++---- client/include/common/panorama_defines.hpp | 2 ++ client/src/DataBuffer.cpp | 26 +++++++++++++++++----- client/src/main.cpp | 13 ++++++++--- client/src/mainframe.cpp | 11 ++++++++- client/src/tcp_client.cpp | 15 +++++++------ 8 files changed, 72 insertions(+), 24 deletions(-) diff --git a/client/include/client/DataBuffer.hpp b/client/include/client/DataBuffer.hpp index b4e1ded4..efbeb22e 100644 --- a/client/include/client/DataBuffer.hpp +++ b/client/include/client/DataBuffer.hpp @@ -1,11 +1,13 @@ -#pragma once +#ifndef __DATABUFFER__ +#define __DATABUFFER__ #include #include #include #include "common/panorama_defines.hpp" +#include "client/buffer_base.hpp" #include -class DataBuffer { +class DataBuffer : public BufferBase { public: DataBuffer(); ~DataBuffer(); @@ -78,3 +80,4 @@ class DataBuffer { // This keeps parsing logic isolated from buffer logic bool decodeJson(const std::string& jsonStr /*, ParsedData &out */); }; +#endif // __DATABUFFER__ \ No newline at end of file diff --git a/client/include/client/mainframe.hpp b/client/include/client/mainframe.hpp index f18bc5b1..d8d5711a 100644 --- a/client/include/client/mainframe.hpp +++ b/client/include/client/mainframe.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef __MAINFRAME__ +#define __MAINFRAME__ #include #include #include @@ -13,6 +14,7 @@ class MessageModel; +class DataBuffer; //class GraphPanel; class SensorDataManager; //class SensorDataFrame; // Add this @@ -20,6 +22,7 @@ class SensorDataManager; class MainFrame : public wxFrame { public: MainFrame(const wxString& title, std::shared_ptr model, + std::shared_ptr dataBuffer, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(1200, 800)); @@ -27,6 +30,9 @@ class MainFrame : public wxFrame { void updateMessageDisplay(); std::shared_ptr model_; + std::shared_ptr dataBuffer_; wxTextCtrl* messageDisplay_; }; + +#endif // __MAINFRAME__ \ No newline at end of file diff --git a/client/include/client/tcp_client.hpp b/client/include/client/tcp_client.hpp index 8cee98c6..dd61224a 100644 --- a/client/include/client/tcp_client.hpp +++ b/client/include/client/tcp_client.hpp @@ -1,14 +1,17 @@ -#pragma once +#ifndef __TCP_CLIENT__ +#define __TCP_CLIENT__ + #include #include #include #include class MessageModel; +class DataBuffer; class TcpClient { public: - TcpClient(const std::string& host, int port, std::shared_ptr model); + TcpClient(const std::string& host, int port, std::shared_ptr model, std::shared_ptr dataBuffer); ~TcpClient(); void start(); @@ -22,12 +25,15 @@ class TcpClient { std::string host_; int port_; std::shared_ptr model_; + std::shared_ptr dataBuffer_; std::atomic running_; std::thread clientThread_; - + #ifdef _WIN32 unsigned long long socket_; // SOCKET type on Windows #else int socket_; #endif -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/client/include/common/panorama_defines.hpp b/client/include/common/panorama_defines.hpp index c333dc23..384710f0 100644 --- a/client/include/common/panorama_defines.hpp +++ b/client/include/common/panorama_defines.hpp @@ -1,3 +1,5 @@ +#pragma once + typedef struct { char a; float a_data; diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index 0c5693ce..33777207 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -8,27 +8,41 @@ DataBuffer::~DataBuffer() { } void DataBuffer::writeData(buffer_data_t jsonChunk) { - // Append the new chunk of raw JSON data to the buffer. This functions only job is to store raw + // Append the new chunk of raw JSON data to the buffer. This functions only job is to store raw // inbound data in a way that doesn't lose anything later the parser will call extractNextJson() // parseNextJson() - buffer_.push_back(jsonChunk); + write(jsonChunk); } void DataBuffer::setData(buffer_data_t jsonData) { // Overwrite the entire buffer with new raw JSON data - buffer_.clear(); - buffer_.push_front(jsonData); + BufferBase::setData(jsonData); } std::list DataBuffer::readAll() const { // TODO: return raw buffer as is - return buffer_; + return BufferBase::readAll(); } std::list DataBuffer::consume() { // TODO: copy the raw buffer then clear the buffer and return copied content - std::list temp = buffer_; + return BufferBase::consume(); } + +size_t DataBuffer::size() const { + return BufferBase::size(); +} + +void DataBuffer::clear() { + BufferBase::clear(); +} + +bool DataBuffer::hasCompleteJson() const { + // For now, just check if buffer is not empty + // In a more sophisticated implementation, this would check for complete JSON objects + return !buffer_.empty(); +} + std::string DataBuffer::extractNextJson() { // TODO: // 1. Use findJsonBoundary() to locate a complete JSON object diff --git a/client/src/main.cpp b/client/src/main.cpp index 049fa83a..1cce7202 100644 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -5,7 +5,8 @@ #include "client/argparser.hpp" #include "client/message_model.hpp" #include "client/tcp_client.hpp" -#include "client/json_reader.hpp" +#include "client/DataBuffer.hpp" +#include "client/json_reader.hpp" #include using namespace std; @@ -35,8 +36,12 @@ class PanoramaClient : public wxApp { // --- Create model (shared between view and controller) --- model_ = std::make_shared(); + // --- Create DataBuffer (shared between TCP client and GUI) --- + dataBuffer_ = std::make_shared(); + // --- Create and start TCP client on separate thread --- - tcpClient_ = std::make_unique("127.0.0.1", 3000, model_); + // TODO: FIX 127.0.0.1:3000 to allow ESP32 to actually connect + tcpClient_ = std::make_unique("127.0.0.1", 3000, model_, dataBuffer_); tcpClient_->start(); // For running without a gui @@ -51,9 +56,10 @@ class PanoramaClient : public wxApp { } // --- Create view --- - MainFrame* w = new MainFrame("Panorama Client", model_); + MainFrame* w = new MainFrame("Panorama Client", model_, dataBuffer_); w->Show(); + // --- If test mode, quit after 3 seconds --- if (parser.isTestMode()) { wxTimer* timer = new wxTimer(this); @@ -77,6 +83,7 @@ class PanoramaClient : public wxApp { private: std::shared_ptr model_; + std::shared_ptr dataBuffer_; std::unique_ptr tcpClient_; }; diff --git a/client/src/mainframe.cpp b/client/src/mainframe.cpp index 4ff2536a..1222b36c 100644 --- a/client/src/mainframe.cpp +++ b/client/src/mainframe.cpp @@ -1,5 +1,6 @@ #include "client/mainframe.hpp" #include "client/message_model.hpp" +#include "client/DataBuffer.hpp" #include "client/graph_panel.hpp" #include "client/sensor_data_panel.h" #include "client/sensor_manager.hpp" @@ -7,8 +8,9 @@ #include MainFrame::MainFrame(const wxString& title, std::shared_ptr model, + std::shared_ptr dataBuffer, const wxPoint& pos, const wxSize& size) - : wxFrame(nullptr, wxID_ANY, title, pos, size), model_(model) { + : wxFrame(nullptr, wxID_ANY, title, pos, size), model_(model), dataBuffer_(dataBuffer) { // Create splitter for layout wxSplitterWindow* mainSplitter = new wxSplitterWindow(this, wxID_ANY); @@ -92,6 +94,13 @@ void MainFrame::updateMessageDisplay() { for (const auto& msg : messages) { text += wxString::FromUTF8(msg.c_str()) + "\n"; } + + if (dataBuffer_ && dataBuffer_->size() > 0) { + text += "\n--- DataBuffer Contents ---\n"; + text += wxString::FromUTF8(dataBuffer_->toStringAll().c_str()); + text += "--- End of DataBuffer ---\n"; + } + messageDisplay_->SetValue(text); messageDisplay_->SetInsertionPointEnd(); } \ No newline at end of file diff --git a/client/src/tcp_client.cpp b/client/src/tcp_client.cpp index 2f0a25ef..2a3c9e63 100644 --- a/client/src/tcp_client.cpp +++ b/client/src/tcp_client.cpp @@ -1,5 +1,6 @@ #include "client/tcp_client.hpp" #include "client/message_model.hpp" +#include "client/DataBuffer.hpp" #include "common/panorama_utils.hpp" #include #include @@ -24,8 +25,8 @@ #define SOCKET_ERROR -1 #endif -TcpClient::TcpClient(const std::string& host, int port, std::shared_ptr model) - : host_(host), port_(port), model_(model), running_(false), socket_(INVALID_SOCKET) { +TcpClient::TcpClient(const std::string& host, int port, std::shared_ptr model, std::shared_ptr dataBuffer) + : host_(host), port_(port), model_(model), dataBuffer_(dataBuffer), running_(false), socket_(INVALID_SOCKET) { #ifdef _WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); @@ -81,13 +82,13 @@ void TcpClient::run() { cleanup(); break; } - + buffer[bytesRead] = '\0'; std::string received(buffer); - - // print json - //pinfo("Received JSON: ", received); - reader.exportToBuffer(received); + + // Parse JSON and write to DataBuffer + buffer_data_t parsedData = reader.exportToBuffer(received); + dataBuffer_->writeData(parsedData); model_->addMessage("Received: " + received); } From 07f11ff9fde238e00e82561c854ffba10ac98c81 Mon Sep 17 00:00:00 2001 From: Henry van Weelderen Date: Sat, 24 Jan 2026 15:31:09 -0800 Subject: [PATCH 04/12] filling buffer data --- client/src/json_reader.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/json_reader.cpp b/client/src/json_reader.cpp index 7e265507..8aebe7e6 100644 --- a/client/src/json_reader.cpp +++ b/client/src/json_reader.cpp @@ -69,7 +69,13 @@ buffer_data_t JsonReader::exportToBuffer(std::string json) { double sensorValue = doc["value"].GetDouble(); std::cout << sensorTypeString << sensorValue << sensorUnitString << std::endl; - + if (sensorTypeString == "temperature") { + ret.a = 'a'; + ret.a_data = sensorValue; + } else { + ret.b_data = sensorValue; + ret.b = 'b'; + } return ret; From e024ecc08a9dade42f11ff91827c347d85b9a474 Mon Sep 17 00:00:00 2001 From: aexzhou Date: Tue, 27 Jan 2026 21:24:17 -0800 Subject: [PATCH 05/12] Added Debug function --- client/include/common/panorama_utils.hpp | 13 +++++++++--- client/src/DataBuffer.cpp | 26 ++++++++++++++++++++++-- tools/pserver/pserver.py | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/client/include/common/panorama_utils.hpp b/client/include/common/panorama_utils.hpp index 59a1e38d..e681404a 100644 --- a/client/include/common/panorama_utils.hpp +++ b/client/include/common/panorama_utils.hpp @@ -10,8 +10,8 @@ // #endif -#ifndef PANORAMA_UTILS_HPP -#define PANORAMA_UTILS_HPP +#ifndef __PANORAMA_UTILS_HPP__ +#define __PANORAMA_UTILS_HPP__ #include @@ -22,4 +22,11 @@ void pinfo(const Args&... args) { std::cout << std::endl; } -#endif // PANORAMA_UTILS_HPP +template +void pdebug(const Args&... args) { + std::cout << "[DEBUG][Client]\t"; + (std::cout << ... << args); // fold expression over operator<< + std::cout << std::endl; +} + +#endif // __PANORAMA_UTILS_HPP__ diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index 33777207..1642b293 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -1,4 +1,5 @@ #include "client/DataBuffer.hpp" +#include DataBuffer::DataBuffer() { // TODO: any initialization if needed @@ -11,7 +12,14 @@ void DataBuffer::writeData(buffer_data_t jsonChunk) { // Append the new chunk of raw JSON data to the buffer. This functions only job is to store raw // inbound data in a way that doesn't lose anything later the parser will call extractNextJson() // parseNextJson() + std::cout << "[DataBuffer] Writing data to buffer:" << std::endl; + std::cout << "[DataBuffer] a: '" << jsonChunk.a << "' a_data: " << jsonChunk.a_data << std::endl; + std::cout << "[DataBuffer] b: '" << jsonChunk.b << "' b_data: " << jsonChunk.b_data << std::endl; + std::cout << "[DataBuffer] Buffer size before write: " << size() << std::endl; + write(jsonChunk); + + std::cout << "[DataBuffer] Buffer size after write: " << size() << std::endl; } void DataBuffer::setData(buffer_data_t jsonData) { @@ -91,8 +99,22 @@ void DataBuffer::parseAll(/* std::vector &out */) { std::string DataBuffer::toString(const buffer_data_t& buffer_item) { //convert one struct of buffer_ into string std::string temp = "{"; - temp = temp + "\"" + buffer_item.a + "\": " + std::to_string(buffer_item.a_data) + ", "; - temp = temp + "\"" + buffer_item.b + "\": " + std::to_string(buffer_item.b_data); + + // + bool hasA = buffer_item.a != '\0'; + bool hasB = buffer_item.b != '\0'; + + if (hasA) { + temp = temp + "\"" + buffer_item.a + "\": " + std::to_string(buffer_item.a_data); + if (hasB) { + temp += ", "; + } + } + + if (hasB) { + temp = temp + "\"" + buffer_item.b + "\": " + std::to_string(buffer_item.b_data); + } + temp += "}"; return temp; } diff --git a/tools/pserver/pserver.py b/tools/pserver/pserver.py index 6560595e..3bf80d83 100644 --- a/tools/pserver/pserver.py +++ b/tools/pserver/pserver.py @@ -41,7 +41,7 @@ def send_stream(self, client_socket, client_address, streamer: PStreamer): def main(): host = '127.0.0.1' - port = 4000 + port = 3000 if len(sys.argv) > 1: port = int(sys.argv[1]) From 9e58122182cc28e368049e8414700c5d6e8629ce Mon Sep 17 00:00:00 2001 From: Henry van Weelderen Date: Sat, 31 Jan 2026 14:09:24 -0800 Subject: [PATCH 06/12] buffer changes - extract next and pop items - max buffer size --- client/include/client/DataBuffer.hpp | 2 +- client/include/client/buffer_base.hpp | 13 +++++++++++ client/src/DataBuffer.cpp | 31 ++++++++++++++++----------- client/src/json_reader.cpp | 2 +- client/src/mainframe.cpp | 7 +++--- client/src/tcp_client.cpp | 2 +- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/client/include/client/DataBuffer.hpp b/client/include/client/DataBuffer.hpp index efbeb22e..648fcb0b 100644 --- a/client/include/client/DataBuffer.hpp +++ b/client/include/client/DataBuffer.hpp @@ -49,7 +49,7 @@ class DataBuffer : public BufferBase { // Parse the next complete JSON object in the buffer. // Returns success/failure depending on whether parsing succeeded. // The parsed result can be returned as a variant, struct, or any user-defined type. - bool parseNextJson(/* ParsedData &out */); + std::string parseNextJson(/* ParsedData &out */); // Parse *all* complete JSON objects currently in the buffer. // Useful if the buffer contains multiple messages. diff --git a/client/include/client/buffer_base.hpp b/client/include/client/buffer_base.hpp index dfa079c2..b86cd131 100644 --- a/client/include/client/buffer_base.hpp +++ b/client/include/client/buffer_base.hpp @@ -25,6 +25,7 @@ class BufferBase { virtual void write(T data) { std::lock_guard lock(mutex_); buffer_.push_back(std::move(data)); + } /** @@ -57,6 +58,17 @@ class BufferBase { return result; } + // Returns the first element of the buffer and removes it from the buffer + virtual T extractNextBuffer() { + buffer_data_t ret = buffer_.front(); + buffer_.pop_front(); + return ret; + } + + virtual void popFront() { + buffer_.pop_front(); + } + /** * @brief Get the number of elements in the buffer * @return The number of elements @@ -86,4 +98,5 @@ class BufferBase { protected: std::list buffer_; mutable std::mutex mutex_; + int MAX_BUFFER_SIZE = 2; }; diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index 1642b293..1a9108c1 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -1,5 +1,6 @@ #include "client/DataBuffer.hpp" #include +#include DataBuffer::DataBuffer() { // TODO: any initialization if needed @@ -12,14 +13,18 @@ void DataBuffer::writeData(buffer_data_t jsonChunk) { // Append the new chunk of raw JSON data to the buffer. This functions only job is to store raw // inbound data in a way that doesn't lose anything later the parser will call extractNextJson() // parseNextJson() - std::cout << "[DataBuffer] Writing data to buffer:" << std::endl; - std::cout << "[DataBuffer] a: '" << jsonChunk.a << "' a_data: " << jsonChunk.a_data << std::endl; - std::cout << "[DataBuffer] b: '" << jsonChunk.b << "' b_data: " << jsonChunk.b_data << std::endl; - std::cout << "[DataBuffer] Buffer size before write: " << size() << std::endl; + // std::cout << "[DataBuffer] Writing data to buffer:" << std::endl; + // std::cout << "[DataBuffer] a: '" << jsonChunk.a << "' a_data: " << jsonChunk.a_data << std::endl; + // std::cout << "[DataBuffer] b: '" << jsonChunk.b << "' b_data: " << jsonChunk.b_data << std::endl; + // std::cout << "[DataBuffer] Buffer size before write: " << size() << std::endl; write(jsonChunk); - - std::cout << "[DataBuffer] Buffer size after write: " << size() << std::endl; + if (size() >= MAX_BUFFER_SIZE) { + popFront(); + } + // std::cout << "[DataBuffer] Buffer size after write: " << size() << std::endl; + // std::cout << buffer_.size(); + // std::cout << "[DataBuffer] : " << toStringAll() << std::endl; } void DataBuffer::setData(buffer_data_t jsonData) { @@ -56,7 +61,7 @@ std::string DataBuffer::extractNextJson() { // 1. Use findJsonBoundary() to locate a complete JSON object // 2. Extract it from buffer_ // 3. Remove extracted substring from buffer_ - return {}; + return toString(extractNextBuffer()); } size_t DataBuffer::findJsonBoundary() const { @@ -80,13 +85,13 @@ bool DataBuffer::decodeJson(const std::string& jsonStr /*, ParsedData &out */) { return false; } -bool DataBuffer::parseNextJson(/* ParsedData &out */) { +std::string DataBuffer::parseNextJson(/* ParsedData &out */) { // TODO: // 1. Use extractNextJson() to get next complete object // 2. Validate using isValidJson() // 3. Decode using decodeJson() // 4. Return true if parsed successfully - return false; + return ""; } void DataBuffer::parseAll(/* std::vector &out */) { @@ -105,14 +110,14 @@ std::string DataBuffer::toString(const buffer_data_t& buffer_item) { bool hasB = buffer_item.b != '\0'; if (hasA) { - temp = temp + "\"" + buffer_item.a + "\": " + std::to_string(buffer_item.a_data); + temp = temp + "\"" + std::to_string(buffer_item.a) + "\": " + std::to_string(buffer_item.a_data); if (hasB) { temp += ", "; } } if (hasB) { - temp = temp + "\"" + buffer_item.b + "\": " + std::to_string(buffer_item.b_data); + temp = temp + "\"" + std::to_string(buffer_item.b) + "\": " + std::to_string(buffer_item.b_data); } temp += "}"; @@ -123,8 +128,8 @@ std::string DataBuffer::toStringAll() { //print all buffer_ as string //buffer_ is an array of buffer_data_t std::string res = ""; - - for (buffer_data_t buffer_item : buffer_) { + + for (buffer_data_t buffer_item : readAll()) { res += toString(buffer_item) + ",\n"; } return res; diff --git a/client/src/json_reader.cpp b/client/src/json_reader.cpp index 8aebe7e6..c6973e02 100644 --- a/client/src/json_reader.cpp +++ b/client/src/json_reader.cpp @@ -68,7 +68,7 @@ buffer_data_t JsonReader::exportToBuffer(std::string json) { double sensorValue = doc["value"].GetDouble(); - std::cout << sensorTypeString << sensorValue << sensorUnitString << std::endl; + // std::cout << sensorTypeString << sensorValue << sensorUnitString << std::endl; if (sensorTypeString == "temperature") { ret.a = 'a'; ret.a_data = sensorValue; diff --git a/client/src/mainframe.cpp b/client/src/mainframe.cpp index 1222b36c..79c24520 100644 --- a/client/src/mainframe.cpp +++ b/client/src/mainframe.cpp @@ -94,10 +94,11 @@ void MainFrame::updateMessageDisplay() { for (const auto& msg : messages) { text += wxString::FromUTF8(msg.c_str()) + "\n"; } - - if (dataBuffer_ && dataBuffer_->size() > 0) { + + if (dataBuffer_->size() > 0) { + std::cout << dataBuffer_->toStringAll(); text += "\n--- DataBuffer Contents ---\n"; - text += wxString::FromUTF8(dataBuffer_->toStringAll().c_str()); + text += wxString::FromUTF8(dataBuffer_->toStringAll()); text += "--- End of DataBuffer ---\n"; } diff --git a/client/src/tcp_client.cpp b/client/src/tcp_client.cpp index 2a3c9e63..98e081a0 100644 --- a/client/src/tcp_client.cpp +++ b/client/src/tcp_client.cpp @@ -89,7 +89,7 @@ void TcpClient::run() { // Parse JSON and write to DataBuffer buffer_data_t parsedData = reader.exportToBuffer(received); dataBuffer_->writeData(parsedData); - + model_->addMessage("Data" + std::to_string(dataBuffer_->size())); model_->addMessage("Received: " + received); } } From 37b367200811b9593a8604b9d7344d15d8a8e334 Mon Sep 17 00:00:00 2001 From: Henry van Weelderen Date: Sat, 31 Jan 2026 15:01:20 -0800 Subject: [PATCH 07/12] beginning implementation of new buffer struct --- client/include/client/DataBuffer.hpp | 3 +++ client/include/client/buffer_base.hpp | 2 +- client/include/common/panorama_defines.hpp | 10 +++++--- client/src/DataBuffer.cpp | 29 +++++++++++++++++++--- client/src/mainframe.cpp | 2 +- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/client/include/client/DataBuffer.hpp b/client/include/client/DataBuffer.hpp index 648fcb0b..e05935fb 100644 --- a/client/include/client/DataBuffer.hpp +++ b/client/include/client/DataBuffer.hpp @@ -37,6 +37,7 @@ class DataBuffer : public BufferBase { // Clear the buffer void clear(); + // Extract the next complete JSON object from buffer // Removes extracted portion from buffer std::string extractNextJson(); @@ -59,6 +60,8 @@ class DataBuffer : public BufferBase { std::string toStringAll(); + void exportBuffer(); + private: // Raw buffer storing incoming data std::list buffer_; diff --git a/client/include/client/buffer_base.hpp b/client/include/client/buffer_base.hpp index b86cd131..d50ea151 100644 --- a/client/include/client/buffer_base.hpp +++ b/client/include/client/buffer_base.hpp @@ -98,5 +98,5 @@ class BufferBase { protected: std::list buffer_; mutable std::mutex mutex_; - int MAX_BUFFER_SIZE = 2; + int MAX_BUFFER_SIZE = 5; }; diff --git a/client/include/common/panorama_defines.hpp b/client/include/common/panorama_defines.hpp index 384710f0..2af0d78a 100644 --- a/client/include/common/panorama_defines.hpp +++ b/client/include/common/panorama_defines.hpp @@ -1,8 +1,10 @@ #pragma once +#include typedef struct { - char a; - float a_data; - char b; - float b_data; + float data; + char datatype; + std::time_t timestamp; + char dataunit; + } buffer_data_t; \ No newline at end of file diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index 1a9108c1..bc3074db 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -19,8 +19,9 @@ void DataBuffer::writeData(buffer_data_t jsonChunk) { // std::cout << "[DataBuffer] Buffer size before write: " << size() << std::endl; write(jsonChunk); - if (size() >= MAX_BUFFER_SIZE) { + if (size() > MAX_BUFFER_SIZE) { popFront(); + exportBuffer(); } // std::cout << "[DataBuffer] Buffer size after write: " << size() << std::endl; // std::cout << buffer_.size(); @@ -128,9 +129,31 @@ std::string DataBuffer::toStringAll() { //print all buffer_ as string //buffer_ is an array of buffer_data_t std::string res = ""; - + int c = 0; for (buffer_data_t buffer_item : readAll()) { - res += toString(buffer_item) + ",\n"; + if (c == size() - 1) { + res += toString(buffer_item) + "\n"; + } else { + res += toString(buffer_item) + ",\n"; + } + + c++; } + return res; } + +void DataBuffer::exportBuffer() { + //Export the entire buffer (make a local JSON file under client/src/) + FILE* fp = fopen("./example.json", "w"); + if (!fp) { + std::cerr << "Could not open file for writing exported buffer." << std::endl; + return; + } + + std::string json_content = "[\n" + toStringAll() + "]"; + //std::cout << "JSON CONTENT: " << json_content << std::endl; + fputs(json_content.c_str(), fp); + fclose(fp); + return; +} \ No newline at end of file diff --git a/client/src/mainframe.cpp b/client/src/mainframe.cpp index 79c24520..f2b31471 100644 --- a/client/src/mainframe.cpp +++ b/client/src/mainframe.cpp @@ -96,7 +96,7 @@ void MainFrame::updateMessageDisplay() { } if (dataBuffer_->size() > 0) { - std::cout << dataBuffer_->toStringAll(); + //std::cout << dataBuffer_->toStringAll(); text += "\n--- DataBuffer Contents ---\n"; text += wxString::FromUTF8(dataBuffer_->toStringAll()); text += "--- End of DataBuffer ---\n"; From 1f9d0bab7ebfce6447194fefd761006927823e46 Mon Sep 17 00:00:00 2001 From: Alex Zhou Date: Sat, 31 Jan 2026 15:13:14 -0800 Subject: [PATCH 08/12] Fixed merge issues from merging main branch in --- client/src/tcp_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/tcp_client.cpp b/client/src/tcp_client.cpp index d02e32dd..df5d45c4 100644 --- a/client/src/tcp_client.cpp +++ b/client/src/tcp_client.cpp @@ -26,7 +26,7 @@ #define SOCKET_ERROR -1 #endif -TcpClient::TcpClient(const std::string& host, int port, std::shared_ptr model, std::shared_ptr logger, std::shared_ptr dataBuffer) +TcpClient::TcpClient(const std::string& host, int port, std::shared_ptr model, std::shared_ptr dataBuffer, std::shared_ptr logger) : host_(host), port_(port), model_(model), logger_(logger), dataBuffer_(dataBuffer), running_(false), socket_(INVALID_SOCKET) { #ifdef _WIN32 WSADATA wsaData; From 96c0e5f161607b699b041c24adcac414c568fee3 Mon Sep 17 00:00:00 2001 From: Henry van Weelderen Date: Sat, 31 Jan 2026 15:24:39 -0800 Subject: [PATCH 09/12] changes to struct implemented partly --- client/include/common/panorama_defines.hpp | 8 +++---- client/src/DataBuffer.cpp | 26 +++++++++++----------- client/src/json_reader.cpp | 16 +++++-------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/client/include/common/panorama_defines.hpp b/client/include/common/panorama_defines.hpp index 2af0d78a..82fa6b44 100644 --- a/client/include/common/panorama_defines.hpp +++ b/client/include/common/panorama_defines.hpp @@ -2,9 +2,9 @@ #include typedef struct { - float data; - char datatype; - std::time_t timestamp; - char dataunit; + float data; // actual value + std::time_t timestamp; // date recorded + const char * dataunit; // e.g. "kPa", "mL" + const char * datatype; // e.g. "temperature", "sound" } buffer_data_t; \ No newline at end of file diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index bc3074db..5ae6086f 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -107,19 +107,19 @@ std::string DataBuffer::toString(const buffer_data_t& buffer_item) { std::string temp = "{"; // - bool hasA = buffer_item.a != '\0'; - bool hasB = buffer_item.b != '\0'; - - if (hasA) { - temp = temp + "\"" + std::to_string(buffer_item.a) + "\": " + std::to_string(buffer_item.a_data); - if (hasB) { - temp += ", "; - } - } - - if (hasB) { - temp = temp + "\"" + std::to_string(buffer_item.b) + "\": " + std::to_string(buffer_item.b_data); - } + // bool hasA = buffer_item.a != '\0'; + // bool hasB = buffer_item.b != '\0'; + + // if (hasA) { + // temp = temp + "\"" + std::to_string(buffer_item.a) + "\": " + std::to_string(buffer_item.a_data); + // if (hasB) { + // temp += ", "; + // } + // } + + // if (hasB) { + // temp = temp + "\"" + std::to_string(buffer_item.b) + "\": " + std::to_string(buffer_item.b_data); + // } temp += "}"; return temp; diff --git a/client/src/json_reader.cpp b/client/src/json_reader.cpp index c6973e02..40fb9672 100644 --- a/client/src/json_reader.cpp +++ b/client/src/json_reader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include JsonReader::JsonReader() {} @@ -65,17 +66,12 @@ buffer_data_t JsonReader::exportToBuffer(std::string json) { doc["unit"].GetString(), doc["unit"].GetStringLength() ); - double sensorValue = doc["value"].GetDouble(); - - // std::cout << sensorTypeString << sensorValue << sensorUnitString << std::endl; - if (sensorTypeString == "temperature") { - ret.a = 'a'; - ret.a_data = sensorValue; - } else { - ret.b_data = sensorValue; - ret.b = 'b'; - } + + ret.datatype = sensorTypeString.c_str(); + ret.data = sensorValue; + ret.dataunit = sensorUnitString.c_str(); + ret.timestamp = std::time(&ret.timestamp); return ret; From 67b710116d8d43a11493930732bba9d63ccaee0a Mon Sep 17 00:00:00 2001 From: Alex Zhou Date: Sat, 31 Jan 2026 15:39:57 -0800 Subject: [PATCH 10/12] Fixed uninitialized databuffer pointer --- client/src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/main.cpp b/client/src/main.cpp index ba32cd15..f67f562b 100644 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -131,6 +131,9 @@ class PanoramaClient : public wxApp { std::cerr << "Warning: Data logger failed to initialize. Data will not be persisted." << std::endl; } + // --- Create DataBuffer --- + dataBuffer_ = std::make_shared(); + // --- Create and start TCP client on separate thread --- tcpClient_ = std::make_unique("127.0.0.1", 3000, model_, dataBuffer_, dataLogger_); tcpClient_->start(); From 9676dd7bdc46803d1cd7ea56313711602ca6f18a Mon Sep 17 00:00:00 2001 From: annhypen Date: Sat, 31 Jan 2026 15:48:00 -0800 Subject: [PATCH 11/12] changed toString() in DataBuffer.cpp --- client/src/DataBuffer.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index 5ae6086f..5d9a4273 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -102,26 +102,23 @@ void DataBuffer::parseAll(/* std::vector &out */) { // parseNextJson(...) } + std::string DataBuffer::toString(const buffer_data_t& buffer_item) { //convert one struct of buffer_ into string - std::string temp = "{"; + bool hasUnit = buffer_item.dataunit != '\0'; - // - // bool hasA = buffer_item.a != '\0'; - // bool hasB = buffer_item.b != '\0'; + std::string temp = "{"; - // if (hasA) { - // temp = temp + "\"" + std::to_string(buffer_item.a) + "\": " + std::to_string(buffer_item.a_data); - // if (hasB) { - // temp += ", "; - // } - // } + temp = temp + "\"datatype\": \"" + buffer_item.datatype + "\", \"data\": " + std::to_string(buffer_item.data) + ", "; - // if (hasB) { - // temp = temp + "\"" + std::to_string(buffer_item.b) + "\": " + std::to_string(buffer_item.b_data); - // } + if (hasUnit) { + temp = temp + "\"dataunit\": \"" + buffer_item.dataunit + "\", "; + } + + temp = temp + "\"timestamp\": " + std::to_string(buffer_item.timestamp); temp += "}"; + return temp; } From 56875183b4c5ec463223d91c11e268c61a2476b2 Mon Sep 17 00:00:00 2001 From: Alex Zhou Date: Sat, 7 Feb 2026 12:03:14 -0800 Subject: [PATCH 12/12] Fix databuffer comparison logic error --- client/src/DataBuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/DataBuffer.cpp b/client/src/DataBuffer.cpp index 5d9a4273..a5409ae5 100644 --- a/client/src/DataBuffer.cpp +++ b/client/src/DataBuffer.cpp @@ -1,3 +1,4 @@ + #include "client/DataBuffer.hpp" #include #include @@ -105,7 +106,7 @@ void DataBuffer::parseAll(/* std::vector &out */) { std::string DataBuffer::toString(const buffer_data_t& buffer_item) { //convert one struct of buffer_ into string - bool hasUnit = buffer_item.dataunit != '\0'; + bool hasUnit = buffer_item.dataunit != nullptr && buffer_item.dataunit[0] != '\0'; std::string temp = "{";