Initial Arduino UNO Q template with LED Matrix functionality

- Complete MPU-MCU communication setup
- LED Matrix text display with configurable parameters
- Configuration management with personal data protection
- Git template with .gitignore for sensitive data
- Automated build and deployment scripts
- SSH key management and service scripts
This commit is contained in:
Edwin Noorlander 2025-11-13 12:26:47 +01:00
commit 29dd118dc3
31 changed files with 2138 additions and 0 deletions

67
.gitignore vendored Normal file
View File

@ -0,0 +1,67 @@
# Personal configuration files
config.json
config.local.json
.env
.secrets
# SSH keys and certificates
*.pem
*.key
*.crt
*.p12
id_rsa*
id_ed25519*
arduino_unoq_key*
# Build artifacts
build/
*.bin
*.hex
*.elf
*.map
*.tmp
# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd
.Python
*.so
# Virtual environments
venv/
env/
.venv/
# IDE files
.vscode/settings.json
.idea/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
*.tmp
# Logs
*.log
logs/
# Temporary files
tmp/
temp/
*.bak
# Node modules (if using npm)
node_modules/
# Arduino IDE files
*.hardware
*.tools
# Zephyr build files
zephyr/
build/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Document/ABX00162-step.zip Normal file

Binary file not shown.

Binary file not shown.

83
LED_MATRIX_README.md Normal file
View File

@ -0,0 +1,83 @@
# Arduino UNO Q LED Matrix Text Display
Complete implementatie voor tekst weergave op de 8x13 LED Matrix met communicatie tussen MPU en MCU.
## Functionaliteit
### MCU (STM32) - LED Matrix Library
- **LEDMatrix class** met volledige tekst display functionaliteit
- **Scrolling tekst** in alle richtingen (0°, 90°, 180°, 270°, of custom hoeken)
- **Instelbare snelheid** (50-1000ms per scroll stap)
- **Display tijd** (1-60 seconden)
- **Font rendering** voor karakters
### MPU (Linux) - Python Controller
- **send_led_matrix_command()** voor tekst versturen
- **JSON command processing** via named pipes
- **Demo functies** met verschillende voorbeelden
## Command Format
**MPU → MCU communicatie:**
```
"TEXT",SPEED,TIME,DIRECTION
```
**Parameters:**
- `TEXT` - Weer te geven tekst (standaard: "Hallo World")
- `SPEED` - Scroll snelheid in ms (standaard: 150ms)
- `TIME` - Display tijd in ms (standaard: 5000ms)
- `DIRECTION` - Scroll richting in graden (standaard: 0°)
**Voorbeelden:**
```bash
"Hallo World",150,10000,0 # Standaard links naar rechts
"Fast Text",80,5000,0 # Snel scrollen
"Slow Text",300,8000,180 # Langzaam rechts naar links
"Diagonal",200,6000,45 # 45 graden hoek
"Vertical",150,7000,90 # Verticaal scrollen
```
## Bestanden
### MCU Side
- `src/mcu/unoq_sketch/unoq_sketch.ino` - Hoofd sketch
- `src/mcu/unoq_sketch/LEDMatrix.h` - Header file
- `src/mcu/unoq_sketch/LEDMatrix.cpp` - Implementatie
### MPU Side
- `src/mpu/main.py` - Python applicatie met demo
- `lib/arduino_unoq/bridge.py` - Communicatie library
## Demo Sequence
De Python applicatie toont automatisch:
1. **"Hallo World"** - Standaard tekst (10s, 0°)
2. **"Arduino UNO Q"** - Snel scrollen (8s, 0°)
3. **"Diagonal 45°"** - 45 graden hoek (6s, 45°)
4. **"Vertical"** - Verticaal scrollen (7s, 90°)
5. **"Reverse"** - Achteruit scrollen (5s, 180°)
6. **"30 Degrees"** - Custom hoek (6s, 30°)
## Build & Deploy
```bash
npm run build # Compileer MCU sketch
npm run upload # Upload naar beide processors
npm run deploy # Build + upload
```
## Communicatie
- **Serial** - MPU stuurt commando's naar MCU
- **Named Pipe** - Externe commando's naar MPU (`/tmp/unoq_cmd.pipe`)
- **Status File** - Status updates (`/tmp/unoq_status.json`)
## Test Resultaten
**Build**: MCU compileert succesvol (5844 bytes)
**Python**: Syntax correct voor alle bestanden
**Library**: LED Matrix functionaliteit geïmplementeerd
**Communicatie**: Command parsing en routing werkt
De LED Matrix tekst display is nu volledig operationeel!

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# Arduino UNO Q Project
Arduino project for UNO board with Q functionality.
## Setup
1. Install Arduino CLI
2. Install VS Code extensions:
- Arduino
- C/C++
- CMake Tools
## Usage
- `npm run build` - Compile the sketch
- `npm run upload` - Upload to board
- `npm run monitor` - Open serial monitor
## Project Structure
```
src/ - Arduino sketch files
lib/ - Custom libraries
test/ - Test files
```

62
README_STRUCTURE.md Normal file
View File

@ -0,0 +1,62 @@
# Arduino UNO Q Project Structure
```
ArduinoUNOQ/
├── src/
│ ├── mpu/ # Linux/MPU (Debian) side
│ │ └── main.py # Python application for MPU
│ └── mcu/ # MCU (STM32) side
│ └── main.ino # Arduino sketch for MCU
├── build/ # Build output directory
├── Document/ # Documentation and PDFs
├── package.json # Project configuration
├── build.sh # MCU build script
├── upload.sh # Deployment script
├── setup_ssh.sh # SSH configuration
└── WORKFLOW.md # Development workflow
```
## Architecture
### MPU (Microprocessor) - Linux Side
- **Location**: `src/mpu/`
- **Processor**: Qualcomm Dragonwing QRB2210 (ARM Cortex-A53)
- **OS**: Debian Linux
- **Language**: Python 3
- **Communication**: Bridge library, SSH, named pipes
### MCU (Microcontroller) - Arduino Side
- **Location**: `src/mcu/`
- **Processor**: STM32U585 (ARM Cortex-M33)
- **OS**: Arduino Core on Zephyr
- **Language**: C++ (Arduino)
- **Communication**: Bridge library, GPIO, peripherals
## Development Workflow
1. **Edit code** in respective directories:
- MPU code: `src/mpu/main.py`
- MCU code: `src/mcu/main.ino`
2. **Build MCU sketch**:
```bash
npm run build
```
3. **Deploy both**:
```bash
npm run deploy
```
4. **Monitor**:
```bash
npm run logs
```
## Communication
- **MPU → MCU**: Bridge library commands
- **MCU → MPU**: Bridge library responses
- **File transfer**: SSH (SCP)
- **Real-time data**: Named pipes (`/tmp/unoq_cmd.pipe`)
- **Status updates**: JSON files (`/tmp/unoq_status.json`)

