Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
- name: Verify embedded binaries exist
run: |
set -euo pipefail
expected=(mini module6 module15 module32 original original-v2 plus revised-mini xl)
expected=(module6 module15 module32 original original-v2 plus xl)
missing=0
for bin in "${expected[@]}"; do
if [ -f "target/thumbv6m-none-eabi/release/$bin" ]; then
Expand All @@ -89,14 +89,12 @@ jobs:
with:
name: firmware-${{ github.sha }}
path: |
target/thumbv6m-none-eabi/release/mini
target/thumbv6m-none-eabi/release/module6
target/thumbv6m-none-eabi/release/module15
target/thumbv6m-none-eabi/release/module32
target/thumbv6m-none-eabi/release/original
target/thumbv6m-none-eabi/release/original-v2
target/thumbv6m-none-eabi/release/plus
target/thumbv6m-none-eabi/release/revised-mini
target/thumbv6m-none-eabi/release/xl
retention-days: 30

Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with th

## Project Overview

ProductionDeck is an open-source RP2040-based Stream Deck–compatible firmware in Rust (Embassy). Multiple **device profiles** (Mini, Classic/Mk.2, XL, Neo, +, modules, etc.) share the same codebase; each profile selects USB PID, layout, and **Legacy (Mini)** vs **Main/Expanded** HID handling. Physical hardware is often a small key matrix + one ST7735 region unless you build a larger layout.
ProductionDeck is an open-source RP2040-based Stream Deck–compatible firmware in Rust (Embassy). Multiple **device profiles** (Classic/Mk.2, XL, Neo, +, modules, etc.) share the same codebase; each profile selects USB PID, layout, and **Legacy (Mini-family)** vs **Main/Expanded** HID handling. Six-key Mini-class hardware is covered only by **`module6`** ([`Device::Module6Keys`]). Physical hardware is often a small key matrix + one ST7735 region unless you build a larger layout.

**Current Status**: Alpha - Firmware compiles successfully, ready for hardware testing.

Expand Down Expand Up @@ -50,7 +50,7 @@ cargo doc --open
## Project Structure

### Core Source Files
- `src/bin/*.rs` - One binary per target device (`mini`, `xl`, `mk2`, `neo`, `plus-xl`, …)
- `src/bin/*.rs` - One binary per target device (`module6`, `xl`, `mk2`, `neo`, `plus-xl`, …)
- `src/lib.rs` - Library root (`productiondeck` crate)
- `src/config.rs` - Hardware configuration constants and pin assignments
- `src/device/mod.rs` - USB PID, layout, and protocol family per `Device`
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 1 addition & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ portable-atomic = { version = "1.0", features = ["critical-section"] }
# Display and graphics
st7735-lcd = "0.10"
embedded-graphics = "0.8"
embedded-graphics-core = "0.4"

# USB HID
usbd-hid = "0.10"
Expand Down Expand Up @@ -66,18 +67,6 @@ debug = 2
incremental = false
opt-level = "z"

[[bin]]
name = "mini"
path = "src/bin/mini.rs"
test = false
bench = false

[[bin]]
name = "revised-mini"
path = "src/bin/revised_mini.rs"
test = false
bench = false

[[bin]]
name = "original"
path = "src/bin/original.rs"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ cargo install elf2uf2-rs flip-link
## Building

```bash
cargo build --release --bin mini
cargo build --release --bin module6
```

Other devices: `original`, `xl`, `plus`, `module6`, etc.
Expand Down
6 changes: 3 additions & 3 deletions build-devices.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ echo "=== ProductionDeck Multi-Device Build Script ==="
echo

# List of devices to build
devices=("mini" "revised-mini" "original" "original-v2" "xl" "plus")
devices=("original" "original-v2" "xl" "plus")

echo "Available device targets:"
for device in "${devices[@]}"; do
Expand Down Expand Up @@ -45,7 +45,7 @@ else
echo "All builds completed!"
echo
echo "Usage examples:"
echo " cargo run --release --bin mini # Run Mini firmware"
echo " cargo run --release --bin module6 # Module 6 / Mini-family firmware"
echo " cargo run --release --bin xl # Run XL firmware"
echo " ./build-devices.sh mini # Build only Mini firmware"
echo " ./build-devices.sh module6 # Build only Module 6 firmware"
fi
22 changes: 0 additions & 22 deletions src/bin/mini.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/bin/module6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const DEVICE: Device = Device::Module6Keys;
fn main() -> ! {
run_multicore(
DEVICE,
MulticoreCore0Layout::MiniOrModule6Direct,
MulticoreCore0Layout::Module6DirectTc00,
MulticoreCore1Buffer::B8192,
)
}
17 changes: 0 additions & 17 deletions src/bin/revised_mini.rs

