Studio Power Automation
Sub-GHz RF Studio Power Automation (pikvm-studio)
This page details the wireless sub-GHz RF power control infrastructure in the studio, including the hardware transceiver, mathematical reverse-engineering of the 33-bit Princeton/Fosmon PWM protocol, complete device payload database, CLI controller, and CLIlessons controller.learned during development.
1. Hardware & Physical Setup
All lighting, outboard gear racks, monitor speakers, and peripherals in the studio are switched via 433.92 MHz RF wireless power relays controlled by a dedicated transceiver plugged into pikvm-studio.
- Host Node:
pikvm-studio(PiKVM V4 Plus, Raspberry Pi 4 Model B, Arch Linux ARM) - Transceiver: Great Scott Gadgets YARD Stick One
- USB ID:
1d50:605b(OpenMoko / GSG RfCat CC1111) - Core SoC: Texas Instruments CC1111F32 (24.0 MHz reference crystal)
setAmpMode(1))
Antenna: Sub-GHz vertical SMA whip antenna
Carrier Frequency: 433.92920 MHz
Modulation: ASK / OOK (Amplitude Shift Keying / On-Off Keying)
+--------------------------------------------------------------------------------+
| Host: pikvm-studio (Arch Linux ARM) |
| |
| [ studio-power CLI ] ---> [ RfCat / rflib ] ---> [ YARD Stick One (CC1111) ] |
+-----------------------------------------------------------------------|--------+
| 433.92920 MHz ASK/OOK
| (33-bit PWM)PWM, 3433 baud)
v
+------------------+ +------------------+ +------------------+ +------------------+
| Moroccan Lamp | | Recording Rack | | Studio Computer | | Subwoofer |
| (Fosmon Outlet) | | (Fosmon Outlet) | | (Fosmon Outlet) | | (Fosmon Outlet) |
+------------------+ +------------------+ +------------------+ +------------------+
+------------------+ +------------------+ +------------------+
| Main PA Speakers | | TV Monitor | | Neewer LED Panels|
| (Fosmon Outlet) | | (Fosmon Outlet) | | (Fosmon Outlet) |
+------------------+ +------------------+ +------------------+
2. The Reverse-Engineering Journey & Lessons Learned
Achieving reliable, production-grade RF transmission from the YARD Stick One to physical studio outlets required resolving several hardware, firmware, and protocol discrepancies.
Why FCC Filings Were Insufficient
Public FCC equipment authorization filings (such as Grantee 2A3BM / FCC ID 2A3BM5782988) provide RF emissions compliance data—confirming the fundamental carrier frequency (433.92 MHz), field strength, and occupied bandwidth—but do not document the digital baseband protocol:
The Flipper Zero Ground-Truth Workflow
To decode the baseband protocol, a Flipper Zero was used to capture raw sub-GHz RF transmissions from the physical remotes:
.sub captures (Mrc_on.sub, Mrc_off.sub, etc.).
Hardware Ground Truth: Replaying .sub files directly from the Flipper Zero reliably triggered the physical relays, confirming that the recorded pulse sequences were mathematically valid.
Pulse-Interval Extraction: Microsecond-level pulse analysis revealed clean 33-bit repeating frames:
'1'
High pulse ≈ 290 µs, Low pulse ≈ 870 µs for bit '0'
Trailing sync gap ≈ 290 µs High, 10,400 µs Low (10.4 ms)
Fundamental clock tick: Te = 291.27 µs (3433.22 baud)
Isolating the Transceiver Issue: Because Flipper Zero replay worked consistently while initial YARD Stick One transmissions failed, we confirmed the payload bitstreams were correct, allowing us to isolate the root cause to the CC1111's 24.0 MHz reference crystal configuration.
The Great Crystal Oscillator Frequency Trap (24.0 MHz vs 26.0 MHz)
The most elusive obstacle was the RF carrier frequency register calculation:
FREQ = 0x10B071 for 433.92 MHz:
$$\text{FREQ} = \frac{433,920,000}{26,000,000} \times 2^{16} = 1,093,745 = \mathbf{0x10B071}$$
The Reality: The CC1111 USB SoC on the YARD Stick One does not use a 26 MHz crystal. Because USB 2.0 Full-Speed requires a 48 MHz clock derived from a 2x PLL, the CC1111 utilizes a 24.0 MHz reference crystal (FREQ_OSC = 24000000 Hz).
The Consequence: When 0x10B071 was loaded into a 24 MHz CC1111, the actual emitted RF carrier was:
$$\text{Actual Freq} = \frac{1,093,745 \times 24,000,000}{2^{16}} = 400.54\text{ MHz}$$
The transceiver was broadcasting over 33 MHz off-target, resulting in zero signal reaching the 433.92 MHz receivers.
The Fix: Calibrating for the true 24.0 MHz crystal yielded the exact frequency registers:
$$\text{FREQ} = \frac{433,920,000}{24,000,000} \times 2^{16} = 1,184,883 = \mathbf{0x121473}$$
FREQ2 = 0x12, FREQ1 = 0x14, FREQ0 = 0x73 (with Channel CHANNR = 0x00).
Pulse Framing & The "Double Sync Gap" Trap
From Flipper Zero capture analysis:
0: 1 tick High, 3 ticks Low (1000 -> 291 µs High, 874 µs Low)
Bit 1: 3 ticks High, 1 tick Low (1110 -> 874 µs High, 291 µs Low)
Sync Gap: 1 tick High, 35 ticks Low (1 + 35 zeros -> 291 µs High, 10.19 ms Low)
The Framing Bug: Initial synthetic generators placed a sync pulse at the beginning of the frame and another sync pulse at the end. When repeating frames in a burst, this created two back-to-back sync gaps (>21 ms of dead carrier), which caused the relay microcontroller's state machine to timeout and drop the frame.
The Fix: A frame consists strictly of the 33 data bits followed by a single trailing sync gap:
Frame Composition: 33 data bits × 4 ticks + 36 sync ticks = 168 ticks = 21 bytes (48.93 ms per frame)
Multi-Frame Contiguous Streaming vs Single-Shot Bursts
Consumer 433 MHz ASK/OOK receivers use simple superheterodyne/regenerative circuits with slow Automatic Gain Control (AGC). Single-shot transmissions or frames separated by USB packet latency fail because the receiver AGC cannot settle in time.
The Fix: In studio-power, the 21-byte frame is multiplied into a continuous 630-byte stream (30 consecutive frames) transmitted in a single uninterrupted RF burst:
Burst Duration: 630 bytes × 8 bits / 3433.22 baud = ~1.468 seconds
This ensures the receiver AGC locks on and decodes the command reliably across rooms.
3. Protocol Specification (Princeton / Fosmon 33-Bit PWM)
The wireless relays in the studio use the 33-bit Princeton / Fosmon Pulse-Width Modulation (PWM) encoding over a 433.92 MHz ASK/OOK carrier.
Timing & Waveform Structure
- Fundamental Clock Tick Period (
$T_e$)Te):$291.75,\mu\text{s}$27 µs ($\approx3433.223428\text{ baud}$)baud) - Bit Symbol
0: $1T_e$tick High ($292,\mu\text{s}$)
10001: 11101 + Bit '0': +---+
| |___________________ (1 tick high, 3 ticks low)
<Te><------ 3Te ------->
Bit '1': +---------------+
| |_______ (3 ticks high, 1 tick low)
<----- 3Te ----><--Te-->
Sync: +---+
| |____________________________________________________ (1 tick high, 3135 ticks low)
<Te><---------------------- 31Te35Te ----------------------->
4. CC1111 Hardware Register Map & RfCat USB Protocol
The standalone native C driver (yard_tx.c / cc1111_rfcat.h) controls the transceiver directly using libusb-1.0 control transfers and bulk endpoints:
CompleteRfCat FrameUSB CompositionVendor Requests (bmRequestType = 0x40)
Each
0x00 (RFCAT_REQ_PING): Verifies firmware communication.
0x01 (RFCAT_REQ_STROBE): Dispatches CC1111 radio command 0x01 STX, 0x04 = SIDLE).
0x03 (RFCAT_REQ_PEEK): Reads memory-mapped SFR / XDATA registers.
0x04 (RFCAT_REQ_POKE): Writes memory-mapped SFR / XDATA registers.
0x10 (RFCAT_REQ_SET_AMP_MODE): Toggles Skyworks SE2431L Power Amplifier (1 = ON, 0 = Bypass).
EP 0x04 (RFCAT_EP_BULK_OUT): High-speed USB Bulk OUT endpoint for streaming OOK baseband byte frames directly to the CC1111 TX FIFO.
Calibrated CC1111 Transceiver Register Map
FREQ2
0xDF09
0x12
Frequency Synthesizer MSB: $\text{FREQ1
0xDF0A
0x14
Frequency Synthesizer Middle Byte
FREQ0
0xDF0B
0x73
Frequency Synthesizer LSB
CHANNR
0xDF0C
0x00
Base RF channel index (0)
MDMCFG4
0xDF10
0x08
Filter bandwidth (187.5 kHz) & Data Rate Exponent ($\text{MDMCFG3
0xDF11
0x84
Data Rate Mantissa ($\text{DRATE_M} = 132$). $\text{Baud} = \frac{(256+132)\times 2^8}{2^{28}} \times 24\text{M} = \mathbf{3433.22\text{ Transmissions
MDMCFG2
0xDF12
0x30
Modulation format: ASK/OOK (0x30), preamble/sync word disabled
MDMCFG1
0xDF13
0x00
Zero extra preamble bytes
MDMCFG0
0xDF14
0xF8
Channel spacing exponent
FREND0
0xDF17
0x01
Sets PA output power level index 1 for bit symbol 1
MCSM0
0xDF18
0x18
Automatic synthesizer calibration on IDLE-to-TX transition
PA_TABLE1
0xDF2F
0xC0
Maximum RF output power (+10 PA_TABLE0
0xDF2E
0x00
Carrier cut-off for OOK Low level
PKTCTRL0
0xDF08
0x00
Fixed packet length mode
RFST
0xDF36
0x01
Radio Command Strobe: STX (Start Transmission)
3.5. Studio Device Payload Database
Every studio outlet has a dedicated 33-bit code for ON and OFF. Below is the complete, mathematically decoded bitstream database::
| Device Key | Device Name | Description & Safety Notes | State | 33-Bit Binary Bitstream | Hex Payload |
|---|---|---|---|---|---|
mrc |
Moroccan Lamp | Decorative ambient studio lighting | ON OFF |
110100001100000100001011011110100110100001100000100001010011110110 |
0x1a18216f40x1a18214f6 |
rack |
Recording Rack | Preamp rack, compressors, FireWire interfaces | ON OFF |
001011011010100100001011100110000001011011010100100001010100110010 |
0x5b5217300x5b521532 |
computer |
Studio Computer | DAW PC power outlet (requires PiKVM wake) | ON OFF |
001011011010100100001101100111110001011011010100100001100100111100 |
0x5b521b3e0x5b52193c |
sub |
Subwoofer | Studio active subwoofer monitor | ON OFF |
010110100111010000001101000111000010110100111010000001100000111010 |
0xb4e81a380xb4e8183a |
pa |
Main PA Speakers | Main active monitor speakers | ON OFF |
010110100111010000001011000110100010110100111010000001010000110110 |
0xb4e816340xb4e81436 |
tv |
TV Monitor | Studio display monitor & Chromecast | ON OFF |
010110100111010000001111000111100010110100111010000001110000111110 |
0xb4e81e3c0xb4e81c3e |
neewer |
Neewer LED Lights | Video and photography LED studio lighting | ON OFF |
001010010110011000001111010101110001010010110011000001110010101100 |
0x52cc1eae0x52cc1cac |
4.6. Signal Synthesis Implementation (Python)
To generate and transmit any command from scratch using rflib:
#!/usr/bin/env python3
import sys, time
sys.path.insert(0, "/tmp/rfcat")
import rflib
def synthesize_pwm(encode_pwm_exact(bit_string):
"""Converts a 33-bit code into aan mathematicallyexact pure 3428-baud21-byte OOK payload.frame at 3433 baud."""
raw_bitsraw = ""
for bit in bit_string:
if bit == '1':
raw_bitsraw += "1110" # 3 ticks high, 1 tick low
elif bit == '0':
raw_bitsraw += "1000" # 1 tick high, 3 ticks low
# Append Sync:trailing sync pulse: 1 tick high, 3135 ticks low raw_bits(~10.2 ms)
raw += "1" + ("0" * 31)
# Pad to byte boundary35)
while len(raw_bits)raw) % 8 != 0:
raw_bitsraw += "0"
return bytes(int(raw_bits[raw[i:i+8], 2) for i in range(0, len(raw_bits)raw), 8))
def send_signal(send_power_signal(bit_string, repeats=10)30):
payload = synthesize_pwm(encode_pwm_exact(bit_string)
d = rflib.RfCat()
d.setFreq(433920000)
d.setMdmModulation(rflib.MOD_ASK_OOK)
d.setMdmDRate(3428)3433)
d.setMdmSyncMode(0)
d.setMaxPower()
d.setAmpMode(1) # Enable hardware RF power amplifier
d.RFxmit(payload * repeats)
d.cleanup()
# Example: Turn ON Moroccan Lamp
send_signal(send_power_signal("110100001100000100001011011110100", repeats=10)30)
5.7. CLI Tool: studio-power
The utility is permanently installed on pikvm-studio at /usr/local/bin/studio-power.
Command Syntax
# Toggle individual devices:
$ sudo studio-power mrc on
$ sudo studio-power mrc off
$ sudo studio-power rack on
$ sudo studio-power rack off
$ sudo studio-power computer on
$ sudo studio-power computer off
$ sudo studio-power sub on
$ sudo studio-power sub off
$ sudo studio-power pa on
$ sudo studio-power pa off
$ sudo studio-power tv on
$ sudo studio-power tv off
$ sudo studio-power neewer on
$ sudo studio-power neewer off
# Session management (turn entire studio on or off):
$ sudo studio-power all on
$ sudo studio-power all off
# List devices:
$ studio-power list