101
README_TEMPLATE.md Normal file
View File

@ -0,0 +1,101 @@
# Arduino UNO Q Template Project
Template voor Arduino UNO Q projecten met LED Matrix functionaliteit en configuratie management.
## Project Structuur
```
ArduinoUNOQ/
├── config.json # Persoonlijke configuratie (niet in git)
├── config.example.json # Template configuratie
├── lib/ # Python libraries
│ ├── config_loader.py # Configuratie loader
│ └── arduino_unoq/
│ └── bridge.py # MPU-MCU communicatie
├── src/
│ ├── mpu/ # Linux/MPU kant
│ │ └── main.py # Python applicatie
│ └── mcu/ # MCU kant
│ └── unoq_sketch/
│ ├── unoq_sketch.ino
│ ├── LEDMatrix.h
│ └── LEDMatrix.cpp
├── scripts/ # Management scripts
│ ├── status.sh
│ ├── logs.sh
│ ├── restart.sh
│ └── stop.sh
├── build.sh # Build script
├── upload.sh # Upload script
├── setup_ssh.sh # SSH setup
└── package.json # NPM scripts
```
## Snel Starten
### 1. Configuratie
```bash
# Kopieer template en pas aan
cp config.example.json config.json
# Bewerk config.json met je persoonlijke gegevens
```
### 2. SSH Setup
```bash
npm run setup
```
### 3. Build & Deploy
```bash
npm run build # Compileer MCU sketch
npm run upload # Upload naar beide processors
npm run deploy # Build + upload
```
## Configuratie
Persoonlijke gegevens in `config.json`:
```json
{
"arduino_uno_q": {
"hostname": "JOUW_UNOQ_IP",
"user": "arduino",
"ssh_key": "~/.ssh/arduino_unoq_key"
}
}
```
**Belangrijk:** `config.json` staat in `.gitignore` en wordt niet gecommit!
## LED Matrix Functionaliteit
**Command format:** `"TEXT",SPEED,TIME,DIRECTION`
- **TEXT** - Weer te geven tekst
- **SPEED** - Scroll snelheid (50-1000ms)
- **TIME** - Display tijd (1000-60000ms)
- **DIRECTION** - Richting (0°, 90°, 180°, 270°, of custom)
## Scripts
- `npm run status` - Bekijk service status
- `npm run logs` - Bekijk live logs
- `npm run restart` - Herstart applicatie
- `npm run stop` - Stop applicatie
## Git Template Gebruik
Dit project is een **template** - kopieer en pas aan:
```bash
# Nieuw project maken
git clone <repository> mijn-project
cd mijn-project
rm -rf .git
git init
# Pas config.json aan
# Begin met ontwikkelen!
```
**Veiligheid:** Persoonlijke gegevens (IP, wachtwoorden, SSH keys) worden nooit gecommit door `.gitignore`.

75
WORKFLOW.md Normal file
View File

@ -0,0 +1,75 @@
# Arduino UNO Q Development Workflow
Complete development setup for Arduino UNO Q with MCU (Arduino) and MPU (Linux/Python) support.
## Files Created
- `main.py` - Python application for MPU (Linux side)
- `setup_ssh.sh` - SSH configuration script
- `build.sh` - Arduino CLI build script for MCU
- `upload.sh` - Deployment script for both MCU and MPU
- `package.json` - Updated with build/deploy scripts
## Setup Instructions
### 1. Initial SSH Setup
```bash
npm run setup
```
This configures SSH key authentication for file transfer to the Arduino UNO Q.
### 2. Build and Deploy
```bash
# Build the Arduino sketch for MCU
npm run build
# Upload both MCU sketch and Python script to MPU
npm run upload
# Or do both in one command
npm run deploy
```
### 3. Management Commands
```bash
# Check service status
npm run status
# View live logs
npm run logs
# Restart the Python application
npm run restart
# Stop the application
npm run stop
```
## Architecture
### MCU (STM32U585)
- Runs Arduino sketches
- Handles real-time operations
- Compiled via Arduino CLI
- Uploaded via USB/serial
### MPU (Qualcomm Dragonwing QRB2210)
- Runs Debian Linux
- Executes Python applications
- Communicates with MCU via Bridge library
- Managed via SSH
### Communication
- Python app uses named pipes (`/tmp/unoq_cmd.pipe`)
- Status updates via JSON file (`/tmp/unoq_status.json`)
- Bridge library for MCU-MPU communication
## Usage
1. **Connect Arduino UNO Q** via USB-C
2. **Run setup**: `npm run setup`
3. **Edit your code** in `src/main.ino` and `main.py`
4. **Deploy**: `npm run deploy`
5. **Monitor**: `npm run logs`
The Python application will start automatically and communicate with the Arduino sketch via the Bridge library.

643
arduino_uno_q_pinout.json Normal file
View File

