Compare commits

...
8 changed files with 1342 additions and 16 deletions

No files matched your search

+9 -2
View File
@@ -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"
+32 -13
View File
@@ -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
+5
View File
@@ -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
![](./assets/architecture-overview.png)
## The Application is Split Into 3 Main Layers
+346
View File
@@ -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.
+13 -1
View File
@@ -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
+498
View File
@@ -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.
+157
View File
@@ -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)
+282
View File
@@ -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.