This file was deleted.

17 changes: 13 additions & 4 deletions src/channels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
//! This module defines all the Embassy channels used for communication
//! between different tasks in the ProductionDeck application.

use crate::config::{DISPLAY_CHANNEL_CAPACITY, MULTICORE_CHANNEL_SIZE, USB_COMMAND_CHANNEL_SIZE};
use crate::types::{ButtonState, DisplayCommand, UsbCommand};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex};
use embassy_sync::channel::Channel;

/// Channel for button state communication from button task to USB task
Expand All @@ -13,8 +14,16 @@ pub static BUTTON_CHANNEL: Channel<ThreadModeRawMutex, ButtonState, 1> = Channel

/// Channel for USB commands from HID handler to other tasks
/// Buffer size: 4 (allows some buffering of commands)
pub static USB_COMMAND_CHANNEL: Channel<ThreadModeRawMutex, UsbCommand, 4> = Channel::new();
pub static USB_COMMAND_CHANNEL: Channel<ThreadModeRawMutex, UsbCommand, USB_COMMAND_CHANNEL_SIZE> =
Channel::new();

/// Channel for display commands to the display task
/// Buffer size: 8 (allows buffering of multiple display operations)
pub static DISPLAY_CHANNEL: Channel<ThreadModeRawMutex, DisplayCommand, 8> = Channel::new();
pub static DISPLAY_CHANNEL: Channel<ThreadModeRawMutex, DisplayCommand, DISPLAY_CHANNEL_CAPACITY> =
Channel::new();

