Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97be26c666 | ||
|
|
b32e8547fb | ||
|
|
492fb4b3a5 | ||
|
|
6deafa72bb |
No files matched your search
+9
-2
@@ -1,11 +1,18 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"server",
|
||||
# Hardware Abstraction Layer (Framework)
|
||||
"ethercat-hal",
|
||||
"ethercat-hal-derive",
|
||||
|
||||
# Control Framework (Framework)
|
||||
"control-core",
|
||||
"ethercat-eeprom-dump",
|
||||
"control-core-derive",
|
||||
|
||||
# Machine Implementations (QiTech-Specific)
|
||||
"server",
|
||||
|
||||
# Utilities
|
||||
"ethercat-eeprom-dump",
|
||||
]
|
||||
exclude = []
|
||||
resolver = "2"
|
||||
|
||||
@@ -12,24 +12,37 @@ QiTech Control is an industrial control panel software for the next generation o
|
||||
|
||||
# Repo Structure
|
||||
|
||||
Frontend
|
||||
This repository is organized as a monorepo with clear separation of concerns. See [Repository Organization](./docs/repository-organization.md) for detailed architecture information.
|
||||
|
||||
- `/electron`: Frontend code for the control software built with React and Electron.
|
||||
## Hardware Abstraction Layer (Framework)
|
||||
|
||||
Backend
|
||||
- `/ethercat-hal`: Hardware abstraction layer for Beckhoff and other EtherCAT devices and protocols
|
||||
- `/ethercat-hal-derive`: Derive macros for `ethercat-hal`
|
||||
|
||||
- `/server`: Glue between Beckhoff and Electron. Implements machine logic.
|
||||
- `/ethercat-hal`: Hardware abstraction layer for Beckhoff (and possibly other EtherCat) devices and protocols.
|
||||
- `/ethercat-hal-derive`: Macros for `ethercat-hal`
|
||||
- `/control-core`: Core control logic for the server.
|
||||
## Control Framework (Framework)
|
||||
|
||||
Operating System
|
||||
- `/control-core`: Generic control logic, actor system, and API abstractions
|
||||
- `/control-core-derive`: Derive macros for `control-core`
|
||||
|
||||
- `/nixos`: Custom Linux with realtime kernel & preconfigured for touchscreens.
|
||||
## Machine Implementations (QiTech-Specific)
|
||||
|
||||
Other
|
||||
- `/server`: QiTech-specific machine implementations and glue code that ties everything together
|
||||
|
||||
- `/docs`: Documentation for the project.
|
||||
## User Interface
|
||||
|
||||
- `/electron`: Electron-based control panel UI built with React and TypeScript
|
||||
|
||||
## Operating System
|
||||
|
||||
- `/nixos`: Custom NixOS configuration with real-time kernel & touchscreen support
|
||||
|
||||
## Utilities
|
||||
|
||||
- `/ethercat-eeprom-dump`: CLI tool for dumping EtherCAT device EEPROM data
|
||||
|
||||
## Documentation
|
||||
|
||||
- `/docs`: Project documentation, architecture guides, and developer resources
|
||||
|
||||
# Technology Choices
|
||||
|
||||
@@ -76,9 +89,15 @@ We could combine the code of the frontend and backend using [Doxius](https://dio
|
||||
|
||||
# More Docs
|
||||
|
||||
- [x] [Architecture & Data Flow](./docs/architecture-overview.md)
|
||||
## Architecture & Organization
|
||||
|
||||
- [x] Example Winder V2
|
||||
- [x] [**Organization Summary**](./docs/organization-summary.md) - **Quick reference** for understanding the repository structure
|
||||
- [x] [Architecture & Data Flow](./docs/architecture-overview.md) - System architecture overview with diagrams
|
||||
- [x] [Repository Organization](./docs/repository-organization.md) - Monorepo structure, component boundaries, and modularization options
|
||||
- [x] [Component Interfaces](./docs/component-interfaces.md) - How components interact and interface boundaries
|
||||
- [x] [Migration Guide for Splitting](./docs/migration-guide-splitting.md) - Step-by-step guide for splitting into multiple repositories (if needed)
|
||||
|
||||
## Component Documentation
|
||||
|
||||
- [ ] Electron
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
# Architecture Overview
|
||||
|
||||
For detailed information about repository organization and component separation, see:
|
||||
- [Repository Organization](./repository-organization.md) - Monorepo structure and modularization options
|
||||
- [Component Interfaces](./component-interfaces.md) - How components interact and interface boundaries
|
||||
|
||||

|
||||
|
||||
## The Application is Split Into 3 Main Layers
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
# Component Interfaces and Boundaries
|
||||
|
||||
This document describes the interfaces between major components in the QiTech Control system and how they interact with each other.
|
||||
|
||||
## Component Layering
|
||||
|
||||
The system follows a clear layered architecture:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ User Interface │
|
||||
│ (Electron) │
|
||||
└────────────────────┬────────────────────────────────┘
|
||||
│ REST API / SocketIO
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Machine Implementations │
|
||||
│ (server) │
|
||||
└────────────────────┬────────────────────────────────┘
|
||||
│ Trait implementations
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Control Framework │
|
||||
│ (control-core) │
|
||||
└────────────────────┬────────────────────────────────┘
|
||||
│ Device traits
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Hardware Abstraction Layer │
|
||||
│ (ethercat-hal) │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 1. Hardware Abstraction Layer (ethercat-hal)
|
||||
|
||||
### Public Interface
|
||||
|
||||
The HAL provides traits and types for working with EtherCAT devices:
|
||||
|
||||
**Core Traits:**
|
||||
- `Device`: Base trait for all EtherCAT devices
|
||||
- `Group`: Trait for grouping related devices
|
||||
- `PDO`: Process Data Object handling
|
||||
- `CoE`: CANopen over EtherCAT configuration
|
||||
|
||||
**Key Types:**
|
||||
- Input/Output primitives (digital, analog)
|
||||
- Device configurations
|
||||
- Error types
|
||||
|
||||
**Dependencies:**
|
||||
- External: `ethercrab`, `smol`, `uom`, `bitvec`
|
||||
- Internal: None (lowest layer)
|
||||
|
||||
**Usage Example:**
|
||||
```rust
|
||||
use ethercat_hal::{Device, Group};
|
||||
|
||||
// Implement Device trait for a custom EtherCAT device
|
||||
impl Device for MyCustomDevice {
|
||||
// Implementation details
|
||||
}
|
||||
```
|
||||
|
||||
### Design Principles
|
||||
|
||||
- **Generic**: No knowledge of specific machines or control logic
|
||||
- **Stateless**: Devices are primarily data structures for I/O
|
||||
- **Type-safe**: Uses Rust's type system for safe I/O operations
|
||||
- **Zero-cost abstractions**: Minimal runtime overhead
|
||||
|
||||
## 2. Control Framework (control-core)
|
||||
|
||||
### Public Interface
|
||||
|
||||
The control framework provides abstractions for building control systems:
|
||||
|
||||
**Core Traits:**
|
||||
- `Actor`: Trait for control logic components that run in the control loop
|
||||
- `Machine`: Trait for machine implementations
|
||||
- `MachineValidation`: Trait for validating machine configurations
|
||||
|
||||
**Key Features:**
|
||||
- Actor system for modular control logic
|
||||
- SocketIO namespace abstractions
|
||||
- REST API helpers
|
||||
- Device identification and grouping
|
||||
- Caching mechanisms
|
||||
|
||||
**Dependencies:**
|
||||
- Internal: `ethercat-hal` (for device types)
|
||||
- External: `socketioxide`, `axum`, `serde`, `smol`
|
||||
|
||||
**Usage Example:**
|
||||
```rust
|
||||
use control_core::{Actor, Machine, Group};
|
||||
|
||||
// Implement Actor for a control component
|
||||
struct PIDController {
|
||||
// ... fields
|
||||
}
|
||||
|
||||
impl Actor for PIDController {
|
||||
fn act(&mut self, group: &Group) -> anyhow::Result<()> {
|
||||
// Control logic that runs each cycle
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Implement Machine for a specific machine type
|
||||
struct MyMachine {
|
||||
actors: Vec<Box<dyn Actor>>,
|
||||
}
|
||||
|
||||
impl Machine for MyMachine {
|
||||
// Implementation details
|
||||
}
|
||||
```
|
||||
|
||||
### Design Principles
|
||||
|
||||
- **Generic**: Machine-agnostic, works for any industrial control application
|
||||
- **Composable**: Actors can be combined to build complex control logic
|
||||
- **Real-time capable**: Designed for deterministic execution
|
||||
- **API-ready**: Built-in SocketIO and REST abstractions
|
||||
|
||||
## 3. Machine Implementations (server)
|
||||
|
||||
### Responsibilities
|
||||
|
||||
The server crate contains QiTech-specific implementations:
|
||||
|
||||
1. **Machine Implementations** (`src/machines/`)
|
||||
- Winder, Extruder, Laser, etc.
|
||||
- Each machine implements the `Machine` trait
|
||||
- Contains machine-specific actors and logic
|
||||
|
||||
2. **EtherCAT Setup** (`src/ethercat/`)
|
||||
- Interface discovery
|
||||
- Device enumeration
|
||||
- Group creation
|
||||
|
||||
3. **Serial Devices** (`src/serial/`)
|
||||
- Non-EtherCAT devices (e.g., laser sensors)
|
||||
- Serial protocol implementations
|
||||
|
||||
4. **API Handlers** (`src/rest/`, `src/socketio/`)
|
||||
- Machine mutation endpoints
|
||||
- Real-time status updates
|
||||
- Device identification management
|
||||
|
||||
5. **Control Loop** (`src/loop.rs`)
|
||||
- Main control loop execution
|
||||
- Thread management
|
||||
- Actor coordination
|
||||
|
||||
**Dependencies:**
|
||||
- Internal: `control-core`, `ethercat-hal`
|
||||
- External: `axum`, `socketioxide`, `tokio`, `smol`
|
||||
|
||||
**Example Machine Implementation:**
|
||||
```rust
|
||||
use control_core::{Machine, Actor, Group};
|
||||
use ethercat_hal::Device;
|
||||
|
||||
pub struct WinderV2 {
|
||||
// Actors
|
||||
puller: Puller,
|
||||
traverse: Traverse,
|
||||
// ... other components
|
||||
}
|
||||
|
||||
impl Machine for WinderV2 {
|
||||
fn act(&mut self, group: &Group) -> anyhow::Result<()> {
|
||||
// Coordinate all actors
|
||||
self.puller.act(group)?;
|
||||
self.traverse.act(group)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Design Principles
|
||||
|
||||
- **Machine-specific**: Contains QiTech business logic
|
||||
- **Uses framework**: Builds on `control-core` and `ethercat-hal`
|
||||
- **API implementation**: Provides REST and SocketIO endpoints
|
||||
- **Integration point**: Ties together hardware, framework, and UI
|
||||
|
||||
## 4. User Interface (electron)
|
||||
|
||||
### Interface with Backend
|
||||
|
||||
The Electron UI communicates with the server through two channels:
|
||||
|
||||
#### REST API
|
||||
|
||||
Used for request/response operations:
|
||||
|
||||
- **Machine mutations**: Start, stop, change parameters
|
||||
- **Device identification**: Read/write device IDs
|
||||
- **Configuration**: System settings
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
// POST /machine/mutation
|
||||
const response = await fetch('http://localhost:3001/machine/mutation', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
mutation: 'Start',
|
||||
parameters: { /* ... */ }
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### SocketIO
|
||||
|
||||
Used for real-time updates:
|
||||
|
||||
- **Main namespace** (`/`): System-wide events (machine discovery, errors)
|
||||
- **Machine namespaces** (`/machine/<vendor>/<id>`): Machine-specific state updates
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { io } from 'socket.io-client';
|
||||
|
||||
const socket = io('http://localhost:3001/machine/1/2');
|
||||
|
||||
socket.on('state', (machineState) => {
|
||||
// Update UI with new machine state
|
||||
updateDisplay(machineState);
|
||||
});
|
||||
```
|
||||
|
||||
### Design Principles
|
||||
|
||||
- **Decoupled**: Communicates via APIs, not tight coupling
|
||||
- **Reactive**: Uses SocketIO for real-time updates
|
||||
- **Machine-aware**: Contains UI for each machine type
|
||||
- **Reusable**: Built with standard web technologies
|
||||
|
||||
## 5. Operating System (nixos)
|
||||
|
||||
### Role
|
||||
|
||||
Provides the runtime environment:
|
||||
|
||||
- Real-time kernel for deterministic control loop execution
|
||||
- System services for the server
|
||||
- Touchscreen configuration
|
||||
- Package management
|
||||
|
||||
### Integration
|
||||
|
||||
- Builds and packages the `server` binary
|
||||
- Configures systemd service for automatic startup
|
||||
- Provides system dependencies (libraries, drivers)
|
||||
|
||||
## Interface Guidelines
|
||||
|
||||
### For Framework Development (ethercat-hal, control-core)
|
||||
|
||||
When working on framework crates:
|
||||
|
||||
1. **No QiTech-specific code**: Keep implementations generic
|
||||
2. **Document public APIs**: Assume external users
|
||||
3. **Semantic versioning**: Changes should follow semver
|
||||
4. **Minimal dependencies**: Only add well-maintained, stable crates
|
||||
5. **Examples**: Provide usage examples in documentation
|
||||
6. **Testing**: Write tests that don't depend on specific machines
|
||||
|
||||
### For Machine Development (server)
|
||||
|
||||
When implementing machines:
|
||||
|
||||
1. **Use framework traits**: Implement `Machine` and `Actor` traits
|
||||
2. **Isolate machine code**: Keep machine-specific code in `src/machines/<machine_name>/`
|
||||
3. **API design**: Design REST/SocketIO APIs with UI in mind
|
||||
4. **Error handling**: Use `anyhow::Result` for error propagation
|
||||
5. **Documentation**: Document machine-specific behavior
|
||||
|
||||
### For UI Development (electron)
|
||||
|
||||
When working on the UI:
|
||||
|
||||
1. **API contracts**: Respect REST/SocketIO API contracts
|
||||
2. **Type safety**: Use TypeScript types for API responses
|
||||
3. **Machine components**: Keep machine-specific UI in `src/machines/<machine_name>/`
|
||||
4. **Reusable components**: Extract common patterns to shared components
|
||||
5. **Error handling**: Handle network errors gracefully
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
### Error Handling
|
||||
|
||||
- **HAL**: Returns `anyhow::Result` for device operations
|
||||
- **Framework**: Uses `anyhow::Result` with context
|
||||
- **Server**: Propagates errors, logs with `tracing`
|
||||
- **UI**: Displays user-friendly error messages
|
||||
|
||||
### Logging and Tracing
|
||||
|
||||
- **Backend**: Uses `tracing` crate with structured logging
|
||||
- **UI**: Uses console logging and optional telemetry
|
||||
|
||||
### Testing
|
||||
|
||||
- **Unit tests**: Each crate has unit tests for internal logic
|
||||
- **Integration tests**: Server has tests that span multiple components
|
||||
- **E2E tests**: Electron has Playwright tests for UI workflows
|
||||
|
||||
### Configuration
|
||||
|
||||
- **Server**: TOML configuration file (`config.toml`)
|
||||
- **UI**: Electron store for user preferences
|
||||
- **NixOS**: System configuration in Nix files
|
||||
|
||||
## Future Considerations
|
||||
|
||||
### If Splitting into Multiple Repositories
|
||||
|
||||
1. **Version Pinning**: Server would depend on specific versions of framework crates
|
||||
2. **Release Coordination**: Framework releases need stability guarantees
|
||||
3. **Breaking Changes**: Would require careful migration planning
|
||||
4. **Documentation**: Each repository needs comprehensive docs
|
||||
5. **CI/CD**: Separate pipelines for each repository
|
||||
|
||||
### Maintaining Current Structure
|
||||
|
||||
1. **Clean Boundaries**: Continue enforcing layer separation
|
||||
2. **Interface Stability**: Treat framework interfaces as if they were versioned APIs
|
||||
3. **Documentation**: Keep this document updated
|
||||
4. **Testing**: Ensure framework crates can be tested independently
|
||||
|
||||
## Summary
|
||||
|
||||
The QiTech Control system has a well-defined layered architecture:
|
||||
|
||||
- **ethercat-hal**: Provides hardware abstraction (reusable)
|
||||
- **control-core**: Provides control framework (reusable)
|
||||
- **server**: Implements QiTech machines (specific)
|
||||
- **electron**: Provides user interface (adaptable)
|
||||
- **nixos**: Provides runtime environment (adaptable)
|
||||
|
||||
Each layer depends only on layers below it, creating clear separation of concerns and enabling potential future modularization.
|
||||
@@ -1,4 +1,16 @@
|
||||
# Environment Setup
|
||||
# Getting Started
|
||||
|
||||
This guide will help you set up your development environment for QiTech Control.
|
||||
|
||||
## Understanding the Repository
|
||||
|
||||
Before starting, it's recommended to understand the repository organization:
|
||||
|
||||
- [Repository Organization](../repository-organization.md) - Monorepo structure and component boundaries
|
||||
- [Architecture Overview](../architecture-overview.md) - System architecture and data flow
|
||||
- [Component Interfaces](../component-interfaces.md) - How components interact
|
||||
|
||||
## Environment Setup
|
||||
|
||||
Working on this repository requires you to use cargo and npm. In the following document the installation process will be shown
|
||||
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
# Migration Guide: Splitting the Monorepo
|
||||
|
||||
This guide provides a step-by-step approach for splitting the QiTech Control monorepo into multiple repositories, should that become necessary in the future.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before considering a split:
|
||||
|
||||
1. **Framework Stability**: Ensure `ethercat-hal` and `control-core` APIs are stable
|
||||
2. **Documentation**: All framework crates have comprehensive documentation
|
||||
3. **Tests**: Framework crates have thorough test coverage
|
||||
4. **Versioning Strategy**: Decide on semantic versioning approach
|
||||
5. **Team Consensus**: All stakeholders agree on the split
|
||||
|
||||
## Recommended Approach: Gradual Migration
|
||||
|
||||
### Phase 1: Prepare Framework for External Use
|
||||
|
||||
**Goal**: Make framework crates publishable while keeping monorepo structure.
|
||||
|
||||
#### Step 1.1: Clean Up Framework Dependencies
|
||||
|
||||
Ensure framework crates only depend on:
|
||||
- Each other (via path dependencies)
|
||||
- Well-maintained external crates
|
||||
- No `server` or machine-specific code
|
||||
|
||||
```bash
|
||||
# Check dependency tree
|
||||
cd control
|
||||
cargo tree -p ethercat-hal
|
||||
cargo tree -p control-core
|
||||
```
|
||||
|
||||
#### Step 1.2: Add Package Metadata
|
||||
|
||||
Update `ethercat-hal/Cargo.toml` and `control-core/Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "ethercat-hal"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
authors = ["QiTech Industries GmbH"]
|
||||
license = "MIT OR Apache-2.0" # Choose appropriate license
|
||||
description = "Hardware abstraction layer for EtherCAT devices"
|
||||
documentation = "https://docs.rs/ethercat-hal"
|
||||
repository = "https://github.com/qitechgmbh/control-framework"
|
||||
keywords = ["ethercat", "industrial", "automation", "beckhoff"]
|
||||
categories = ["embedded", "hardware-support"]
|
||||
readme = "README.md"
|
||||
```
|
||||
|
||||
#### Step 1.3: Write Framework Documentation
|
||||
|
||||
For each framework crate:
|
||||
|
||||
1. Create `README.md` with:
|
||||
- Purpose and features
|
||||
- Installation instructions
|
||||
- Quick start example
|
||||
- Link to full documentation
|
||||
|
||||
2. Add crate-level documentation to `src/lib.rs`:
|
||||
```rust
|
||||
//! # Ethercat HAL
|
||||
//!
|
||||
//! Hardware abstraction layer for EtherCAT devices.
|
||||
//!
|
||||
//! ## Quick Start
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use ethercat_hal::{Device, Group};
|
||||
//! // ... example code
|
||||
//! ```
|
||||
```
|
||||
|
||||
3. Document all public APIs with examples
|
||||
|
||||
#### Step 1.4: Test Framework Isolation
|
||||
|
||||
```bash
|
||||
# Try building framework crates independently
|
||||
cd ethercat-hal && cargo build
|
||||
cd ../control-core && cargo build
|
||||
|
||||
# Run tests
|
||||
cd ../ethercat-hal && cargo test
|
||||
cd ../control-core && cargo test
|
||||
```
|
||||
|
||||
#### Step 1.5: Publish to crates.io (Optional Dry Run)
|
||||
|
||||
```bash
|
||||
cd ethercat-hal
|
||||
cargo publish --dry-run
|
||||
|
||||
cd ../control-core
|
||||
cargo publish --dry-run
|
||||
```
|
||||
|
||||
### Phase 2: Extract Framework to Separate Repository
|
||||
|
||||
**Goal**: Move framework crates to a new repository.
|
||||
|
||||
#### Step 2.1: Create Framework Repository
|
||||
|
||||
```bash
|
||||
# Create new repository
|
||||
git clone https://github.com/qitechgmbh/control-framework.git
|
||||
cd control-framework
|
||||
|
||||
# Set up structure
|
||||
mkdir -p ethercat-hal ethercat-hal-derive control-core control-core-derive
|
||||
touch Cargo.toml README.md LICENSE
|
||||
```
|
||||
|
||||
#### Step 2.2: Copy Framework Code with History
|
||||
|
||||
Use `git filter-repo` to preserve commit history:
|
||||
|
||||
```bash
|
||||
# Install git-filter-repo
|
||||
pip install git-filter-repo
|
||||
|
||||
# Clone original repo
|
||||
git clone https://github.com/qitechgmbh/control.git control-temp
|
||||
cd control-temp
|
||||
|
||||
# Extract ethercat-hal with history
|
||||
git filter-repo --subdirectory-filter ethercat-hal --force
|
||||
|
||||
# Push to framework repo
|
||||
git remote add framework https://github.com/qitechgmbh/control-framework.git
|
||||
git push framework main:ethercat-hal-history
|
||||
|
||||
# Repeat for other framework crates
|
||||
```
|
||||
|
||||
#### Step 2.3: Set Up Framework Workspace
|
||||
|
||||
In `control-framework/Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[workspace]
|
||||
members = [
|
||||
"ethercat-hal",
|
||||
"ethercat-hal-derive",
|
||||
"control-core",
|
||||
"control-core-derive",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
authors = ["QiTech Industries GmbH"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/qitechgmbh/control-framework"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
# ... copy from original
|
||||
```
|
||||
|
||||
#### Step 2.4: Update Internal Dependencies
|
||||
|
||||
Update `control-core/Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
ethercat_hal = { version = "0.1.0", path = "../ethercat-hal" }
|
||||
# ... other deps
|
||||
```
|
||||
|
||||
#### Step 2.5: Add CI/CD
|
||||
|
||||
Create `.github/workflows/ci.yml`:
|
||||
|
||||
```yaml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo test --all-features
|
||||
- run: cargo clippy -- -D warnings
|
||||
- run: cargo doc --no-deps
|
||||
|
||||
publish:
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo publish --token ${CRATES_TOKEN}
|
||||
env:
|
||||
CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }}
|
||||
```
|
||||
|
||||
#### Step 2.6: Publish Framework to crates.io
|
||||
|
||||
```bash
|
||||
cd control-framework
|
||||
|
||||
# Publish in dependency order
|
||||
cd ethercat-hal-derive
|
||||
cargo publish
|
||||
|
||||
cd ../ethercat-hal
|
||||
cargo publish
|
||||
|
||||
cd ../control-core-derive
|
||||
cargo publish
|
||||
|
||||
cd ../control-core
|
||||
cargo publish
|
||||
```
|
||||
|
||||
### Phase 3: Update QiTech Repository
|
||||
|
||||
**Goal**: Make QiTech repo depend on published framework crates.
|
||||
|
||||
#### Step 3.1: Remove Framework Code
|
||||
|
||||
In the original `control` repository:
|
||||
|
||||
```bash
|
||||
cd control
|
||||
git rm -r ethercat-hal ethercat-hal-derive control-core control-core-derive
|
||||
```
|
||||
|
||||
#### Step 3.2: Update server/Cargo.toml
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
# Replace path dependencies with crates.io dependencies
|
||||
ethercat_hal = "0.1.0"
|
||||
control_core = "0.1.0"
|
||||
control_core_derive = "0.1.0"
|
||||
|
||||
# ... other deps remain same
|
||||
```
|
||||
|
||||
#### Step 3.3: Update Workspace
|
||||
|
||||
Update root `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[workspace]
|
||||
members = [
|
||||
"server",
|
||||
"ethercat-eeprom-dump",
|
||||
]
|
||||
```
|
||||
|
||||
#### Step 3.4: Test Migration
|
||||
|
||||
```bash
|
||||
cd server
|
||||
cargo build
|
||||
cargo test
|
||||
```
|
||||
|
||||
#### Step 3.5: Update Documentation
|
||||
|
||||
Update `README.md`:
|
||||
|
||||
```markdown
|
||||
# QiTech Control
|
||||
|
||||
This repository contains QiTech-specific machine implementations using the
|
||||
[control-framework](https://github.com/qitechgmbh/control-framework).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [ethercat-hal](https://crates.io/crates/ethercat-hal) - Hardware abstraction layer
|
||||
- [control-core](https://crates.io/crates/control-core) - Control framework
|
||||
```
|
||||
|
||||
### Phase 4: Extract UI (Optional)
|
||||
|
||||
**Goal**: Separate Electron UI into its own repository.
|
||||
|
||||
#### Step 4.1: Create UI Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/qitechgmbh/control-ui.git
|
||||
cd control-ui
|
||||
|
||||
# Copy electron directory
|
||||
cp -r ../control/electron/* .
|
||||
```
|
||||
|
||||
#### Step 4.2: Make UI Generic
|
||||
|
||||
1. Remove QiTech-specific machine UIs or make them plugins
|
||||
2. Create configuration for API endpoints
|
||||
3. Add documentation for customization
|
||||
|
||||
#### Step 4.3: Publish as npm Package
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@qitech/control-ui",
|
||||
"version": "1.0.0",
|
||||
"description": "Electron UI for industrial control systems",
|
||||
"main": "dist/main.js",
|
||||
"repository": "github:qitechgmbh/control-ui"
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
npm publish --access public
|
||||
```
|
||||
|
||||
#### Step 4.4: Use UI in QiTech Repo
|
||||
|
||||
Option A: Git Submodule:
|
||||
```bash
|
||||
cd control
|
||||
git rm -r electron
|
||||
git submodule add https://github.com/qitechgmbh/control-ui.git electron
|
||||
```
|
||||
|
||||
Option B: npm Package:
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@qitech/control-ui": "^1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Alternative: Gradual Separation without Multiple Repositories
|
||||
|
||||
If full split is not necessary, maintain logical separation within monorepo:
|
||||
|
||||
### Use Cargo Workspaces Effectively
|
||||
|
||||
```toml
|
||||
[workspace]
|
||||
members = [
|
||||
# Framework (don't depend on server)
|
||||
"framework/ethercat-hal",
|
||||
"framework/ethercat-hal-derive",
|
||||
"framework/control-core",
|
||||
"framework/control-core-derive",
|
||||
|
||||
# Application (depends on framework)
|
||||
"app/server",
|
||||
|
||||
# UI
|
||||
"ui/electron",
|
||||
|
||||
# Utils
|
||||
"utils/ethercat-eeprom-dump",
|
||||
]
|
||||
```
|
||||
|
||||
### Enforce Boundaries with Linting
|
||||
|
||||
Add a CI check to ensure framework doesn't depend on application:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# check-dependencies.sh
|
||||
|
||||
if grep -r "server" framework/*/Cargo.toml; then
|
||||
echo "Error: Framework should not depend on server!"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If migration causes issues:
|
||||
|
||||
### Roll Back Phase 3
|
||||
|
||||
```bash
|
||||
cd control
|
||||
git revert <migration-commit>
|
||||
git push
|
||||
```
|
||||
|
||||
### Revert to Path Dependencies
|
||||
|
||||
Update `server/Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
ethercat_hal = { path = "../ethercat-hal" }
|
||||
control_core = { path = "../control-core" }
|
||||
```
|
||||
|
||||
### Keep Framework Repo
|
||||
|
||||
The framework repository can remain as a mirror/backup even if not actively used.
|
||||
|
||||
## Post-Migration Maintenance
|
||||
|
||||
### Version Updates
|
||||
|
||||
When updating framework:
|
||||
|
||||
1. **Framework Repository**:
|
||||
```bash
|
||||
cd control-framework
|
||||
# Make changes
|
||||
cargo test
|
||||
# Update version in Cargo.toml
|
||||
git tag v0.2.0
|
||||
git push --tags
|
||||
cargo publish
|
||||
```
|
||||
|
||||
2. **QiTech Repository**:
|
||||
```bash
|
||||
cd control/server
|
||||
# Update Cargo.toml
|
||||
ethercat_hal = "0.2.0"
|
||||
cargo update
|
||||
cargo test
|
||||
```
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
When framework has breaking changes:
|
||||
|
||||
1. Bump major version (0.1.0 → 0.2.0 or 1.0.0)
|
||||
2. Write migration guide
|
||||
3. Support old version for transition period
|
||||
4. Update QiTech repo when ready
|
||||
|
||||
### Documentation
|
||||
|
||||
Keep both repositories' documentation in sync:
|
||||
- Framework: API documentation
|
||||
- QiTech: Machine implementation examples using framework
|
||||
|
||||
## Timeline Estimate
|
||||
|
||||
- **Phase 1** (Preparation): 2-4 weeks
|
||||
- Documentation and cleanup
|
||||
- Testing isolation
|
||||
|
||||
- **Phase 2** (Framework Extraction): 1-2 weeks
|
||||
- Repository setup
|
||||
- History migration
|
||||
- Publishing to crates.io
|
||||
|
||||
- **Phase 3** (QiTech Update): 1 week
|
||||
- Update dependencies
|
||||
- Testing
|
||||
- Documentation updates
|
||||
|
||||
- **Phase 4** (UI Extraction, Optional): 2-3 weeks
|
||||
- Repository setup
|
||||
- Generalization
|
||||
- Integration testing
|
||||
|
||||
**Total: 6-10 weeks** depending on scope
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- ✅ Framework crates build independently
|
||||
- ✅ All tests pass in both repositories
|
||||
- ✅ Documentation is comprehensive
|
||||
- ✅ CI/CD pipelines are working
|
||||
- ✅ QiTech machines work with published framework
|
||||
- ✅ Version management is clear
|
||||
- ✅ Team is trained on new workflow
|
||||
|
||||
## Conclusion
|
||||
|
||||
Splitting the monorepo is a significant undertaking that should only be done when:
|
||||
1. Framework is stable and well-documented
|
||||
2. There's clear need for independent versioning
|
||||
3. External users want to use the framework
|
||||
4. Team has bandwidth to maintain multiple repositories
|
||||
|
||||
The gradual approach outlined here minimizes risk by:
|
||||
- Preparing framework first (Phase 1 can be done immediately)
|
||||
- Publishing framework while keeping monorepo (reversible)
|
||||
- Only removing framework code once proven stable
|
||||
- Maintaining clear rollback options
|
||||
|
||||
For now, continue with the monorepo approach while following best practices that keep the option open for future splitting.
|
||||
@@ -0,0 +1,157 @@
|
||||
# Repository Organization Summary
|
||||
|
||||
This document provides a quick reference for understanding the QiTech Control repository structure.
|
||||
|
||||
## Quick Navigation
|
||||
|
||||
- **[Repository Organization](./repository-organization.md)** - Complete guide to the monorepo structure
|
||||
- **[Component Interfaces](./component-interfaces.md)** - How components interact
|
||||
- **[Migration Guide](./migration-guide-splitting.md)** - How to split into multiple repos (if needed)
|
||||
- **[Architecture Overview](./architecture-overview.md)** - System architecture diagrams
|
||||
|
||||
## At a Glance
|
||||
|
||||
### Framework Layer (Reusable)
|
||||
|
||||
These components form a generic control framework that could be used by other projects:
|
||||
|
||||
```
|
||||
ethercat-hal + ethercat-hal-derive
|
||||
↓
|
||||
control-core + control-core-derive
|
||||
```
|
||||
|
||||
- **Purpose**: Provide abstractions for building industrial control systems
|
||||
- **Audience**: Could be published to crates.io for external use
|
||||
- **Dependencies**: Only on external crates and each other
|
||||
|
||||
### Application Layer (QiTech-Specific)
|
||||
|
||||
```
|
||||
server/
|
||||
├── machines/ # Machine implementations (winder, extruder, etc.)
|
||||
├── ethercat/ # EtherCAT setup
|
||||
├── serial/ # Serial device handling
|
||||
├── rest/ # REST API handlers
|
||||
└── socketio/ # SocketIO handlers
|
||||
```
|
||||
|
||||
- **Purpose**: QiTech-specific machine implementations
|
||||
- **Audience**: QiTech internal use
|
||||
- **Dependencies**: Uses framework + external crates
|
||||
|
||||
### User Interface
|
||||
|
||||
```
|
||||
electron/
|
||||
├── src/machines/ # Machine-specific UIs
|
||||
├── components/ # Reusable UI components
|
||||
├── routes/ # Application routing
|
||||
└── ...
|
||||
```
|
||||
|
||||
- **Purpose**: Control panel user interface
|
||||
- **Technology**: Electron, React, TypeScript
|
||||
- **Communication**: REST + SocketIO APIs
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **Clean Layering**: Framework doesn't depend on application code
|
||||
2. **Type Safety**: Rust's type system ensures safe hardware access
|
||||
3. **Real-time Capable**: Designed for deterministic control loops
|
||||
4. **API-First**: UI communicates through well-defined APIs
|
||||
5. **Testable**: Each layer can be tested independently
|
||||
|
||||
## When to Use What
|
||||
|
||||
### Working on Hardware Support
|
||||
- Edit: `ethercat-hal/`
|
||||
- Purpose: Adding new EtherCAT devices or improving HAL
|
||||
|
||||
### Working on Framework Features
|
||||
- Edit: `control-core/`
|
||||
- Purpose: Adding actors, improving control logic abstractions
|
||||
|
||||
### Working on Machines
|
||||
- Edit: `server/src/machines/`
|
||||
- Purpose: Implementing or modifying machine behavior
|
||||
|
||||
### Working on UI
|
||||
- Edit: `electron/`
|
||||
- Purpose: UI changes, new screens, UX improvements
|
||||
|
||||
### Working on System Configuration
|
||||
- Edit: `nixos/`
|
||||
- Purpose: OS configuration, deployment setup
|
||||
|
||||
## Common Questions
|
||||
|
||||
### Q: Can I depend on `server` from `control-core`?
|
||||
**A: No.** Framework crates should never depend on application code. This maintains reusability.
|
||||
|
||||
### Q: Where should I put reusable control logic?
|
||||
**A: In `control-core`.** If it's generic and could be used by multiple machines, it belongs in the framework.
|
||||
|
||||
### Q: Where should I put QiTech-specific logic?
|
||||
**A: In `server`.** Machine-specific implementations go in `server/src/machines/`.
|
||||
|
||||
### Q: Should we split into multiple repositories?
|
||||
**A: Not yet.** The current monorepo structure works well for the current development phase. See the [Migration Guide](./migration-guide-splitting.md) for when and how to split if needed.
|
||||
|
||||
### Q: How do I ensure my changes maintain clean boundaries?
|
||||
**A: Follow these guidelines:**
|
||||
1. Framework code should be generic (no QiTech-specific assumptions)
|
||||
2. Document public APIs as if for external users
|
||||
3. Keep machine code isolated in appropriate directories
|
||||
4. Write tests that verify isolation
|
||||
|
||||
## Quick Reference: Dependency Rules
|
||||
|
||||
```
|
||||
✅ Allowed:
|
||||
- server → control-core → ethercat-hal
|
||||
- control-core → ethercat-hal
|
||||
- electron → server (via APIs only)
|
||||
|
||||
❌ Not Allowed:
|
||||
- ethercat-hal → control-core
|
||||
- control-core → server
|
||||
- ethercat-hal → server
|
||||
- server → electron
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
New to the project? Start here:
|
||||
|
||||
1. Read [Getting Started](./developer-docs/getting-started.md)
|
||||
2. Review [Architecture Overview](./architecture-overview.md)
|
||||
3. Read [Repository Organization](./repository-organization.md)
|
||||
4. Look at [Component Interfaces](./component-interfaces.md) for detailed API information
|
||||
|
||||
## Contributing
|
||||
|
||||
When making changes:
|
||||
|
||||
1. **Understand the layer** you're working in
|
||||
2. **Follow the dependencies** - only depend on lower layers
|
||||
3. **Document public APIs** - especially in framework crates
|
||||
4. **Write tests** - unit tests for each layer, integration tests across layers
|
||||
5. **Keep it clean** - maintain separation of concerns
|
||||
|
||||
## Future Considerations
|
||||
|
||||
The repository is structured to allow future splitting if needed:
|
||||
|
||||
- **Short term**: Continue with monorepo, maintain clean boundaries
|
||||
- **Medium term**: Prepare framework crates for publication (add docs, examples)
|
||||
- **Long term**: Consider splitting when framework is stable and there are external users
|
||||
|
||||
See [Migration Guide](./migration-guide-splitting.md) for the full plan.
|
||||
|
||||
---
|
||||
|
||||
For more detailed information, see the complete documentation:
|
||||
- [Repository Organization](./repository-organization.md)
|
||||
- [Component Interfaces](./component-interfaces.md)
|
||||
- [Migration Guide](./migration-guide-splitting.md)
|
||||
@@ -0,0 +1,282 @@
|
||||
# Repository Organization
|
||||
|
||||
This document explains the current repository structure and provides guidance on how the codebase is organized for maintainability and potential future modularization.
|
||||
|
||||
## Overview
|
||||
|
||||
The QiTech Control repository is currently a monorepo that contains multiple logical components:
|
||||
|
||||
1. **Hardware Abstraction Layer (HAL)** - Low-level EtherCAT device interfaces
|
||||
2. **Control Framework** - Generic control logic and abstractions
|
||||
3. **Machine Implementations** - QiTech-specific machine logic
|
||||
4. **User Interface** - Electron-based control panel UI
|
||||
5. **Operating System** - NixOS configuration for deployment
|
||||
|
||||
## Current Structure
|
||||
|
||||
### 1. Hardware Abstraction Layer
|
||||
|
||||
**Crates:** `ethercat-hal`, `ethercat-hal-derive`
|
||||
|
||||
**Purpose:** Provides low-level abstractions for interfacing with Beckhoff and other EtherCAT devices.
|
||||
|
||||
**Key Features:**
|
||||
- Device trait definitions
|
||||
- PDO (Process Data Object) handling
|
||||
- CoE (CANopen over EtherCAT) configuration
|
||||
- I/O primitives
|
||||
- Built on top of [ethercrab](https://github.com/ethercrab-rs/ethercrab)
|
||||
|
||||
**Dependencies:** External crates only (ethercrab, smol, uom, etc.)
|
||||
|
||||
**Reusability:** Highly reusable for any EtherCAT-based control system
|
||||
|
||||
### 2. Control Framework
|
||||
|
||||
**Crates:** `control-core`, `control-core-derive`
|
||||
|
||||
**Purpose:** Provides generic control logic abstractions that can be used across different machine types.
|
||||
|
||||
**Key Features:**
|
||||
- Actor system for control logic components
|
||||
- SocketIO and REST API abstractions
|
||||
- Machine trait definitions
|
||||
- Device identification and validation
|
||||
- Group management
|
||||
- Video streaming support (optional)
|
||||
|
||||
**Dependencies:** `ethercat-hal`, external crates
|
||||
|
||||
**Reusability:** Reusable for building various industrial control systems
|
||||
|
||||
### 3. Machine Implementations (QiTech-Specific)
|
||||
|
||||
**Crate:** `server`
|
||||
|
||||
**Purpose:** Contains QiTech-specific machine implementations and glue code that ties everything together.
|
||||
|
||||
**Key Components:**
|
||||
- **Machine implementations** (`src/machines/`):
|
||||
- Winder V2
|
||||
- Extruder V1/V2
|
||||
- Aquapath (Waterway) V1
|
||||
- Laser V1
|
||||
- Buffer V1
|
||||
- Mock machines for testing
|
||||
- **EtherCAT setup** (`src/ethercat/`): Interface discovery, configuration
|
||||
- **Serial device handling** (`src/serial/`): Non-EtherCAT devices
|
||||
- **REST API handlers** (`src/rest/`): Machine mutations, device identification
|
||||
- **SocketIO handlers** (`src/socketio/`): Real-time communication
|
||||
- **Control loop** (`src/loop.rs`): Main control loop execution
|
||||
|
||||
**Dependencies:** `control-core`, `ethercat-hal`, external crates
|
||||
|
||||
**Reusability:** QiTech-specific, but demonstrates how to use the framework
|
||||
|
||||
### 4. User Interface
|
||||
|
||||
**Directory:** `electron/`
|
||||
|
||||
**Purpose:** Electron-based user interface for controlling and monitoring machines.
|
||||
|
||||
**Key Features:**
|
||||
- React-based UI with TypeScript
|
||||
- Real-time updates via SocketIO
|
||||
- REST API client for machine control
|
||||
- Machine-specific UI components (`src/machines/`)
|
||||
- Shadcn/UI component library
|
||||
- TanStack Router for navigation
|
||||
- Theming and internationalization support
|
||||
|
||||
**Dependencies:** Node.js, Electron, React ecosystem
|
||||
|
||||
**Reusability:** Could be reused with modifications for similar control systems
|
||||
|
||||
### 5. Operating System Configuration
|
||||
|
||||
**Directory:** `nixos/`
|
||||
|
||||
**Purpose:** NixOS configuration for deployment on control panels.
|
||||
|
||||
**Key Features:**
|
||||
- Real-time kernel configuration
|
||||
- Touchscreen support
|
||||
- System service definitions
|
||||
- Package management
|
||||
|
||||
**Reusability:** Reusable for similar embedded Linux deployments
|
||||
|
||||
### 6. Utility Crates
|
||||
|
||||
**Crate:** `ethercat-eeprom-dump`
|
||||
|
||||
**Purpose:** Command-line utility for dumping EtherCAT device EEPROM data.
|
||||
|
||||
**Dependencies:** `ethercat-hal`, `control-core`
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ ethercat-hal │◄─── Low-level HAL
|
||||
│ + derive macros │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
│ depends on
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ control-core │◄─── Generic framework
|
||||
│ + derive macros │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
│ depends on
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ server │◄─── QiTech-specific
|
||||
│ (machine impls) │ implementations
|
||||
└─────────────────────┘
|
||||
|
||||
┌─────────────────────┐
|
||||
│ electron │◄─── UI (communicates via
|
||||
│ (UI) │ REST/SocketIO APIs)
|
||||
└─────────────────────┘
|
||||
|
||||
┌─────────────────────┐
|
||||
│ nixos │◄─── OS configuration
|
||||
│ (deployment) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
## Conceptual Separation
|
||||
|
||||
If this repository were to be split into separate repositories, a logical separation would be:
|
||||
|
||||
### Option A: Three Repository Split
|
||||
|
||||
1. **`control-framework`** (or `industrial-control-rs`)
|
||||
- Contains: `ethercat-hal`, `ethercat-hal-derive`, `control-core`, `control-core-derive`
|
||||
- Purpose: Reusable Rust framework for building industrial control systems
|
||||
- Audience: Other companies/projects building EtherCAT control systems
|
||||
- Published to: crates.io
|
||||
|
||||
2. **`control-ui`** (or `control-electron-ui`)
|
||||
- Contains: `electron/` directory
|
||||
- Purpose: Reusable Electron-based UI for control systems
|
||||
- Audience: Projects that want a pre-built control panel UI
|
||||
- Could be: npm package or standalone repository
|
||||
|
||||
3. **`control-qitech`**
|
||||
- Contains: `server/` (machine implementations), `nixos/` (deployment config)
|
||||
- Dependencies: Uses `control-framework` crates, includes `control-ui` as git submodule
|
||||
- Purpose: QiTech-specific machine implementations and deployment
|
||||
- Audience: QiTech internal use
|
||||
|
||||
### Option B: Two Repository Split (Simpler)
|
||||
|
||||
1. **`control-framework`**
|
||||
- Contains: `ethercat-hal`, `control-core`, derive macros, `electron/`, `nixos/`
|
||||
- Purpose: Complete reusable control system framework (backend + UI + OS)
|
||||
- Published: Core crates to crates.io, UI could be npm package
|
||||
|
||||
2. **`control-qitech`**
|
||||
- Contains: `server/` machine implementations
|
||||
- Dependencies: Uses `control-framework` crates and UI
|
||||
- Purpose: QiTech-specific implementations
|
||||
|
||||
## Advantages of Current Monorepo Structure
|
||||
|
||||
1. **Faster Development**: No need to coordinate versions across repositories
|
||||
2. **Atomic Changes**: Changes that span multiple components can be done in a single commit
|
||||
3. **Simplified CI/CD**: Single build pipeline for all components
|
||||
4. **Easier Testing**: Integration tests can span all components
|
||||
5. **No Submodule Complexity**: Git submodules can be challenging to work with
|
||||
6. **Unified Documentation**: All docs in one place
|
||||
7. **Consistent Versioning**: Everything versioned together
|
||||
|
||||
## Advantages of Multi-Repository Structure
|
||||
|
||||
1. **Clear Boundaries**: Enforces separation of concerns at repository level
|
||||
2. **Independent Versioning**: Framework can have stable releases while QiTech-specific code evolves
|
||||
3. **Access Control**: Different teams can have different permissions
|
||||
4. **Selective Cloning**: Users only clone what they need
|
||||
5. **Public/Private Split**: Framework could be open-source while keeping QiTech-specific code private
|
||||
6. **Clearer Licensing**: Different licenses for different components
|
||||
7. **Smaller Repositories**: Faster clone times, less clutter
|
||||
|
||||
## Recommendations
|
||||
|
||||
### For Current Development (Monorepo)
|
||||
|
||||
The monorepo structure is appropriate for the current stage of development because:
|
||||
|
||||
1. The framework is still evolving rapidly alongside machine implementations
|
||||
2. The team is small and benefits from unified development workflow
|
||||
3. Breaking changes across layers can be handled atomically
|
||||
4. There's no immediate need to share the framework externally
|
||||
|
||||
**Best Practices to Maintain:**
|
||||
- Keep dependencies clean (framework crates should not depend on `server`)
|
||||
- Document public APIs in framework crates as if they were standalone
|
||||
- Write framework code generically without QiTech-specific assumptions
|
||||
- Keep machine-specific code isolated in `server/src/machines/`
|
||||
|
||||
### For Future (Multi-Repository)
|
||||
|
||||
Consider splitting when:
|
||||
|
||||
1. **Framework Stabilization**: When `ethercat-hal` and `control-core` APIs are stable enough for versioned releases
|
||||
2. **External Users**: When other companies/projects want to use the framework
|
||||
3. **Team Growth**: When separate teams are working on framework vs. machines
|
||||
4. **Open Source Plans**: If planning to open-source the framework while keeping machine implementations private
|
||||
|
||||
**Migration Path:**
|
||||
1. Extract `ethercat-hal` and `control-core` to `control-framework` repository
|
||||
2. Publish to crates.io with semantic versioning
|
||||
3. Update `server/Cargo.toml` to use published crates instead of path dependencies
|
||||
4. Optionally extract `electron/` as a separate UI package
|
||||
5. Keep `server/` as QiTech-specific implementation repository
|
||||
|
||||
## Current Approach: Virtual Separation
|
||||
|
||||
To get benefits of both approaches:
|
||||
|
||||
1. **Maintain Clean Boundaries**: Continue enforcing that framework crates don't depend on `server`
|
||||
2. **Documentation**: Document framework crates as standalone libraries
|
||||
3. **Testing**: Write tests for framework crates that don't depend on machine implementations
|
||||
4. **Cargo Workspaces**: Use workspace organization to group related crates
|
||||
5. **Future-Ready**: Write code assuming eventual split, making future extraction easier
|
||||
|
||||
## Workspace Organization
|
||||
|
||||
The workspace is organized to reflect logical grouping:
|
||||
|
||||
```toml
|
||||
[workspace]
|
||||
members = [
|
||||
# Framework crates (HAL layer)
|
||||
"ethercat-hal",
|
||||
"ethercat-hal-derive",
|
||||
|
||||
# Framework crates (Core layer)
|
||||
"control-core",
|
||||
"control-core-derive",
|
||||
|
||||
# Machine implementations
|
||||
"server",
|
||||
|
||||
# Utilities
|
||||
"ethercat-eeprom-dump",
|
||||
]
|
||||
```
|
||||
|
||||
This organization makes it clear which crates are part of the reusable framework and which are application-specific.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The current monorepo structure is well-suited for QiTech's needs at this stage. The codebase already has good logical separation between:
|
||||
- Reusable framework components (`ethercat-hal`, `control-core`)
|
||||
- Machine-specific implementations (`server`)
|
||||
- User interface (`electron`)
|
||||
- Deployment configuration (`nixos`)
|
||||
|
||||
The key is to maintain clean boundaries and follow best practices that would make a future split straightforward if needed. This gives QiTech the flexibility to evolve the architecture as requirements change without prematurely optimizing for a multi-repository structure.
|
||||
Reference in new issue
Block a user