From cdcfc6320697dabb396e889671751acd64a3e904 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 01:29:33 +0000 Subject: [PATCH 1/3] Initial plan From 7db82a503bd0481b6df283810dde8bea6698c1c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 01:51:07 +0000 Subject: [PATCH 2/3] docs: fix documentation accuracy, broken imports, and API references Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- README.md | 42 ++++++++------- .../docs/basic-usage/framing-details.mdx | 51 ++++++++++--------- docs/src/content/docs/basic-usage/framing.mdx | 19 ++++--- .../docs/basic-usage/language-examples.mdx | 31 +++++++---- .../content/docs/extended-features/cpp-sdk.md | 42 +++++++-------- .../extended-features/custom-features.mdx | 26 ++++++---- .../docs/extended-features/python-sdk.md | 46 +++++++++-------- .../docs/getting-started/installation.md | 2 +- .../docs/getting-started/quick-start.md | 2 +- docs/src/content/docs/index.mdx | 2 +- .../content/docs/reference/cli-reference.md | 4 +- .../src/content/docs/reference/development.md | 4 +- docs/src/content/docs/reference/testing.md | 2 +- 13 files changed, 147 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index 065dc745..e4a20d49 100644 --- a/README.md +++ b/README.md @@ -138,9 +138,7 @@ Frame: [0x90] [0x71] [0x04] [0x2A] [0x01, 0x02, 0x03, 0x04] [0x7F] [0x8A] | Seq | `[SEQ] [LEN] [MSG_ID] [PACKET] [CRC]` | 5 | Packet loss detection | | MultiSystemStream | `[SEQ] [SYS] [COMP] [LEN] [MSG_ID] [PACKET] [CRC]` | 7 | Multi-vehicle streaming | -See [Framing Documentation](docs/framing.md) for the complete frame format reference. - -### Parser State Machine +See [Framing Documentation](https://struct-frame.mylonics.com/basic-usage/framing/) for the complete frame format reference. The frame parser implements a state machine to handle partial data and synchronization recovery: @@ -189,7 +187,7 @@ gcc examples/main.c -I generated/c -o main #### C++ ```bash python -m struct_frame examples/myl_vehicle.proto --build_cpp -g++ -std=c++17 examples/main.cpp -I generated/cpp -o main +g++ -std=c++20 examples/main.cpp -I generated/cpp -o main ./main ``` @@ -203,15 +201,15 @@ python -m struct_frame examples/myl_vehicle.proto --build_gql | Feature | C | C++ | TypeScript | Python | C# | GraphQL | Status | |---------|---|-----|------------|--------|----|---------|--------| -| **Core Types** | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | Stable | -| **String** | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | Stable | -| **Enums** | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | Stable | -| **Enum Classes** | N/A | ✓ | N/A | N/A | ✗ | N/A | Stable | -| **Nested Messages** | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | Stable | -| **Message IDs** | ✓ | ✓ | ✓ | ✓ | ✗ | N/A | Stable | -| **Message Serialization** | ✓ | ✓ | ✓ | ✓ | ✗ | N/A | Stable | -| **Flatten** | N/A | N/A | N/A | ✓ | ✗ | ✓ | Partial | -| **Arrays** | ✓ | ✓ | Partial | ✓ | ✗ | ✓ | Stable | +| **Core Types** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | +| **String** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | +| **Enums** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | +| **Enum Classes** | N/A | ✓ | N/A | N/A | N/A | N/A | Stable | +| **Nested Messages** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | +| **Message IDs** | ✓ | ✓ | ✓ | ✓ | ✓ | N/A | Stable | +| **Message Serialization** | ✓ | ✓ | ✓ | ✓ | ✓ | N/A | Stable | +| **Flatten** | N/A | N/A | N/A | ✓ | N/A | ✓ | Partial | +| **Arrays** | ✓ | ✓ | Partial | ✓ | ✓ | ✓ | Stable | **Legend:** - **✓** - Feature works as documented @@ -279,14 +277,14 @@ message SimpleHeartbeat { | Feature | C | C++ | TypeScript | Python | C# | Status | Notes | |---------|---|-----|------------|--------|----|---------|-------| -| **Frame Encoding** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | All languages can create frames | -| **Frame Parsing** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | State machine implementation | -| **Checksum Validation** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | Fletcher-16 algorithm | -| **Sync Recovery** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | Auto-recovery from corruption | -| **Partial Frame Handling** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | Handles chunked data streams | -| **Message ID Routing** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | Automatic message type detection | -| **Buffer Management** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | Fixed-size buffers prevent overflow | -| **Cross-Language Compatibility** | ✓ | ✓ | ✓ | ✓ | ✗ | Stable | Frames interoperate between languages | +| **Frame Encoding** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | All languages can create frames | +| **Frame Parsing** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | State machine implementation | +| **Checksum Validation** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | Fletcher-16 algorithm | +| **Sync Recovery** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | Auto-recovery from corruption | +| **Partial Frame Handling** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | Handles chunked data streams | +| **Message ID Routing** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | Automatic message type detection | +| **Buffer Management** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | Fixed-size buffers prevent overflow | +| **Cross-Language Compatibility** | ✓ | ✓ | ✓ | ✓ | ✓ | Stable | Frames interoperate between languages | ### Extended Frame Format Options @@ -304,7 +302,7 @@ Struct Frame supports multiple frame types and payload types for different use c - **SysComp**: System/Component IDs for multi-vehicle networks (MAVLink-style) - **MultiSystemStream**: Sequence + SysComp for streaming with loss detection -See [Framing Documentation](docs/framing.md) for the complete format reference. +See [Framing Documentation](https://struct-frame.mylonics.com/basic-usage/framing/) for the complete format reference. ## Frame Format Examples and Usage diff --git a/docs/src/content/docs/basic-usage/framing-details.mdx b/docs/src/content/docs/basic-usage/framing-details.mdx index 8ff7373b..4771423f 100644 --- a/docs/src/content/docs/basic-usage/framing-details.mdx +++ b/docs/src/content/docs/basic-usage/framing-details.mdx @@ -107,7 +107,7 @@ For Minimal payloads, the parser requires a message length callback to determine ## Usage in C++ ```cpp -#include "FrameProfiles.hpp" +#include "frame_profiles.hpp" using namespace FrameParsers; @@ -137,27 +137,31 @@ while (auto result = reader.next()) { ## Usage in Python ```python -from struct_frame_parser import Parser, HeaderType, PayloadType - -# Create parser with specific frame types -parser = Parser( - enabled_headers=[HeaderType.BASIC, HeaderType.TINY], - enabled_payloads=[PayloadType.DEFAULT, PayloadType.EXTENDED] +from frame_profiles import ( + ProfileStandardWriter, + ProfileStandardAccumulatingReader, ) +from struct_frame.generated.messages import MyMessage, get_message_info # Encode -frame = parser.encode( - msg_id=42, - msg=b"payload data", - header_type=HeaderType.BASIC, - payload_type=PayloadType.DEFAULT -) - -# Decode (byte-by-byte) -for byte in incoming_data: - result = parser.parse_byte(byte) - if result.valid: +msg = MyMessage(value=42) +writer = ProfileStandardWriter(1024) +writer.write(msg) +frame = writer.data() + +# Decode (byte-by-byte streaming) +reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) +for byte in frame: + result = reader.push_byte(byte) + if result and result.valid: handle_message(result) + +# Decode (buffer mode) +reader2 = ProfileStandardAccumulatingReader(get_message_info=get_message_info) +reader2.add_data(frame) +result = reader2.next() +if result and result.valid: + handle_message(result) ``` ## Custom Profiles @@ -182,13 +186,12 @@ Create custom frame formats by combining header and payload types: ```python - from struct_frame_parser import create_custom_profile, HeaderType, PayloadType + from frame_profiles import ProfileConfig, HEADER_TINY_CONFIG, PAYLOAD_EXTENDED_CONFIG + from frame_profiles import BufferWriter, AccumulatingReader - custom = create_custom_profile( - "TinyExtended", - HeaderType.TINY, - PayloadType.EXTENDED - ) + custom_config = ProfileConfig(HEADER_TINY_CONFIG, PAYLOAD_EXTENDED_CONFIG, name="TinyExtended") + writer = BufferWriter(custom_config, 1024) + reader = AccumulatingReader(custom_config) ``` diff --git a/docs/src/content/docs/basic-usage/framing.mdx b/docs/src/content/docs/basic-usage/framing.mdx index 6219e8a0..e8b6b241 100644 --- a/docs/src/content/docs/basic-usage/framing.mdx +++ b/docs/src/content/docs/basic-usage/framing.mdx @@ -61,17 +61,20 @@ The Standard profile (recommended for most uses): ```python - from struct_frame_parser import Parser, HeaderType, PayloadType - - parser = Parser() + from frame_profiles import ProfileStandardWriter, ProfileStandardAccumulatingReader + from struct_frame.generated.messages import MyMessage, get_message_info # Encode - frame = parser.encode_basic(msg_id=42, msg=b"data") + msg = MyMessage(value=42) + writer = ProfileStandardWriter(1024) + writer.write(msg) + frame = writer.data() # Decode + reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) for byte in frame: - result = parser.parse_byte(byte) - if result.valid: + result = reader.push_byte(byte) + if result and result.valid: print(f"Message {result.msg_id}: {result.msg_data}") ``` @@ -80,9 +83,9 @@ The Standard profile (recommended for most uses): ```cpp - #include "FrameProfiles.hpp" + #include "frame_profiles.hpp" - using namespace StructFrame; + using namespace FrameParsers; // Encode uint8_t buffer[1024]; diff --git a/docs/src/content/docs/basic-usage/language-examples.mdx b/docs/src/content/docs/basic-usage/language-examples.mdx index 5c68a3f4..f3c400e7 100644 --- a/docs/src/content/docs/basic-usage/language-examples.mdx +++ b/docs/src/content/docs/basic-usage/language-examples.mdx @@ -33,8 +33,12 @@ Frame profiles provide complete framing and parsing functionality. This is the * ### Python with Profiles ```python -from generated.example import ExampleStatus -from generated.frame_profiles import ( +# Add py_path to sys.path before importing +import sys +sys.path.insert(0, 'generated/') # py_path + +from struct_frame.generated.example import ExampleStatus, get_message_info +from frame_profiles import ( ProfileStandardWriter, ProfileStandardAccumulatingReader ) @@ -48,12 +52,12 @@ bytes_written = writer.write(msg) frame_data = writer.data() # Parse received frames -reader = ProfileStandardAccumulatingReader() +reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) reader.add_data(frame_data) # Deserialize using FrameMsgInfo result = reader.next() -if result: +if result and result.valid: decoded_msg = ExampleStatus.deserialize(result) # Pass FrameMsgInfo directly print(f"ID: {decoded_msg.id}, Value: {decoded_msg.value}") ``` @@ -93,7 +97,7 @@ if (result) { ```cpp #include "example.structframe.hpp" -#include "FrameProfiles.hpp" +#include "frame_profiles.hpp" // Create and serialize a message ExampleStatus msg; @@ -183,7 +187,11 @@ For cases where you need direct access to message bytes without framing: ### Python ```python -from generated.example import ExampleStatus +# Add py_path to sys.path before importing +import sys +sys.path.insert(0, 'generated/') # py_path + +from struct_frame.generated.example import ExampleStatus # Create a message msg = ExampleStatus(id=42, value=3.14) @@ -301,13 +309,16 @@ class Program { ### Serial Communication (Python) ```python +import sys import serial -from generated.example import ExampleStatus -from generated.frame_profiles import ProfileStandardAccumulatingReader +sys.path.insert(0, 'generated/') # py_path + +from struct_frame.generated.example import ExampleStatus, get_message_info +from frame_profiles import ProfileStandardAccumulatingReader # Setup serial connection ser = serial.Serial('/dev/ttyUSB0', 115200) -reader = ProfileStandardAccumulatingReader() +reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) while True: if ser.in_waiting: @@ -330,7 +341,7 @@ while True: ```cpp #include "example.structframe.hpp" -#include "FrameProfiles.hpp" +#include "frame_profiles.hpp" // Byte-by-byte streaming parser for UART/serial FrameParsers::ProfileStandardAccumulatingReader reader; diff --git a/docs/src/content/docs/extended-features/cpp-sdk.md b/docs/src/content/docs/extended-features/cpp-sdk.md index a47e3d14..06d0aefe 100644 --- a/docs/src/content/docs/extended-features/cpp-sdk.md +++ b/docs/src/content/docs/extended-features/cpp-sdk.md @@ -25,25 +25,29 @@ Minimal footprint for embedded systems. Serial transport only. ## Observer Pattern -Subscribe to messages using function pointers: +Subscribe to messages using function pointers or lambdas: ```cpp #include "struct_frame_sdk/sdk_embedded.hpp" -#include "messages.sf.hpp" +#include "messages.structframe.hpp" void handle_status(const StatusMessage& msg, uint8_t msgId) { std::cout << "Status: " << msg.value << std::endl; } int main() { - // Create SDK - StructFrame::SDK sdk; - - // Subscribe to messages - sdk.subscribe(handle_status); - - // Process incoming data - sdk.process_byte(byte); + // Create SDK with transport and frame parser + StructFrame::StructFrameSdkConfig config{ + .transport = &my_transport, + .frameParser = &my_frame_parser, + }; + StructFrame::StructFrameSdk sdk(config); + + // Subscribe to messages by message ID + sdk.subscribe(StatusMessage::MSG_ID, handle_status); + + // Connect the transport (incoming data is handled via callbacks) + sdk.connect(); } ``` @@ -52,39 +56,29 @@ int main() { ### Serial ```cpp -#include "struct_frame_sdk/transports/serial.hpp" +#include "struct_frame_sdk/serial_transport.hpp" StructFrame::SerialTransport serial("/dev/ttyUSB0", 115200); serial.connect(); serial.send(message_id, data, size); ``` -### UDP +### Network (UDP, TCP, WebSocket) ```cpp -#include "struct_frame_sdk/transports/udp.hpp" +#include "struct_frame_sdk/network_transports.hpp" StructFrame::UDPTransport udp("192.168.1.100", 8080); udp.connect(); udp.send(message_id, data, size); ``` -### TCP - -```cpp -#include "struct_frame_sdk/transports/tcp.hpp" - -StructFrame::TCPTransport tcp("192.168.1.100", 8080); -tcp.connect(); -tcp.send(message_id, data, size); -``` - ## Frame Profiles Use predefined frame profiles: ```cpp -#include "FrameProfiles.hpp" +#include "frame_profiles.hpp" using namespace FrameParsers; diff --git a/docs/src/content/docs/extended-features/custom-features.mdx b/docs/src/content/docs/extended-features/custom-features.mdx index 39b08c21..13b6fd43 100644 --- a/docs/src/content/docs/extended-features/custom-features.mdx +++ b/docs/src/content/docs/extended-features/custom-features.mdx @@ -37,14 +37,18 @@ The generator creates a `get_msg_info` function automatically: ```python - from struct_frame.frame_profiles import get_profile, Profile - from messages import get_msg_info - - # Get minimal profile - profile = get_profile(Profile.SENSOR) # TinyMinimal - - # Parser uses auto-generated get_msg_info - parser = profile.create_parser(get_msg_info) + from frame_profiles import ProfileSensorWriter, ProfileSensorAccumulatingReader + from struct_frame.generated.messages import get_message_info + + # Encode using sensor profile (Tiny + Minimal) + writer = ProfileSensorWriter(1024) + writer.write(msg) + frame = writer.data() + + # Parser requires get_message_info callback for minimal profiles + reader = ProfileSensorAccumulatingReader(get_message_info=get_message_info) + reader.add_data(frame) + result = reader.next() ``` @@ -52,11 +56,11 @@ The generator creates a `get_msg_info` function automatically: ```cpp - #include "FrameProfiles.hpp" + #include "frame_profiles.hpp" #include "messages.structframe.hpp" - // Use sensor profile with minimal frames - ProfileSensorAccumulatingReader reader(get_msg_info); + // Use sensor profile with minimal frames (requires message info callback) + ProfileSensorAccumulatingReader reader(get_message_info); ``` diff --git a/docs/src/content/docs/extended-features/python-sdk.md b/docs/src/content/docs/extended-features/python-sdk.md index c9f7ec9c..70376f47 100644 --- a/docs/src/content/docs/extended-features/python-sdk.md +++ b/docs/src/content/docs/extended-features/python-sdk.md @@ -16,38 +16,44 @@ python -m struct_frame messages.proto --build_py --py_path generated/ --sdk ## Parser Usage ```python -from struct_frame_parser import Parser, HeaderType, PayloadType -from messages_sf import Status - -# Create parser -parser = Parser() +from frame_profiles import ProfileStandardWriter, ProfileStandardAccumulatingReader +from struct_frame.generated.messages import Status, get_message_info # Encode -frame = parser.encode_basic(msg_id=1, msg=Status(value=42).to_bytes()) +msg = Status(value=42) +writer = ProfileStandardWriter(1024) +writer.write(msg) +frame = writer.data() # Decode +reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) for byte in frame: - result = parser.parse_byte(byte) - if result.valid: - msg = Status.from_bytes(result.msg_data) - print(f"Status: {msg.value}") + result = reader.push_byte(byte) + if result and result.valid: + decoded = Status.deserialize(result) + print(f"Status: {decoded.value}") ``` ## Message Router ```python -from struct_frame_sdk import MessageRouter -from messages_sf import Status - -router = MessageRouter() - -# Subscribe to messages -@router.subscribe(Status) -def handle_status(msg: Status): +from struct_frame_sdk.struct_frame_sdk import StructFrameSdk, StructFrameSdkConfig +from struct_frame_sdk.tcp_transport import TcpTransport +from struct_frame.generated.messages import Status + +# Configure SDK with transport +config = StructFrameSdkConfig( + transport=TcpTransport('192.168.1.100', 8080), + frame_parser=... # frame parser instance +) +sdk = StructFrameSdk(config) + +# Subscribe to messages by ID +def handle_status(msg: Status, msg_id: int): print(f"Status: {msg.value}") -# Process incoming data -router.process_byte(byte) +sdk.subscribe(Status.msg_id, handle_status) +sdk.connect() ``` ## Transports diff --git a/docs/src/content/docs/getting-started/installation.md b/docs/src/content/docs/getting-started/installation.md index 15d6afe3..27805555 100644 --- a/docs/src/content/docs/getting-started/installation.md +++ b/docs/src/content/docs/getting-started/installation.md @@ -20,7 +20,7 @@ python -m struct_frame --help Depending on which languages you plan to use: - **C**: GCC or compatible C compiler -- **C++**: G++ with C++17 support or later +- **C++**: G++ with C++20 support or later - **TypeScript/JavaScript**: Node.js and npm - **Python**: Python 3.8 or later (already required for code generation) - **C#**: .NET SDK diff --git a/docs/src/content/docs/getting-started/quick-start.md b/docs/src/content/docs/getting-started/quick-start.md index 91d50c6f..a0e4424c 100644 --- a/docs/src/content/docs/getting-started/quick-start.md +++ b/docs/src/content/docs/getting-started/quick-start.md @@ -62,7 +62,7 @@ int main() { Compile and run: ```bash -g++ -std=c++17 -I generated/ main.cpp -o main +g++ -std=c++20 -I generated/ main.cpp -o main ./main ``` diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index fc677b82..6149f226 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -94,7 +94,7 @@ python -m struct_frame status.proto --build_c --build_py --build_ts msg = ExampleStatus(id=42, value=3.14) # Serialize to bytes - data = msg.pack() + data = msg.serialize() ``` diff --git a/docs/src/content/docs/reference/cli-reference.md b/docs/src/content/docs/reference/cli-reference.md index 13f576e7..2e4a751c 100644 --- a/docs/src/content/docs/reference/cli-reference.md +++ b/docs/src/content/docs/reference/cli-reference.md @@ -56,6 +56,8 @@ python -m struct_frame [proto_file] [options] | `--force` | Force regeneration even if hash matches previous generation | | `--hash_path PATH` | Path to store the generation hash file | | `--generate_tests` | Generate test code with dummy values for round-trip verification | +| `--validate` | Validate the proto file without generating code | +| `--debug` | Enable debug output during code generation | ## Examples @@ -93,7 +95,7 @@ python -m struct_frame messages.proto --build_cpp --sdk ### TypeScript - `.structframe.ts` - Message definitions and classes - Frame utilities (frame-base.ts, frame-headers.ts, frame-profiles.ts, etc.) -- `struct_frame_sdk/` - SDK files (if `--sdk` used) +- `struct-frame-sdk/` - SDK files (if `--sdk` used) ### Python - `struct_frame/generated/.py` - Message definitions and classes diff --git a/docs/src/content/docs/reference/development.md b/docs/src/content/docs/reference/development.md index 4e9fd96b..3aaf4312 100644 --- a/docs/src/content/docs/reference/development.md +++ b/docs/src/content/docs/reference/development.md @@ -110,10 +110,10 @@ PYTHONPATH=src python src/main.py examples/generic_robot.proto \ ```bash # Generate and check for errors -PYTHONPATH=src python src/main.py examples/array_test.proto --build_py +PYTHONPATH=src python src/main.py examples/array_test.proto --build_py --py_path generated/py # Import generated code -python -c "import sys; sys.path.insert(0, 'generated/py'); import array_test_sf" +python -c "import sys; sys.path.insert(0, 'generated/py'); from struct_frame.generated.array_test import get_message_info" ``` ## Code Style diff --git a/docs/src/content/docs/reference/testing.md b/docs/src/content/docs/reference/testing.md index adebfebd..438bd527 100644 --- a/docs/src/content/docs/reference/testing.md +++ b/docs/src/content/docs/reference/testing.md @@ -57,7 +57,7 @@ sudo apt install gcc xcode-select --install ``` -**C++ tests**: G++ with C++14 support +**C++ tests**: G++ with C++20 support ```bash # Ubuntu/Debian sudo apt install g++ From 77d26d04481bb18ac7a6a8e46e18ae87425df95e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 02:10:28 +0000 Subject: [PATCH 3/3] Changes before error encountered Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- README.md | 160 +++++++++--------- .../docs/extended-features/python-sdk.md | 32 ++-- .../docs/extended-features/typescript-sdk.md | 41 +++-- docs/src/content/docs/index.mdx | 4 +- .../docs/reference/build-integration.md | 8 +- docs/src/content/docs/reference/testing.md | 14 +- 6 files changed, 139 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index e4a20d49..178921da 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,10 @@ python test_all.py python tests/run_tests.py --verbose # Skip specific languages -python tests/run_tests.py --skip-ts --skip-c --skip-cpp +python tests/run_tests.py --skip-lang ts --skip-lang c # Generate code only (no compilation/execution) -python tests/run_tests.py --generate-only +python tests/run_tests.py --only-generate ``` See `tests/README.md` for detailed test documentation. @@ -76,7 +76,7 @@ Struct Frame provides high-level SDKs for simplified message communication: - **C++**: Header-only with observer/subscriber pattern, ideal for embedded systems - **C#**: Async/await-based for .NET Core, Xamarin, and MAUI applications -See the [SDK Overview](https://struct-frame.mylonics.com/user-guide/sdk-overview/) for details. +See the [SDK Overview](https://struct-frame.mylonics.com/extended-features/sdk-overview/) for details. ## Framing System @@ -352,112 +352,110 @@ Result: [0x7E, 0xC9] #### Python Frame Handling ```python -# Import generated classes -from myl_vehicle_sf import VehicleStatus -from struct_frame_parser import FrameParser, BasicPacket +import sys +sys.path.insert(0, 'generated/py/') # py_path + +from struct_frame.generated.myl_vehicle import MylVehicleVehicleStatus, get_message_info +from frame_profiles import ProfileStandardWriter, ProfileStandardAccumulatingReader # Create message -msg = VehicleStatus() -msg.vehicle_id = 1234 -msg.speed = 65.5 -msg.engine_on = True +msg = MylVehicleVehicleStatus(vehicle_id=1234, speed=65.5, engine_on=True) # Encode to frame -packet = BasicPacket() -frame_bytes = packet.encode_msg(msg) +writer = ProfileStandardWriter(1024) +writer.write(msg) +frame_bytes = writer.data() print(f"Frame: {[hex(b) for b in frame_bytes]}") -# Parse frame (simulate byte-by-byte reception) -parser = FrameParser({0x90: BasicPacket()}, {42: VehicleStatus}) +# Parse frame (byte-by-byte) +reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) for byte in frame_bytes: - result = parser.parse_char(byte) - if result: - print(f"Parsed: vehicle_id={result.vehicle_id}, speed={result.speed}") + result = reader.push_byte(byte) + if result and result.valid: + parsed = MylVehicleVehicleStatus.deserialize(result) + print(f"Parsed: vehicle_id={parsed.vehicle_id}, speed={parsed.speed}") ``` #### TypeScript Frame Handling ```typescript -import * as mv from './generated/ts/myl_vehicle.sf'; -import { struct_frame_buffer, parse_char } from './generated/ts/struct_frame_parser'; +import { MylVehicleVehicleStatus } from './generated/ts/myl_vehicle.structframe'; +import { ProfileStandardWriter, ProfileStandardAccumulatingReader } from './generated/ts/frame-profiles'; // Create and encode message -let tx_buffer = new struct_frame_buffer(256); -let msg = new mv.VehicleStatus(); +const msg = new MylVehicleVehicleStatus(); msg.vehicle_id = 1234; msg.speed = 65.5; msg.engine_on = true; -mv.VehicleStatus_encode(tx_buffer, msg); -// Parse frame -let rx_buffer = new struct_frame_buffer(256); -for (let i = 0; i < tx_buffer.size; i++) { - if (parse_char(rx_buffer, tx_buffer.data[i])) { - let parsed = mv.VehicleStatus_decode(rx_buffer.msg_data); +const writer = new ProfileStandardWriter(256); +writer.write(msg); +const frameData = writer.data(); + +// Parse frame +const reader = new ProfileStandardAccumulatingReader(); +reader.addData(frameData); +const result = reader.next(); +if (result && result.valid) { + const parsed = MylVehicleVehicleStatus.deserialize(result); console.log(`Parsed: vehicle_id=${parsed.vehicle_id}, speed=${parsed.speed}`); - } } ``` -#### C Frame Handling +#### C Frame Handling ```c -#include "myl_vehicle.sf.h" -#include "struct_frame_parser.h" +#include "myl_vehicle.structframe.h" +#include "frame_profiles.h" // Create message -VehicleStatus msg = {0}; +MylVehicleVehicleStatus msg = {0}; msg.vehicle_id = 1234; msg.speed = 65.5f; msg.engine_on = true; // Encode to frame uint8_t frame_buffer[256]; -size_t frame_size = basic_frame_encode(frame_buffer, 42, (uint8_t*)&msg, sizeof(msg)); - -// Parse frame -packet_state_t parser = {0}; -// ... initialize parser ... - -for (size_t i = 0; i < frame_size; i++) { - msg_info_t info = parse_char(&parser, frame_buffer[i]); - if (info.valid) { - VehicleStatus* parsed = (VehicleStatus*)info.msg_loc; - printf("Parsed: vehicle_id=%d, speed=%.1f\n", parsed->vehicle_id, parsed->speed); - } +ProfileStandardWriter writer = profile_standard_writer_init(frame_buffer, sizeof(frame_buffer)); +profile_standard_writer_write(&writer, MYL_VEHICLE_VEHICLE_STATUS_MSG_ID, + (uint8_t*)&msg, sizeof(msg)); + +// Parse frame byte-by-byte +ProfileStandardAccumulatingReader reader = profile_standard_accumulating_reader_init(get_message_info); +for (size_t i = 0; i < writer.size; i++) { + FrameMsgInfo info = profile_standard_accumulating_reader_push_byte(&reader, frame_buffer[i]); + if (info.valid) { + MylVehicleVehicleStatus* parsed = (MylVehicleVehicleStatus*)info.msg_data; + printf("Parsed: vehicle_id=%d, speed=%.1f\n", parsed->vehicle_id, parsed->speed); + } } ``` #### C++ Frame Handling ```cpp -#include "myl_vehicle.sf.hpp" -#include "struct_frame.hpp" +#include "myl_vehicle.structframe.hpp" +#include "frame_profiles.hpp" // Create message -VehicleStatus msg{}; +MylVehicleVehicleStatus msg{}; msg.vehicle_id = 1234; msg.speed = 65.5f; msg.engine_on = true; // Encode to frame -uint8_t frame_buffer[256]; -StructFrame::BasicPacket format; -StructFrame::EncodeBuffer encoder(frame_buffer, sizeof(frame_buffer)); - -bool success = encoder.encode(&format, VEHICLE_STATUS_MSG_ID, &msg, sizeof(msg)); - -// Parse frame using FrameParser -StructFrame::FrameParser parser(&format, [](size_t msg_id, size_t* size) { - return StructFrame::get_message_length(msg_id, size); -}); - -for (size_t i = 0; i < encoder.size(); i++) { - StructFrame::MessageInfo info = parser.parse_byte(frame_buffer[i]); - if (info.valid) { - VehicleStatus* parsed = reinterpret_cast(info.msg_location); - std::cout << "Parsed: vehicle_id=" << parsed->vehicle_id - << ", speed=" << parsed->speed << std::endl; +uint8_t buffer[256]; +FrameParsers::ProfileStandardWriter writer(buffer, sizeof(buffer)); +writer.write(msg); + +// Parse frame byte-by-byte +FrameParsers::ProfileStandardAccumulatingReader reader; +for (size_t i = 0; i < writer.size(); i++) { + if (auto info = reader.push_byte(buffer[i])) { + MylVehicleVehicleStatus parsed; + parsed.deserialize(info); + std::cout << "Parsed: vehicle_id=" << parsed.vehicle_id + << ", speed=" << parsed.speed << "\n"; } } ``` @@ -466,38 +464,44 @@ for (size_t i = 0; i < encoder.size(); i++) { #### Serial Communication ```python +import sys import serial -from struct_frame_parser import FrameParser +sys.path.insert(0, 'generated/py/') + +from struct_frame.generated.messages import MyMessage, get_message_info +from frame_profiles import ProfileStandardAccumulatingReader # Setup serial connection ser = serial.Serial('/dev/ttyUSB0', 115200) -parser = FrameParser(packet_formats, message_definitions) +reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info) # Continuous parsing loop while True: if ser.in_waiting: - byte = ser.read(1)[0] - result = parser.parse_char(byte) - if result: + data = ser.read(ser.in_waiting) + reader.add_data(data) + result = reader.next() + if result and result.valid: handle_message(result) ``` -#### TCP Socket Communication +#### TCP Socket Communication ```typescript import * as net from 'net'; -import { struct_frame_buffer, parse_char } from './struct_frame_parser'; +import { ProfileStandardAccumulatingReader } from './generated/ts/frame-profiles'; +import { MyMessage } from './generated/ts/messages.structframe'; -const client = net.createConnection({port: 8080}, () => { +const client = net.createConnection({ port: 8080 }, () => { console.log('Connected to server'); }); -let rx_buffer = new struct_frame_buffer(1024); +const reader = new ProfileStandardAccumulatingReader(); client.on('data', (data: Buffer) => { - for (let byte of data) { - if (parse_char(rx_buffer, byte)) { - // Process complete message - handleMessage(rx_buffer.msg_data); - } + reader.addData(data); + let result; + while ((result = reader.next()) && result.valid) { + const msg = MyMessage.deserialize(result); + handleMessage(msg); } }); ``` diff --git a/docs/src/content/docs/extended-features/python-sdk.md b/docs/src/content/docs/extended-features/python-sdk.md index 70376f47..31e417ce 100644 --- a/docs/src/content/docs/extended-features/python-sdk.md +++ b/docs/src/content/docs/extended-features/python-sdk.md @@ -61,35 +61,43 @@ sdk.connect() ### Serial ```python -import serial -from struct_frame_sdk.transports import SerialTransport +from struct_frame_sdk.serial_transport import SerialTransport, SerialTransportConfig -transport = SerialTransport('/dev/ttyUSB0', 115200) +config = SerialTransportConfig(port='/dev/ttyUSB0', baudrate=115200) +transport = SerialTransport(config) transport.connect() -transport.send(msg_id, data) ``` -### Socket +### TCP ```python -import socket -from struct_frame_sdk.transports import SocketTransport +from struct_frame_sdk.tcp_transport import TcpTransport, TcpTransportConfig -transport = SocketTransport('192.168.1.100', 8080) +config = TcpTransportConfig(host='192.168.1.100', port=8080) +transport = TcpTransport(config) +transport.connect() +``` + +### UDP + +```python +from struct_frame_sdk.udp_transport import UdpTransport, UdpTransportConfig + +config = UdpTransportConfig(remote_host='192.168.1.100', remote_port=8080) +transport = UdpTransport(config) transport.connect() -transport.send(msg_id, data) ``` ## Async Support ```python import asyncio -from struct_frame_sdk.async_transports import AsyncSerialTransport +from struct_frame_sdk.async_serial_transport import AsyncSerialTransport, AsyncSerialTransportConfig async def main(): - transport = AsyncSerialTransport('/dev/ttyUSB0', 115200) + config = AsyncSerialTransportConfig(port='/dev/ttyUSB0', baud_rate=115200) + transport = AsyncSerialTransport(config) await transport.connect() - await transport.send(msg_id, data) asyncio.run(main()) ``` diff --git a/docs/src/content/docs/extended-features/typescript-sdk.md b/docs/src/content/docs/extended-features/typescript-sdk.md index 07cfbd1b..15536283 100644 --- a/docs/src/content/docs/extended-features/typescript-sdk.md +++ b/docs/src/content/docs/extended-features/typescript-sdk.md @@ -16,18 +16,21 @@ python -m struct_frame messages.proto --build_ts --ts_path src/generated/ --sdk ## Basic Usage ```typescript -import { MessageRouter } from './generated/ts/struct_frame_sdk'; -import { Status } from './generated/ts/messages.sf'; +import { StructFrameSdk, StructFrameSdkConfig } from './generated/ts/struct-frame-sdk'; +import { TcpTransport } from './generated/ts/struct-frame-sdk'; +import { Status } from './generated/ts/status.structframe'; -const router = new MessageRouter(); +const sdk = new StructFrameSdk({ + transport: new TcpTransport({ host: '192.168.1.100', port: 8080 }), + frameParser: ..., // frame parser instance +}); -// Subscribe to messages -router.subscribe(Status, (msg: Status) => { +// Subscribe to messages by ID +sdk.subscribe(Status.MSG_ID, (msg) => { console.log(`Status: ${msg.value}`); }); -// Process incoming data -router.processByte(byte); +sdk.connect(); ``` ## Transports @@ -35,41 +38,37 @@ router.processByte(byte); ### UDP ```typescript -import { UDPTransport } from './generated/ts/struct_frame_sdk/transports'; +import { UdpTransport } from './generated/ts/struct-frame-sdk'; -const transport = new UDPTransport('192.168.1.100', 8080); +const transport = new UdpTransport({ remoteHost: '192.168.1.100', remotePort: 8080 }); await transport.connect(); -await transport.send(msgId, data); ``` ### TCP ```typescript -import { TCPTransport } from './generated/ts/struct_frame_sdk/transports'; +import { TcpTransport } from './generated/ts/struct-frame-sdk'; -const transport = new TCPTransport('192.168.1.100', 8080); +const transport = new TcpTransport({ host: '192.168.1.100', port: 8080 }); await transport.connect(); -await transport.send(msgId, data); ``` ### WebSocket ```typescript -import { WebSocketTransport } from './generated/ts/struct_frame_sdk/transports'; +import { WebSocketTransport } from './generated/ts/struct-frame-sdk'; -const transport = new WebSocketTransport('ws://localhost:8080'); +const transport = new WebSocketTransport({ url: 'ws://localhost:8080' }); await transport.connect(); -await transport.send(msgId, data); ``` ### Serial (Node.js only) ```typescript -import { SerialTransport } from './generated/ts/struct_frame_sdk/transports'; +import { SerialTransport } from './generated/ts/struct-frame-sdk'; -const transport = new SerialTransport('/dev/ttyUSB0', 115200); +const transport = new SerialTransport({ path: '/dev/ttyUSB0', baudRate: 115200 }); await transport.connect(); -await transport.send(msgId, data); ``` ## Browser vs Node.js @@ -83,10 +82,10 @@ The SDK works in both environments: // Detect environment if (typeof window === 'undefined') { // Node.js - import { SerialTransport } from './struct_frame_sdk/transports'; + const { SerialTransport } = await import('./struct-frame-sdk'); } else { // Browser - import { WebSocketTransport } from './struct_frame_sdk/transports'; + const { WebSocketTransport } = await import('./struct-frame-sdk'); } ``` diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 6149f226..b419f7d0 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -106,8 +106,8 @@ python -m struct_frame status.proto --build_c --build_py --build_ts msg.id = 42; msg.value = 3.14; - // Get binary data - const data = msg.data(); + // Serialize to buffer + const data = msg.serialize(); ``` diff --git a/docs/src/content/docs/reference/build-integration.md b/docs/src/content/docs/reference/build-integration.md index e841a40a..2ec5d092 100644 --- a/docs/src/content/docs/reference/build-integration.md +++ b/docs/src/content/docs/reference/build-integration.md @@ -11,13 +11,13 @@ Integrate code generation into your build system so generated code automatically PROTO_FILES := $(wildcard proto/*.proto) GENERATED_DIR := generated -generated/c/%.sf.h: proto/%.proto +generated/c/%.structframe.h: proto/%.proto python -m struct_frame $< --build_c --c_path generated/c/ -generated/py/%.sf.py: proto/%.proto +generated/py/struct_frame/generated/%.py: proto/%.proto python -m struct_frame $< --build_py --py_path generated/py/ -all: $(PROTO_FILES:proto/%.proto=generated/c/%.sf.h) +all: $(PROTO_FILES:proto/%.proto=generated/c/%.structframe.h) ``` ## CMake (C/C++) @@ -31,7 +31,7 @@ set(PROTO_FILES foreach(PROTO_FILE ${PROTO_FILES}) get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE) - set(GENERATED_HEADER "${CMAKE_BINARY_DIR}/generated/c/${PROTO_NAME}.sf.h") + set(GENERATED_HEADER "${CMAKE_BINARY_DIR}/generated/c/${PROTO_NAME}.structframe.h") add_custom_command( OUTPUT ${GENERATED_HEADER} diff --git a/docs/src/content/docs/reference/testing.md b/docs/src/content/docs/reference/testing.md index 438bd527..57a2f837 100644 --- a/docs/src/content/docs/reference/testing.md +++ b/docs/src/content/docs/reference/testing.md @@ -22,10 +22,15 @@ python tests/run_tests.py [options] Options: --verbose, -v Show detailed output - --skip-lang LANG Skip a language (c, cpp, py, ts, js, csharp, gql) - --only-generate Generate code only, skip tests + --quiet, -q Suppress failure output + --skip-lang LANG Skip a language (can be repeated) + --only-generate Generate code only, skip compile and test + --only-compile Stop after compilation, don't run tests --check-tools Check tool availability only - --clean Clean generated and compiled files + --no-clean Skip cleaning generated files (faster iteration) + --profile NAME Only test specific profile(s) + --no-parallel Disable parallel compilation + --no-color Disable colored output ``` Examples: @@ -39,6 +44,9 @@ python tests/run_tests.py --check-tools # Generate code without running tests python tests/run_tests.py --only-generate + +# Faster iteration (skip cleaning) +python tests/run_tests.py --no-clean ``` ## Test Prerequisites