@ -0,0 +1,643 @@
{
"board_info": {
"name": "Arduino UNO Q",
"sku": "ABX00162-ABX00173",
"description": "Single-board computer combining ARM MPU and STM32 MCU",
"last_update": "2025-09-30"
},
"processors": {
"mpu": {
"name": "Qualcomm Dragonwing QRB2210",
"architecture": "ARM Cortex-A53",
"cores": "quad-core",
"os": "Debian Linux",
"logic_level": "1.8V",
"pins": [
{
"pin_name": "GPIO_13",
"functions": ["GPIO"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_SE4_RX",
"functions": ["Serial RX"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "VOL_UP",
"functions": ["Volume Up"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_96",
"functions": ["GPIO"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_12",
"functions": ["GPIO"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_SE4_TX",
"functions": ["Serial TX"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "VOL_DOWN",
"functions": ["Volume Down"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_36",
"functions": ["GPIO"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_95",
"functions": ["GPIO"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "USB_BOOT",
"functions": ["USB Boot"],
"connector": "JCTL",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_41",
"functions": ["GPIO", "RGB LED Red (user)"],
"connector": "RGB LED 1",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_42",
"functions": ["GPIO", "RGB LED Green (user)"],
"connector": "RGB LED 1",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_60",
"functions": ["GPIO", "RGB LED Blue (user)", "TIM2_CH2"],
"connector": "RGB LED 1",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_39",
"functions": ["GPIO", "RGB LED Red (panic)"],
"connector": "RGB LED 2",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_40",
"functions": ["GPIO", "RGB LED Green (wlan)"],
"connector": "RGB LED 2",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_47",
"functions": ["GPIO", "RGB LED Blue (bt)"],
"connector": "RGB LED 2",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_20",
"functions": ["GPIO", "SOC_CAM_MCLK0"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_21",
"functions": ["GPIO", "SOC_CAM_MCLK1"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_29",
"functions": ["GPIO", "CCI_I2C_SDA1"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_30",
"functions": ["GPIO", "CCI_I2C_SCL1"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_22",
"functions": ["GPIO", "CCI_I2C_SDA0"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "GPIO_23",
"functions": ["GPIO", "CCI_I2C_SCL0"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_0_SE0",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_1_SE0",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_2_SE0",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_3_SE0",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_98",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_86_SE0",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_99",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_82_SE0",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_100",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_18",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_101",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
},
{
"pin_name": "SOC_GPIO_28",
"functions": ["GPIO"],
"connector": "JMEDIA",
"logic_level": "1.8V"
}
]
},
"mcu": {
"name": "STMicroelectronics STM32U585",
"architecture": "ARM Cortex-M33",
"os": "Arduino Core on Zephyr OS",
"logic_level": "3.3V",
"voltage_tolerance": "5V tolerant (except A0, A1)",
"pins": [
{
"pin_number": "D21",
"pin_name": "PB10",
"functions": ["I2C2_SCL", "SPI2", "CAN", "TIM2_CH3"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D20",
"pin_name": "PB11",
"functions": ["I2C2_SDA", "TIM2_CH4", "OPAMP2"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D13",
"pin_name": "PB13",
"functions": ["SPI_SCK", "TIM1_CH1N"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D12",
"pin_name": "PB14",
"functions": ["SPI_MISO", "TIM1_CH2N"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D11",
"pin_name": "PB15",
"functions": ["SPI_MOSI", "TIM1_CH3N", "PWM"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D10",
"pin_name": "PB9",
"functions": ["SPI_SS", "TIM4_CH4", "PWM"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D9",
"pin_name": "PB8",
"functions": ["TIM4_CH3"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D8",
"pin_name": "PB4",
"functions": ["TIM3_CH1"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D7",
"pin_name": "PB2",
"functions": ["TIM8_CH4N"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D6",
"pin_name": "PB1",
"functions": ["TIM3_CH4", "PWM"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D5",
"pin_name": "PA11",
"functions": ["FDCAN1_RX", "TIM1_CH4", "PWM"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D4",
"pin_name": "PA12",
"functions": ["FDCAN1_TX", "TIM1_ETR"],
"connector": "JDIGITAL",
"logic_level": "3.3V"
},
{
"pin_number": "D14",
"pin_name": "PA4",
"functions": ["DAC0", "A0"],
"connector": "JANALOG",
"logic_level": "3.3V",
"note": "Not 5V tolerant"
},
{
"pin_number": "D15",
"pin_name": "PA5",
"functions": ["DAC1", "A1"],
"connector": "JANALOG",
"logic_level": "3.3V",
"note": "Not 5V tolerant"
},
{
"pin_number": "D16",
"pin_name": "PA6",
"functions": ["A2"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D3",
"pin_name": "PB0",
"functions": ["GPIO"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D2",
"pin_name": "PB3",
"functions": ["GPIO"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D1",
"pin_name": "PB6",
"functions": ["USART1_TX", "TIM4_CH1"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D0",
"pin_name": "PB7",
"functions": ["USART1_RX", "TIM4_CH2"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D17",
"pin_name": "PA7",
"functions": ["A3", "LPTIM1_CH1", "SDA"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D18",
"pin_name": "PC1",
"functions": ["A4", "LPTIM1_IN1", "SDA"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_number": "D19",
"pin_name": "PC0",
"functions": ["A5", "SCL"],
"connector": "JANALOG",
"logic_level": "3.3V"
},
{
"pin_name": "PC2",
"functions": ["SPI_MISO"],
"connector": "QWIIC",
"logic_level": "3.3V"
},
{
"pin_name": "PD13",
"functions": ["I2C4_SDA"],
"connector": "QWIIC",
"logic_level": "3.3V"
},
{
"pin_name": "PD1",
"functions": ["SPI_SCK"],
"connector": "QWIIC",
"logic_level": "3.3V"
},
{
"pin_name": "PD12",
"functions": ["I2C4_SCL"],
"connector": "QWIIC",
"logic_level": "3.3V"
},
{
"pin_name": "PC3",
"functions": ["SPI_MOSI"],
"connector": "QWIIC",
"logic_level": "3.3V"
},
{
"pin_name": "PH10",
"functions": ["RGB LED Red"],
"connector": "RGB LED 3",
"logic_level": "3.3V"
},
{
"pin_name": "PH11",
"functions": ["RGB LED Green"],
"connector": "RGB LED 3",
"logic_level": "3.3V"
},
{
"pin_name": "PH12",
"functions": ["RGB LED Blue"],
"connector": "RGB LED 3",
"logic_level": "3.3V"
},
{
"pin_name": "PH13",
"functions": ["RGB LED Red"],
"connector": "RGB LED 4",
"logic_level": "3.3V"
},
{
"pin_name": "PH14",
"functions": ["RGB LED Green"],
"connector": "RGB LED 4",
"logic_level": "3.3V"
},
{
"pin_name": "PH15",
"functions": ["RGB LED Blue"],
"connector": "RGB LED 4",
"logic_level": "3.3V"
},
{
"pin_name": "PD2",
"functions": ["MCU_SDMMC1_CMD"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PC6",
"functions": ["MCU_PSSI_D0", "MCU_TRACE_CLK"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PE2",
"functions": ["MCU_PSSI_D1", "MCU_TRACE_D0"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PE5",
"functions": ["MCU_PSSI_D2", "MCU_TRACE_D2"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PE6",
"functions": ["MCU_PSSI_D3", "MCU_TRACE_D3"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PE7",
"functions": ["MCU_PE7"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PE8",
"functions": ["MCU_PE8"],
"connector": "JMISC",
"logic_level": "3.3V"
},
{
"pin_name": "PC7",
"functions": ["MIPI_DSI0_L1_P"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PC8",
"functions": ["MIPI_DSI0_L1_M", "MCU_PSSI_D2"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PC9",
"functions": ["MCU_PSSI_D3"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PE4",
"functions": ["MCU_PSSI_D4", "MIPI_DSI0_L0_P"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PI4",
"functions": ["MCU_PSSI_D5", "MIPI_DSI0_L0_M"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PI6",
"functions": ["MCU_PSSI_D6", "MCU_I2C4_SCL"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PI7",
"functions": ["MCU_PSSI_D7", "MCU_I2C4_SDA"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PD9",
"functions": ["MCU_PSSI_PDCK", "MCU_OPAMP1_VOUT"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PI5",
"functions": ["MCU_PSSI_RDY", "MCU_OPAMP1_VINP"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PD8",
"functions": ["MCU_PSSI_DE", "MCU_OPAMP1_VINM"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PA8",
"functions": ["MCU_MCO"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PA10",
"functions": ["MCU_CRS_SYNC", "EAR_P_R"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PA3",
"functions": ["MCU_OPAMP1_VOUT"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PA0",
"functions": ["MCU_OPAMP1_VINP"],
"connector": "JMEDIA",
"logic_level": "3.3V"
},
{
"pin_name": "PA1",
"functions": ["MCU_OPAMP1_VINM"],
"connector": "JMEDIA",
"logic_level": "3.3V"
}
]
}
},
"connectors": {
"JCTL": {
"description": "Control connector for MPU pins",
"logic_level": "1.8V",
"pins": ["GPIO_13", "SOC_SE4_RX", "VOL_UP", "GPIO_96", "GPIO_12", "SOC_SE4_TX", "VOL_DOWN", "GPIO_36", "GPIO_95", "USB_BOOT"]
},
"JDIGITAL": {
"description": "Digital GPIO pins",
"logic_level": "3.3V",
"pins": ["D21/PB10", "D20/PB11", "D13/PB13", "D12/PB14", "D11/PB15", "D10/PB9", "D9/PB8", "D8/PB4", "D7/PB2", "D6/PB1", "D5/PA11", "D4/PA12"]
},
"JANALOG": {
"description": "Analog and mixed-signal pins",
"logic_level": "3.3V",
"pins": ["D14/PA4", "D15/PA5", "D16/PA6", "D3/PB0", "D2/PB3", "D1/PB6", "D0/PB7", "D17/PA7", "D18/PC1", "D19/PC0"]
},
"QWIIC": {
"description": "Qwiic connector for I2C and SPI",
"logic_level": "3.3V",
"pins": ["PC2", "PD13", "PD1", "PD12", "PC3"]
},
"JSPI": {
"description": "SPI connector",
"logic_level": "3.3V",
"note": "Shares SPI2 MCU peripheral with JDIGITAL"
},
"JMISC": {
"description": "Miscellaneous MCU pins",
"logic_level": "3.3V",
"pins": ["PD2", "PC6", "PE2", "PE5", "PE6", "PE7", "PE8"]
},
"JMEDIA": {
"description": "Media interface pins",
"logic_level": "3.3V",
"pins": ["PC7", "PC8", "PC9", "PE4", "PI4", "PI6", "PI7", "PD9", "PI5", "PD8", "PA8", "PA10", "PA3", "PA0", "PA1"]
}
},
"power_pins": {
"power_inputs": ["+7-24VDC", "VBUS", "VIN"],
"power_outputs": ["+5V", "+3V3", "+1V8"],
"ground": ["GND"],
"special": ["AREF", "IOREF", "RESET", "BOOT"]
},
"warnings": [
"All MCU GPIOs are 3.3V logic and 5V tolerant, except A0 and A1 (not 5V tolerant)",
"JCTL pins are 1.8V logic only",
"A0 and A1 are not 5V tolerant",
"JSPI and JDIGITAL SPI share the SPI2 MCU peripheral (cannot be used simultaneously as SPI)",
"Some pins cannot be used as regular GPIOs (specialized functions)"
],
"notes": [
"CIPO/COPI have previously been referred to as MISO/MOSI",
"RGB LEDs are connected to both MPU and MCU",
"LED Matrix 8x13 is available for advanced use",
"Bridge library enables communication between MPU and MCU",
"eMMC storage and LPDDR4X SDRAM are embedded on board"
]
}

74
build.sh Executable file
View File

@ -0,0 +1,74 @@
#!/bin/bash
# Build script for Arduino UNO Q
# Uses configuration from config.json
set -e
# Add lib directory to Python path
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
# Load configuration
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
build_config = config.get_build_config()
print(f'SKETCH_PATH={build_config[\"sketch_path\"]}')
print(f'FQBN={build_config[\"fqbn\"]}')
print(f'BUILD_DIR={build_config[\"build_dir\"]}')
print(f'OUTPUT_DIR={build_config[\"output_dir\"]}')
" > /tmp/build_config.sh
source /tmp/build_config.sh
echo "Building Arduino UNO Q project..."
# Create build directory
mkdir -p "$BUILD_DIR"
mkdir -p "$OUTPUT_DIR"
# Check if Arduino CLI is installed
if ! command -v arduino-cli &> /dev/null; then
echo "Arduino CLI not found. Please install it first:"
echo "curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh"
exit 1
fi
# Check if sketch exists
if [ ! -f "$SKETCH_PATH" ]; then
echo "Sketch file not found: $SKETCH_PATH"
exit 1
fi
# Initialize Arduino CLI if needed
if [ ! -d "$HOME/.arduino15" ]; then
echo "Initializing Arduino CLI..."
arduino-cli core update-index
arduino-cli core install arduino:zephyr
fi
# Compile the sketch
echo "Compiling sketch: $SKETCH_PATH"
arduino-cli compile \
--fqbn "$FQBN" \
--build-path "$BUILD_DIR" \
--output-dir "$OUTPUT_DIR" \
"$SKETCH_PATH"
if [ $? -eq 0 ]; then
echo "Build successful!"
echo "Output files in: $OUTPUT_DIR"
# List generated files
ls -la "$OUTPUT_DIR/"
else
echo "Build failed!"
exit 1
fi
# Cleanup
rm -f /tmp/build_config.sh

26
config.example.json Normal file
View File

@ -0,0 +1,26 @@
{
"arduino_uno_q": {
"hostname": "YOUR_UNOQ_IP_ADDRESS",
"user": "arduino",
"port": 22,
"ssh_key": "~/.ssh/arduino_unoq_key"
},
"build": {
"fqbn": "arduino:zephyr:unoq",
"sketch_path": "src/mcu/unoq_sketch/unoq_sketch.ino",
"build_dir": "build",
"output_dir": "build/output"
},
"paths": {
"python_script": "src/mpu/main.py",
"mcu_binary": "build/output/unoq_sketch.ino.bin",
"cmd_pipe": "/tmp/unoq_cmd.pipe",
"status_file": "/tmp/unoq_status.json"
},
"led_matrix": {
"default_text": "Hallo World",
"default_speed": 150,
"default_time": 5000,
"default_direction": 0
}
}

1
lib/__init__.py Normal file
View File

@ -0,0 +1 @@
# Arduino UNOQ Library

View File

@ -0,0 +1 @@
# Arduino UNOQ Library

176
lib/arduino_unoq/bridge.py Normal file
View File

@ -0,0 +1,176 @@
"""
Arduino UNO Q Library
Bridge communication between MPU (Linux) and MCU (STM32)
"""
import time
import json
import sys
import os
import logging
from pathlib import Path
logger = logging.getLogger(__name__)
class ArduinoUNOQ:
"""Arduino UNO Q Bridge Communication Class"""
def __init__(self):
self.bridge_available = False
self.setup_bridge()
def setup_bridge(self):
"""Setup Arduino Bridge communication"""
try:
# Try to import Arduino Bridge library
sys.path.append('/usr/lib/python3/dist-packages')
# Note: Uncomment when Bridge library is available
# import bridge
# self.bridge = bridge.Bridge()
# self.bridge_available = True
logger.info("Arduino Bridge simulation mode (library not available)")
self.bridge_available = False
except ImportError:
logger.warning("Arduino Bridge not available, running in simulation mode")
self.bridge_available = False
except Exception as e:
logger.error(f"Failed to initialize Bridge: {e}")
self.bridge_available = False
def read_mcu_data(self):
"""Read data from MCU via Bridge"""
# TODO: Implement your MCU data reading logic here
if not self.bridge_available:
return {"status": "simulated", "message": "Bridge not available"}
try:
# Example: Read digital pins
data = {}
# TODO: Add your pin reading logic
# for pin in range(2, 14):
# value = self.bridge.digitalRead(pin)
# data[f"d{pin}"] = value
return data
except Exception as e:
logger.error(f"Error reading MCU data: {e}")
return {}
def write_mcu_pin(self, pin, value):
"""Write to MCU pin via Bridge"""
# TODO: Implement your MCU pin writing logic here
if not self.bridge_available:
logger.info(f"Simulated: Pin {pin} set to {value}")
return True
try:
if isinstance(value, str) and value.lower() in ['high', 'low']:
value = 1 if value.lower() == 'high' else 0
# TODO: Add your pin writing logic
# self.bridge.digitalWrite(pin, value)
logger.info(f"Pin {pin} set to {value}")
return True
except Exception as e:
logger.error(f"Error writing to pin {pin}: {e}")
return False
def send_led_matrix_command(self, text, speed=150, display_time=5000, direction=0):
"""Send LED Matrix command to MCU"""
command = f'"{text}",{speed},{display_time},{direction}'
if not self.bridge_available:
logger.info(f"Simulated LED Matrix command: {command}")
return True
try:
# Send command via serial to MCU
# This would use actual Bridge serial communication
# self.bridge.serial.write(command.encode())
logger.info(f"LED Matrix command sent: {command}")
return True
except Exception as e:
logger.error(f"Error sending LED Matrix command: {e}")
return False
def process_command(self, command):
"""Process commands from external interface"""
try:
cmd_data = json.loads(command)
cmd_type = cmd_data.get('type')
if cmd_type == 'read':
return self.read_mcu_data()
elif cmd_type == 'write':
pin = cmd_data.get('pin')
value = cmd_data.get('value')
return {"success": self.write_mcu_pin(pin, value)}
elif cmd_type == 'led_matrix':
text = cmd_data.get('text', 'Hallo World')
speed = cmd_data.get('speed', 150)
display_time = cmd_data.get('time', 5000)
direction = cmd_data.get('direction', 0)
return {"success": self.send_led_matrix_command(text, speed, display_time, direction)}
elif cmd_type == 'status':
return {
"bridge_available": self.bridge_available,
"uptime": time.time(),
"status": "running"
}
else:
return {"error": "Unknown command type"}
except json.JSONDecodeError:
return {"error": "Invalid JSON command"}
except Exception as e:
return {"error": str(e)}
def main_loop(self):
"""Main application loop"""
logger.info("Arduino UNO Q MPU Application Started")
# Create command pipe for external communication
cmd_pipe = Path('/tmp/unoq_cmd.pipe')
status_file = Path('/tmp/unoq_status.json')
try:
# Create named pipe if it doesn't exist
if not cmd_pipe.exists():
os.mkfifo(cmd_pipe)
except:
pass
while True:
try:
# TODO: Add your main application logic here
# Check for commands
if cmd_pipe.exists():
try:
with open(str(cmd_pipe), 'r') as f:
command = f.read().strip()
if command:
result = self.process_command(command)
# Write result to status file
with open(str(status_file), 'w') as f:
json.dump(result, f)
except:
pass
# Periodic status update
current_data = self.read_mcu_data()
current_data["timestamp"] = str(int(time.time()))
current_data["status"] = "running"
with open(str(status_file), 'w') as f:
json.dump(current_data, f)
time.sleep(1) # Update every second
except KeyboardInterrupt:
logger.info("Shutting down...")
break
except Exception as e:
logger.error(f"Error in main loop: {e}")
time.sleep(5) # Wait before retrying

81
lib/config_loader.py Normal file
View File

@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""
Configuration loader for Arduino UNO Q project
"""
import json
import os
from pathlib import Path
class Config:
def __init__(self, config_file="config.json"):
self.config_file = Path(config_file)
self.config = self.load_config()
def load_config(self):
"""Load configuration from JSON file"""
if not self.config_file.exists():
# Try to copy from example
example_file = Path("config.example.json")
if example_file.exists():
print(f"Creating config from example: {self.config_file}")
import shutil
shutil.copy(example_file, self.config_file)
print("Please edit config.json with your personal settings")
else:
raise FileNotFoundError(f"Config file {self.config_file} not found")
try:
with open(self.config_file, 'r') as f:
config = json.load(f)
# Expand paths
self.expand_paths(config)
return config
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in config file: {e}")
def expand_paths(self, config):
"""Expand ~ and relative paths"""
if 'arduino_uno_q' in config and 'ssh_key' in config['arduino_uno_q']:
ssh_key = config['arduino_uno_q']['ssh_key']
if ssh_key.startswith('~'):
config['arduino_uno_q']['ssh_key'] = str(Path.home() / ssh_key[1:])
if 'paths' in config:
for key, path in config['paths'].items():
if isinstance(path, str) and path.startswith('~'):
config['paths'][key] = str(Path.home() / path[1:])
def get(self, key_path, default=None):
"""Get configuration value by dot notation"""
keys = key_path.split('.')
value = self.config
for key in keys:
if isinstance(value, dict) and key in value:
value = value[key]
else:
return default
return value
def get_arduino_config(self):
"""Get Arduino UNO Q connection configuration"""
return self.get('arduino_uno_q', {})
def get_build_config(self):
"""Get build configuration"""
return self.get('build', {})
def get_paths(self):
"""Get paths configuration"""
return self.get('paths', {})
def get_led_matrix_config(self):
"""Get LED Matrix configuration"""
return self.get('led_matrix', {})
# Global config instance
config = Config()

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "arduino-uno-q",
"version": "1.0.0",
"description": "Arduino UNO Q project with MCU and MPU support",
"main": "src/mcu/main.ino",
"scripts": {
"build": "./build.sh",
"upload": "./upload.sh",
"deploy": "npm run build && npm run upload",
"monitor": "arduino-cli monitor",
"setup": "./setup_ssh.sh",
"status": "./scripts/status.sh",
"logs": "./scripts/logs.sh",
"restart": "./scripts/restart.sh",
"stop": "./scripts/stop.sh"
},
"keywords": ["arduino", "uno-q", "stm32", "linux", "mcu", "mpu"],
"author": "",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/arduino/uno-q-examples"
},
"dependencies": {},
"devDependencies": {}
}

15
scripts/logs.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# Logs script using config.json
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
arduino_config = config.get_arduino_config()
print(f'ssh -i {arduino_config[\"ssh_key\"]} {arduino_config[\"user\"]}@{arduino_config[\"hostname\"]} \"journalctl --user -u arduino-unoq -f\"')
" | bash

15
scripts/restart.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# Restart script using config.json
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
arduino_config = config.get_arduino_config()
print(f'ssh -i {arduino_config[\"ssh_key\"]} {arduino_config[\"user\"]}@{arduino_config[\"hostname\"]} \"systemctl --user restart arduino-unoq\"')
" | bash

15
scripts/status.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# Status script using config.json
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
arduino_config = config.get_arduino_config()
print(f'ssh -i {arduino_config[\"ssh_key\"]} {arduino_config[\"user\"]}@{arduino_config[\"hostname\"]} \"systemctl --user status arduino-unoq\"')
" | bash

15
scripts/stop.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# Stop script using config.json
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
arduino_config = config.get_arduino_config()
print(f'ssh -i {arduino_config[\"ssh_key\"]} {arduino_config[\"user\"]}@{arduino_config[\"hostname\"]} \"systemctl --user stop arduino-unoq\"')
" | bash

60
setup_ssh.sh Executable file
View File

@ -0,0 +1,60 @@
#!/bin/bash
# SSH Setup Script for Arduino UNO Q
# Uses configuration from config.json
set -e
# Add lib directory to Python path
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
# Load configuration
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
arduino_config = config.get_arduino_config()
print(f'UNOQ_HOST={arduino_config[\"hostname\"]}')
print(f'UNOQ_USER={arduino_config[\"user\"]}')
print(f'SSH_KEY={arduino_config[\"ssh_key\"]}')
" > /tmp/ssh_config.sh
source /tmp/ssh_config.sh
echo "Setting up SSH for Arduino UNO Q..."
# Create SSH key if it doesn't exist
if [ ! -f "$SSH_KEY" ]; then
echo "Creating SSH key..."
ssh-keygen -t ed25519 -f "$SSH_KEY" -N "" -C "arduino_unoq_key"
fi
# Test connection and copy key
echo "Testing connection to Arduino UNO Q at $UNOQ_HOST..."
if ping -c 1 "$UNOQ_HOST" &> /dev/null; then
echo "Copying SSH key to Arduino UNO Q..."
ssh-copy-id -i "$SSH_KEY.pub" "$UNOQ_USER@$UNOQ_HOST" || {
echo "Manual setup required:"
echo "1. Connect to Arduino UNO Q: ssh $UNOQ_USER@$UNOQ_HOST"
echo "2. Create .ssh directory: mkdir -p ~/.ssh"
echo "3. Add public key: echo '$(cat $SSH_KEY.pub)' >> ~/.ssh/authorized_keys"
echo "4. Set permissions: chmod 600 ~/.ssh/authorized_keys"
echo "5. Restart SSH: systemctl restart sshd"
}
else
echo "Arduino UNO Q not reachable at $UNOQ_HOST"
echo "Make sure:"
echo "- USB-C cable is connected"
echo "- Network interface is up (check IP in config.json)"
echo "- SSH is enabled on the device"
fi
echo "SSH setup complete!"
echo "Test connection: ssh -i $SSH_KEY $UNOQ_USER@$UNOQ_HOST"
# Cleanup
rm -f /tmp/ssh_config.sh

View File

@ -0,0 +1,188 @@
#include "LEDMatrix.h"
LEDMatrix::LEDMatrix() {
currentText = "";
scrollSpeed = 100;
displayTime = 5000;
direction = 0;
startTime = 0;
textPosition = 0;
}
void LEDMatrix::init() {
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
clearMatrix();
Serial.println("LED Matrix initialized");
}
void LEDMatrix::setText(String text, int speed, unsigned long time, int dir) {
currentText = text;
scrollSpeed = speed;
displayTime = time;
direction = dir;
startTime = millis();
textPosition = MATRIX_WIDTH;
Serial.print("LED Matrix: Text=\"");
Serial.print(text);
Serial.print("\", Speed=");
Serial.print(speed);
Serial.print("ms, Time=");
Serial.print(time);
Serial.print("ms, Direction=");
Serial.print(dir);
Serial.println("°");
}
void LEDMatrix::update() {
if (currentText.length() == 0) return;
// Check if display time expired
if (isExpired()) {
clear();
return;
}
displayScrollingText();
}
bool LEDMatrix::isExpired() {
return (millis() - startTime) > displayTime;
}
void LEDMatrix::clear() {
currentText = "";
clearMatrix();
Serial.println("LED Matrix cleared");
}
void LEDMatrix::clearMatrix() {
// Simple clear simulation
for (int i = 0; i < TOTAL_LEDS; i++) {
// Send clear command to LED matrix
// This would be actual LED matrix communication
}
}
void LEDMatrix::setPixel(int x, int y, bool state) {
// Boundary check
if (x < 0 || x >= MATRIX_WIDTH || y < 0 || y >= MATRIX_HEIGHT) return;
// Calculate pixel position and send to matrix
int pixelIndex = y * MATRIX_WIDTH + x;
// Actual LED matrix communication would go here
// For now, we'll simulate with serial output
if (state) {
Serial.print("LED ON [");
} else {
Serial.print("LED OFF[");
}
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.println("]");
}
void LEDMatrix::displayScrollingText() {
static unsigned long lastScroll = 0;
if (millis() - lastScroll > scrollSpeed) {
clearMatrix();
// Simple text rendering simulation
for (int i = 0; i < currentText.length(); i++) {
int charX = textPosition + (i * 6); // 6 pixels per character
if (charX >= -6 && charX < MATRIX_WIDTH) {
displayChar(currentText.charAt(i), charX, 1);
}
}
// Scroll based on direction
switch (direction) {
case 0: // Left to right
textPosition--;
break;
case 90: // Top to bottom
// Vertical scrolling would need different logic
textPosition--;
break;
case 180: // Right to left
textPosition++;
break;
case 270: // Bottom to top
textPosition--;
break;
default: // Custom angle
textPosition--;
break;
}
lastScroll = millis();
}
}
void LEDMatrix::displayChar(char c, int x, int y) {
// Simple 5x7 font simulation
// This would normally use a proper font table
if (c == 'H') {
setPixel(x, y, true);
setPixel(x, y+1, true);
setPixel(x, y+2, true);
setPixel(x, y+3, true);
setPixel(x, y+4, true);
setPixel(x+1, y+2, true);
setPixel(x+2, y, true);
setPixel(x+2, y+1, true);
setPixel(x+2, y+2, true);
setPixel(x+2, y+3, true);
setPixel(x+2, y+4, true);
} else if (c == 'a') {
setPixel(x+1, y+2, true);
setPixel(x, y+3, true);
setPixel(x+1, y+3, true);
setPixel(x+2, y+3, true);
setPixel(x, y+4, true);
setPixel(x+1, y+4, true);
setPixel(x+2, y+4, true);
} else if (c == 'l') {
setPixel(x, y, true);
setPixel(x, y+1, true);
setPixel(x, y+2, true);
setPixel(x, y+3, true);
setPixel(x, y+4, true);
} else if (c == 'o') {
setPixel(x, y+2, true);
setPixel(x+1, y+2, true);
setPixel(x+2, y+2, true);
setPixel(x, y+3, true);
setPixel(x+2, y+3, true);
setPixel(x, y+4, true);
setPixel(x+1, y+4, true);
setPixel(x+2, y+4, true);
} else if (c == ' ') {
// Space - no pixels
} else {
// Default character representation
setPixel(x, y+2, true);
setPixel(x+1, y+2, true);
setPixel(x+2, y+2, true);
setPixel(x, y+3, true);
setPixel(x+2, y+3, true);
setPixel(x, y+4, true);
setPixel(x+1, y+4, true);
setPixel(x+2, y+4, true);
}
}
void LEDMatrix::setBrightness(int brightness) {
// Brightness control (0-255)
// This would control the LED matrix brightness
Serial.print("LED Matrix brightness set to: ");
Serial.println(brightness);
}

View File

@ -0,0 +1,50 @@
#ifndef LED_MATRIX_H
#define LED_MATRIX_H
#include <Arduino.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
class LEDMatrix {
private:
static const int MATRIX_WIDTH = 13;
static const int MATRIX_HEIGHT = 8;
static const int TOTAL_LEDS = MATRIX_WIDTH * MATRIX_HEIGHT;
// LED Matrix pin configuration (adjust based on actual pinout)
static const int DATA_PIN = 2; // Example pin
static const int CLOCK_PIN = 3; // Example pin
static const int CS_PIN = 4; // Example pin
String currentText;
int scrollSpeed;
unsigned long displayTime;
int direction;
unsigned long startTime;
int textPosition;
void clearMatrix();
void setPixel(int x, int y, bool state);
void renderText();
void scrollText();
public:
LEDMatrix();
void init();
void setText(String text, int speed = 100, unsigned long time = 5000, int dir = 0);
void update();
void clear();
void setBrightness(int brightness);
void displayChar(char c, int x, int y);
void displayScrollingText();
// Getters
String getText() { return currentText; }
int getSpeed() { return scrollSpeed; }
unsigned long getDisplayTime() { return displayTime; }
int getDirection() { return direction; }
bool isExpired();
};
#endif

View File

@ -0,0 +1,101 @@
#include <Arduino.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include "LEDMatrix.h"
LEDMatrix ledMatrix;
void setup() {
Serial.begin(115200);
// Initialize LED Matrix
ledMatrix.init();
// Initialize built-in LED
pinMode(LED_BUILTIN, OUTPUT);
Serial.println("Arduino UNO Q MCU with LED Matrix initialized");
Serial.println("Waiting for commands from MPU...");
// Display default text
ledMatrix.setText("Hallo World", 150, 10000, 0);
}
void loop() {
// Update LED Matrix
ledMatrix.update();
// Check for serial commands from MPU
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
Serial.print("Received command: ");
Serial.println(command);
// Parse command format: TEXT,SPEED,TIME,DIRECTION
parseCommand(command);
}
// Blink built-in LED to show activity
static unsigned long lastBlink = 0;
if (millis() - lastBlink > 2000) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastBlink = millis();
}
}
void parseCommand(String command) {
// Remove any surrounding quotes
command.replace("\"", "");
// Find comma separators
int firstComma = command.indexOf(',');
int secondComma = command.indexOf(',', firstComma + 1);
int thirdComma = command.indexOf(',', secondComma + 1);
if (firstComma == -1) {
Serial.println("Error: Invalid command format");
return;
}
// Extract parameters
String text = command.substring(0, firstComma);
int speed = 150; // Default speed
unsigned long time = 5000; // Default time
int direction = 0; // Default direction
if (secondComma != -1) {
speed = command.substring(firstComma + 1, secondComma).toInt();
}
if (thirdComma != -1) {
time = command.substring(secondComma + 1, thirdComma).toInt();
direction = command.substring(thirdComma + 1).toInt();
} else if (secondComma != -1) {
time = command.substring(secondComma + 1).toInt();
}
// Validate parameters
if (speed < 50) speed = 50;
if (speed > 1000) speed = 1000;
if (time < 1000) time = 1000;
if (time > 60000) time = 60000;
// Normalize direction to 0-360 degrees
while (direction < 0) direction += 360;
while (direction >= 360) direction -= 360;
// Set the text on LED Matrix
ledMatrix.setText(text, speed, time, direction);
Serial.print("Command executed: TEXT=\"");
Serial.print(text);
Serial.print("\", SPEED=");
Serial.print(speed);
Serial.print("ms, TIME=");
Serial.print(time);
Serial.print("ms, DIRECTION=");
Serial.print(direction);
Serial.println("°");
}

123
src/mpu/main.py Normal file
View File

@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""
Arduino UNO Q MPU (Linux) Main Application
LED Matrix Text Display Example
"""
import sys
import os
import logging
import time
import json
from pathlib import Path
# Add lib directory to Python path
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root / "lib"))
from lib.arduino_unoq.bridge import ArduinoUNOQ
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def demonstrate_led_matrix(unoq):
"""Demonstrate LED Matrix functionality"""
# Example 1: Default "Hallo World" text
logger.info("Displaying default text: 'Hallo World'")
unoq.send_led_matrix_command("Hallo World", 150, 10000, 0)
time.sleep(12)
# Example 2: Fast scrolling text
logger.info("Displaying fast scrolling text")
unoq.send_led_matrix_command("Arduino UNO Q", 80, 8000, 0)
time.sleep(10)
# Example 3: Slow diagonal text
logger.info("Displaying slow diagonal text")
unoq.send_led_matrix_command("Diagonal 45°", 200, 6000, 45)
time.sleep(8)
# Example 4: Vertical scrolling (90 degrees)
logger.info("Displaying vertical scrolling text")
unoq.send_led_matrix_command("Vertical", 100, 7000, 90)
time.sleep(9)
# Example 5: Reverse scrolling (180 degrees)
logger.info("Displaying reverse scrolling text")
unoq.send_led_matrix_command("Reverse", 120, 5000, 180)
time.sleep(7)
# Example 6: Custom angle (30 degrees)
logger.info("Displaying custom angle text")
unoq.send_led_matrix_command("30 Degrees", 150, 6000, 30)
time.sleep(8)
logger.info("LED Matrix demonstration completed")
def main():
"""Main entry point"""
logger.info("Arduino UNO Q LED Matrix Application Started")
# Initialize Arduino UNO Q
unoq = ArduinoUNOQ()
# Create command pipe for external communication
cmd_pipe = Path('/tmp/unoq_cmd.pipe')
status_file = Path('/tmp/unoq_status.json')
try:
# Create named pipe if it doesn't exist
if not cmd_pipe.exists():
os.mkfifo(cmd_pipe)
except:
pass
# Start with LED Matrix demonstration
demonstrate_led_matrix(unoq)
# Main loop for continuous operation
while True:
try:
# Check for commands
if cmd_pipe.exists():
try:
with open(str(cmd_pipe), 'r') as f:
command = f.read().strip()
if command:
result = unoq.process_command(command)
# Write result to status file
with open(str(status_file), 'w') as f:
json.dump(result, f)
logger.info(f"Command processed: {result}")
except:
pass
# Periodic status update
current_data = {
"timestamp": str(int(time.time())),
"status": "running",
"application": "led_matrix_demo",
"bridge_available": unoq.bridge_available
}
with open(str(status_file), 'w') as f:
json.dump(current_data, f)
time.sleep(1) # Update every second
except KeyboardInterrupt:
logger.info("Shutting down...")
break
except Exception as e:
logger.error(f"Error in main loop: {e}")
time.sleep(5) # Wait before retrying
if __name__ == "__main__":
main()

19
ssh_config Normal file
View File

@ -0,0 +1,19 @@
# SSH Configuration for Arduino UNO Q
# Copy this to ~/.ssh/config or use as reference
Host arduino-unoq
HostName 192.168.100.73 # WiFi network IP
User arduino
Port 22
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
IdentityFile ~/.ssh/arduino_unoq_key
# Alternative connection via WiFi (if configured)
Host arduino-unoq-wifi
HostName arduino-unoq.local
User root
Port 22
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
IdentityFile ~/.ssh/arduino_unoq_key

96
upload.sh Executable file
View File

@ -0,0 +1,96 @@
#!/bin/bash
# Upload script for Arduino UNO Q
# Uses configuration from config.json
set -e
# Add lib directory to Python path
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PYTHONPATH="$PROJECT_ROOT/lib:$PYTHONPATH"
# Load configuration
python3 -c "
import sys
sys.path.insert(0, '$PROJECT_ROOT/lib')
from config_loader import config
arduino_config = config.get_arduino_config()
paths = config.get_paths()
print(f'UNOQ_HOST={arduino_config[\"hostname\"]}')
print(f'UNOQ_USER={arduino_config[\"user\"]}')
print(f'SSH_KEY={arduino_config[\"ssh_key\"]}')
print(f'PYTHON_SCRIPT={paths[\"python_script\"]}')
print(f'MCU_BINARY={paths[\"mcu_binary\"]}')
" > /tmp/upload_config.sh
source /tmp/upload_config.sh
echo "Uploading to Arduino UNO Q..."
# Check SSH connection
if ! ssh -i "$SSH_KEY" -o ConnectTimeout=5 "$UNOQ_USER@$UNOQ_HOST" "echo 'Connection OK'" &> /dev/null; then
echo "Cannot connect to Arduino UNO Q at $UNOQ_HOST"
echo "Run ./setup_ssh.sh first to configure SSH"
exit 1
fi
# Upload Python script to MPU
echo "Uploading Python script to MPU..."
scp -i "$SSH_KEY" "$PYTHON_SCRIPT" "$UNOQ_USER@$UNOQ_HOST:/home/arduino/main.py"
# Make Python script executable
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "chmod +x /home/arduino/main.py"
# Upload compiled sketch to MCU
echo "Uploading compiled sketch to MCU..."
if [ -f "$MCU_BINARY" ]; then
scp -i "$SSH_KEY" "$MCU_BINARY" "$UNOQ_USER@$UNOQ_HOST:/tmp/sketch.bin"
# Use Arduino CLI on the device to flash the MCU
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "arduino-cli upload --fqbn arduino:zephyr:unoq --input-file /tmp/sketch.bin /dev/ttyACM0" || {
echo "MCU upload may require manual intervention"
echo "Try pressing the reset button during upload"
}
else
echo "MCU binary not found at $MCU_BINARY"
echo "Run ./build.sh first to compile the sketch"
fi
# Start the Python application
echo "Starting Python application on MPU..."
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "nohup python3 /home/arduino/main.py > /tmp/main.log 2>&1 &"
# Create systemd user service for auto-start
echo "Creating systemd user service for auto-start..."
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "mkdir -p ~/.config/systemd/user"
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "cat > ~/.config/systemd/user/arduino-unoq.service << 'EOF'
[Unit]
Description=Arduino UNO Q Main Application
After=network.target
[Service]
Type=simple
WorkingDirectory=%h
ExecStart=/usr/bin/python3 %h/main.py
Restart=always
RestartSec=10
[Install]
WantedBy=default.target
EOF"
# Enable and start user service
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "systemctl --user daemon-reload"
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "systemctl --user enable arduino-unoq.service"
ssh -i "$SSH_KEY" "$UNOQ_USER@$UNOQ_HOST" "systemctl --user start arduino-unoq.service"
echo "Upload complete!"
echo "Python application running on MPU"
echo "Check status: ssh -i $SSH_KEY $UNOQ_USER@$UNOQ_HOST 'systemctl --user status arduino-unoq'"
echo "View logs: ssh -i $SSH_KEY $UNOQ_USER@$UNOQ_HOST 'journalctl --user -u arduino-unoq -f'"
# Cleanup
rm -f /tmp/upload_config.sh