/// Core 0 → Core 1 display commands (multicore builds). Uses [`MULTICORE_CHANNEL_SIZE`] slots.
pub static MULTICORE_IMAGE_CHANNEL: Channel<
CriticalSectionRawMutex,
DisplayCommand,
MULTICORE_CHANNEL_SIZE,
> = Channel::new();
14 changes: 13 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,24 @@ pub fn display_total_height() -> usize {

// USB Configuration
pub const USB_POLL_RATE_MS: u64 = 1; // 1ms USB polling (1000Hz)

pub const IMAGE_BUFFER_SIZE: usize = 1024; // 1KB buffer size

// Image processing optimization
pub const IMAGE_PROCESSING_BUFFER_SIZE: usize = 8192; // 8KB for image processing
pub const DISPLAY_BUFFER_SIZE: usize = 2048; // 2KB for display operations
pub const MULTICORE_CHANNEL_SIZE: usize = 8; // Increased channel size for better throughput

/// Queue depth for [`crate::channels::MULTICORE_IMAGE_CHANNEL`].
pub const MULTICORE_CHANNEL_SIZE: usize = 8;

/// Raw BMP accumulation cap for Module 6 chunked uploads.
pub const MODULE6_BMP_CAP: usize = 1024;

/// Depth of [`crate::channels::USB_COMMAND_CHANNEL`].
pub const USB_COMMAND_CHANNEL_SIZE: usize = 4;

/// Depth of [`crate::channels::DISPLAY_CHANNEL`].
pub const DISPLAY_CHANNEL_CAPACITY: usize = 8;

// ===================================================================
// Power Management: Idle Time (Sleep Mode)
Expand Down
64 changes: 12 additions & 52 deletions src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! abstracting away device-specific configurations, protocols, and capabilities.
//!
//! Protocol families (Elgato HID API):
//! - **Legacy / Mini family**: Mini, Mini 2022, Mini Discord, 6-key Module — distinct report layout.
//! - **Mini / 6-key Module**: [`Device::Module6Keys`] only (Mini-family HID); use `--bin module6`.
//! - **Main / Expanded family**: Classic, XL, Neo, Plus, Plus XL, 15/32-key Modules — see General Reference.

pub mod neo;
Expand Down Expand Up @@ -134,11 +134,7 @@ pub trait DeviceConfig {
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Device {
Mini = 0,
/// Mini 2022 (Elgato PID 0x0090)
RevisedMini = 1,
/// Mini Discord (0x00B3)
MiniDiscord = 2,
/// Runtime tags `0`…`2` are unused (removed Mini-family firmware SKUs).
/// First-gen Stream Deck (0x0060)
Original = 3,
/// Stream Deck 2019 (0x006D)
Expand Down Expand Up @@ -170,9 +166,6 @@ impl Device {
return None;
}
match tag {
0 => Some(Device::Mini),
1 => Some(Device::RevisedMini),
2 => Some(Device::MiniDiscord),
3 => Some(Device::Original),
4 => Some(Device::OriginalV2),
5 => Some(Device::Mk2),
Expand All @@ -191,9 +184,6 @@ impl Device {

pub fn pid(&self) -> u16 {
match self {
Device::Mini => 0x0063,
Device::RevisedMini => 0x0090,
Device::MiniDiscord => 0x00B3,
Device::Original => 0x0060,
Device::OriginalV2 => 0x006d,
Device::Mk2 => 0x0080,
Expand Down Expand Up @@ -221,9 +211,7 @@ impl Device {
Device::Plus => (2u8, 4u8, 120u16, 120u16, 800u16, 480u16),
Device::PlusXl => (4u8, 9u8, 112u16, 112u16, 1280u16, 800u16),
Device::Neo => (2u8, 4u8, 96u16, 96u16, 480u16, 320u16),
Device::Mini | Device::RevisedMini | Device::MiniDiscord | Device::Module6Keys => {
(2u8, 3u8, 80u16, 80u16, 320u16, 240u16)
}
Device::Module6Keys => (2u8, 3u8, 80u16, 80u16, 320u16, 240u16),
Device::Original => (3u8, 5u8, 72u16, 72u16, 480u16, 272u16),
};
let mut b = [0u8; 16];
Expand Down Expand Up @@ -271,9 +259,6 @@ impl Device {
impl DeviceConfig for Device {
fn device_name(&self) -> &'static str {
match self {
Device::Mini => "StreamDeck Mini",
Device::RevisedMini => "StreamDeck Mini 2022",
Device::MiniDiscord => "StreamDeck Mini Discord",
Device::Original => "StreamDeck Original",
Device::OriginalV2 => "StreamDeck Classic (2019)",
Device::Mk2 => "StreamDeck Mk.2",
Expand All @@ -298,9 +283,7 @@ impl DeviceConfig for Device {

fn button_layout(&self) -> ButtonLayout {
match self {
Device::Mini | Device::RevisedMini | Device::MiniDiscord | Device::Module6Keys => {
ButtonLayout::new(3, 2, true)
}
Device::Module6Keys => ButtonLayout::new(3, 2, true),
Device::Module15Keys | Device::OriginalV2 | Device::Mk2 | Device::Mk2ScissorKeys => {
ButtonLayout::new(5, 3, true)
}
Expand All @@ -313,16 +296,14 @@ impl DeviceConfig for Device {

fn display_config(&self) -> DisplayConfig {
match self {
Device::Mini | Device::RevisedMini | Device::MiniDiscord | Device::Module6Keys => {
DisplayConfig {
image_width: 80,
image_height: 80,
format: ImageFormat::Bmp,
needs_rotation: true,
flip_horizontal: false,
flip_vertical: false,
}
}
Device::Module6Keys => DisplayConfig {
image_width: 80,
image_height: 80,
format: ImageFormat::Bmp,
needs_rotation: true,
flip_horizontal: false,
flip_vertical: false,
},
Device::Module15Keys | Device::OriginalV2 | Device::Mk2 | Device::Mk2ScissorKeys => {
DisplayConfig {
image_width: 72,
Expand Down Expand Up @@ -378,27 +359,6 @@ impl DeviceConfig for Device {

fn usb_config(&self) -> UsbConfig {
match self {
Device::Mini => UsbConfig {
vid: 0x0fd9,
pid: 0x0063,
product_name: "Stream Deck Mini",
manufacturer: "Elgato Systems",
protocol: ProtocolVersion::V1,
},
Device::RevisedMini => UsbConfig {
vid: 0x0fd9,
pid: 0x0090,
product_name: "Stream Deck Mini",
manufacturer: "Elgato Systems",
protocol: ProtocolVersion::V1,
},
Device::MiniDiscord => UsbConfig {
vid: 0x0fd9,
pid: 0x00B3,
product_name: "Stream Deck Mini",
manufacturer: "Elgato Systems",
protocol: ProtocolVersion::V1,
},
Device::Original => UsbConfig {
vid: 0x0fd9,
pid: 0x0060,
Expand Down
Loading
Loading