Rewrote hidden_menu_probe.py from Winegard-hardcoded to auto-discovering: detects prompt, error string, and submenu structure from any firmware console. Extracted Winegard-specific candidate words to scripts/wordlists/winegard.txt. Deep probe of all 12 G2 submenus discovered commands across A3981 (driver diagnostics), ADC (RSSI monitoring + position sweep), DVB (extended help via man, transponder selection), EEPROM (read/write), GPIO (pin R/W), LATLON (calculator), MOT (azscan, sw), PEAK (EchoStar switch), and STEP (raw stepper control). NVS submenu generates false positives — treats any input as sequential index reads. Safety: added q/Q to default blocklist, bare-CR check before navigate_to_root to prevent accidental shell termination between submenus.
1708 lines
67 KiB
Markdown
1708 lines
67 KiB
Markdown
# Carryout G2 Firmware Exploration
|
||
|
||
**Firmware:** Version 02.02.48 (Copyright 2013 - Winegard Company)
|
||
**Date:** 2026-02-12
|
||
**Connection:** DSD TECH SH-U11 USB RS-422 @ 115200 8N1
|
||
|
||
## Hardware Platform
|
||
|
||
Discovered via `os` → `id` command:
|
||
|
||
```
|
||
NXP Kinetis K60 ARM Cortex-M4
|
||
Package: 144-pin
|
||
Silicon Rev: 2.4
|
||
Mask Set: 4N22D
|
||
P-Flash: 512 KB
|
||
RAM: 128 KB
|
||
Core Clock: 96 MHz (CCLK)
|
||
Bus Clock: 48 MHz (BCLK)
|
||
System ID: TWELINCH
|
||
Antenna ID: 12-IN G2
|
||
Software: 02.02.48
|
||
Flash Base: 0x00010000 (65536)
|
||
Flash Size: 458752 bytes (448 KB)
|
||
```
|
||
|
||
The "TWELINCH" system ID = "Twelve Inch", matching the Carryout G2's ~12" dish
|
||
diameter. Flash starts at 64 KB offset (first 64 KB is bootloader/vector table),
|
||
leaving 448 KB for application firmware.
|
||
|
||
**Exact part number:** MK60DN512VLQ10
|
||
- MK60 = Kinetis K60 family (Cortex-M4 + DSP)
|
||
- DN512 = 512 KB program flash (no FlexNVM)
|
||
- VLQ = LQFP 144-pin package (20x20mm)
|
||
- 10 = 100 MHz max frequency
|
||
|
||
**Datasheets:** `docs/K60-datasheet.pdf` (K60P144M100SF2V2, Rev 3, 6/2013),
|
||
`docs/K60-reference-manual.pdf` (K60P144M100SF2V2RM, ~1800 pages)
|
||
|
||
### Key Peripherals (from datasheet)
|
||
|
||
| Peripheral | Count | Notes |
|
||
|------------|-------|-------|
|
||
| UART | 5 | UART0 = RS-422 console (confirmed) |
|
||
| DSPI | 3 | SPI with DMA; DSPI0/1 likely → A3981 motor drivers |
|
||
| I2C | 2 | |
|
||
| ADC | 2× 16-bit | 863ns conversion; ADC0 likely → RSSI measurement |
|
||
| DAC | 2× 12-bit | |
|
||
| USB | 1× OTG | On-chip transceiver, no external PHY needed |
|
||
| CAN | 2 | Likely unused |
|
||
| Ethernet | 1× IEEE 1588 | Likely unused |
|
||
| FlexTimer | 3 (12 ch) | Motor PWM / step timing |
|
||
| DMA | 16 channel | |
|
||
|
||
### USB Port (Potentially Accessible)
|
||
|
||
The K60 has **dedicated USB pins** (not muxable with GPIO):
|
||
|
||
| LQFP Pin | Signal | Function |
|
||
|----------|--------|----------|
|
||
| 19 | USB0_DP | USB Data+ |
|
||
| 20 | USB0_DM | USB Data- |
|
||
| 21 | VOUT33 | USB VREG 3.3V output |
|
||
| 22 | VREGIN | USB VREG 5V input (self-power from USB) |
|
||
|
||
The Trav'ler Pro uses USB A-to-A (`ttyACM0`) for its serial console — this
|
||
proves Winegard has USB CDC/ACM firmware for the Kinetis platform. The G2 may
|
||
also have a USB connector on the PCB (possibly internal, for field service).
|
||
|
||
NVS indices 2 ("Debug 2nd Console Port") and 4 ("Debug Port Connection") hint
|
||
at multiple console port support — USB could be the second port.
|
||
|
||
## Root Menu Structure
|
||
|
||
At the `TRK>` prompt, `?` lists all available submenus:
|
||
|
||
| Submenu | Command | Description |
|
||
|---------|---------|-------------|
|
||
| A3981 | `a3981` | Allegro A3981 stepper motor driver IC control |
|
||
| ADC | `adc` | Analog-to-digital converter / RSSI / board ID |
|
||
| Dipswitch | `dipswitch` | DIP switch configuration readout |
|
||
| DVB | `dvb` | BCM4515 DVB receiver / signal analysis |
|
||
| EEPROM | `eeprom` | Non-volatile EEPROM storage (separate from NVS) |
|
||
| GPIO | `gpio` | MCU pin register dump (5 ports, 98 pins) |
|
||
| LATLON | `latlon` | Satellite longitude/elevation parameters |
|
||
| MOT | `mot` | Degree-based motor positioning (high-level) |
|
||
| NVS | `nvs` | Non-volatile settings (operational parameters) |
|
||
| OS | `os` | Operating system / task manager / MCU identification |
|
||
| PEAK | `peak` | Signal peaking / DiSEqC switch testing |
|
||
| STEP | `step` | Raw microstep motor control (low-level) |
|
||
|
||
Three-layer motor control architecture:
|
||
1. **`step`** — raw microstep commands (ustep/sec, engage/release motors)
|
||
2. **`mot`** — degree-based positioning (`a <id> <deg>`, `h <id>`)
|
||
3. **Application** — satellite tracking (NVS config, peak, DVB)
|
||
|
||
## NVS Values
|
||
|
||
```
|
||
Num Name Current Saved Default
|
||
---- -------------------------- ---------- ---------- ----------
|
||
0) Log ID's 0x00000007 0x00000007 0x00000007
|
||
1) Log Device 0x00000001 0x00000001 0x00000001
|
||
2) Debug 2nd Console Port 0 0 0
|
||
3) Debug 2nd Packet Port 0 0 0
|
||
4) Debug Port Connection 0 0 0
|
||
16) Pitch Deadband 0.00 0.00 0.00
|
||
17) Roll Deadband 0.00 0.00 0.00
|
||
18) Yaw Deadband 0.00 0.00 0.00
|
||
20) Disable Tracker Proc? TRUE TRUE FALSE ← MODIFIED
|
||
21) Tracker Proc Run Mode 0 0 0
|
||
22) Conical Alpha Az 200 200 200
|
||
23) Conical Alpha El 200 200 200
|
||
24) Conical Radius 1.00 1.00 1.00
|
||
25) Conical Count Max 20 20 20
|
||
26) Conical Test Drift +0 +0 +0
|
||
27) Circle RPM 120 120 120
|
||
28) Circle Pts/Rev 6 6 6
|
||
32) Conical Az Clamp 8.00 8.00 8.00
|
||
33) Conical El Clamp 8.00 8.00 8.00
|
||
35) Motor Pts/Rev 72 72 72
|
||
36) Circle Az Radius 1.00 1.00 1.00
|
||
37) Circle El Radius 1.00 1.00 1.00
|
||
38) Sleep Mode Timer Secs 420 420 420
|
||
40) Motor Type 0 0 0
|
||
41) Satellite Scan Velocity 55.00 55.00 55.00
|
||
48) Motor Spiral Velocity 55.00 55.00 55.00
|
||
49) Motor Gear Ratio 0x00000000 0x00000000 0x00000000
|
||
63) GPS Heading Threshold 1.00 1.00 1.00
|
||
64) GPS Moving Threshold 5.00 MPH 5.00 MPH 5.00 MPH
|
||
66) Spiral Signal In A Row Min +3 +3 +3
|
||
67) Spiral Signal In A Row Max +20 +20 +20
|
||
68) Signal Odd to Even Offset +0 +0 +0
|
||
69) Signal Offset 80 80 80
|
||
70) Signal Baseline Angle 65.00 65.00 65.00
|
||
71) Signal Re-Peak Degrade Percent 25 25 25
|
||
72) Gyro Sensitivity +1110 +1110 +1110
|
||
73) Gyro Filter Size +1 +1 +1
|
||
74) Gyro Calib Readings 100 100 100
|
||
75) Gyro Mount Type 1 1 1
|
||
76) Gyro Velocity Offset 4 4 4
|
||
77) Gyro Max Accel 600 600 600
|
||
80) AZ Max Vel 65.00 65.00 65.00
|
||
81) AZ Max Accel 400.00 400.00 400.00
|
||
82) AZ Home Velocity 55.00 55.00 55.00
|
||
83) AZ Steps/Rev 40000 40000 40000
|
||
84) AZ Direction +1 +1 +1
|
||
85) EL Max Vel 45.00 45.00 45.00
|
||
86) EL Max Accel 400.00 400.00 400.00
|
||
87) EL Home Velocity 45.00 45.00 45.00
|
||
88) EL Steps/Rev 24960 24960 24960
|
||
89) EL Direction +1 +1 +1
|
||
95) AZ Low current limit 0x0000ff0c 0x0000ff0c 0x0000ff0c
|
||
96) AZ High current limit 0x0000ff30 0x0000ff30 0x0000ff30
|
||
97) EL Low current limit 0x0000ff0c 0x0000ff0c 0x0000ff0c
|
||
98) EL High current limit 0x0000ff40 0x0000ff40 0x0000ff40
|
||
101) Minimum Elevation Angle 18.00 18.00 18.00
|
||
102) Maximum Elevation Angle 65.00 65.00 65.00
|
||
103) Elevation Home Angle 65.00 65.00 65.00
|
||
106) Az Stall Detect 78 78 78
|
||
107) El Stall Detect 75 75 75
|
||
108) Az Stall Samples 100 100 100
|
||
109) El Stall Samples 100 100 100
|
||
110) EL Home Current Limit 0x0000ff28 0x0000ff28 0x0000ff28
|
||
111) AZ Home Current Limit 0x0000ff40 0x0000ff40 0x0000ff40
|
||
112) Disable Dipswitch? FALSE FALSE FALSE
|
||
113) Dipswitch Value 101 101 101
|
||
114) Dipswitch Front/Rear Mount 0 0 0
|
||
115) Mount Offset Angle +0 +0 +0
|
||
118) Signal Use LNB Clamp FALSE FALSE FALSE
|
||
128) AZ PID Kp +600 +600 +600
|
||
129) AZ PID Kv +60 +60 +60
|
||
130) AZ PID Ki +1 +1 +1
|
||
131) EL PID Kp +250 +250 +250
|
||
132) EL PID Kv +50 +50 +50
|
||
133) EL PID Ki +1 +1 +1
|
||
136) AZ PWM Stall Cnt 6 6 6
|
||
137) EL PWM Stall Cnt 5 5 5
|
||
143) Tracking Number 0 0 0
|
||
```
|
||
|
||
## Key Parameters for Satellite Tracking
|
||
|
||
| NVS | Name | Value | Notes |
|
||
|-----|------|-------|-------|
|
||
| 20 | Disable Tracker Proc? | TRUE | Prevents TV satellite search on boot |
|
||
| 83 | AZ Steps/Rev | 40000 | Centidegrees per revolution (400.00°) |
|
||
| 88 | EL Steps/Rev | 24960 | ~249.60° per revolution |
|
||
| 80 | AZ Max Vel | 65.00 | °/s azimuth max velocity |
|
||
| 85 | EL Max Vel | 45.00 | °/s elevation max velocity |
|
||
| 101 | Min Elevation | 18.00 | Firmware floor (degrees) |
|
||
| 102 | Max Elevation | 65.00 | Firmware ceiling (degrees) |
|
||
| 103 | EL Home Angle | 65.00 | Where EL homes to on startup |
|
||
| 128-133 | PID Gains | varies | AZ/EL motor PID tuning parameters |
|
||
|
||
## Boot Sequence Observed
|
||
|
||
### Bootloader Phase (<50ms, non-interactive)
|
||
|
||
Captured via `scripts/boot_capture.py` with high-resolution timestamps:
|
||
|
||
```
|
||
[0.050s] 01 00 ← binary status bytes (bootloader→app handshake?)
|
||
[0.050s] Bootloader version: 1.01
|
||
[0.050s] Application is running...
|
||
[0.050s] 98 80 96 ← binary bytes (integrity check? jump address?)
|
||
[0.100s] Application Starting Kinetis PCB... power up/reset
|
||
```
|
||
|
||
The bootloader runs at **115200 baud** (same as application — confirmed by
|
||
multi-baud capture at 9600/19200/38400/57600/230400/460800). There is **no
|
||
interactive window** — ESC, CR, BREAK, 0x55 autobaud, and other interrupt
|
||
sequences at 5-30ms delays all failed to stop the boot. The bootloader
|
||
checks a flag (likely in EEPROM or a reserved flash sector) and immediately
|
||
jumps to the application at 0x10000 if no firmware update is pending.
|
||
|
||
### Application Phase (~10s to prompt)
|
||
|
||
```
|
||
Version 02.02.48
|
||
Copyright 2013 - Winegard Company
|
||
Boot Complete
|
||
|
||
Loc Startup: IDU NOT Present
|
||
app_dipswitch:101
|
||
Primary Update: 10100
|
||
Alternate Update: 11900
|
||
Toggle Ability Update: 0
|
||
Alternate2 Update: 0
|
||
Sat Provider Update: 1
|
||
DVB: id:0000, lon:101.00E
|
||
Tuner = WIDE
|
||
Signal offset = 80
|
||
Signal baseline angle = 6500
|
||
Signal Re-Peak Pct = 25
|
||
NVS Status: 0 Sleep: 420 Dipswitch: 101
|
||
Sleep: 420 NVS: 420
|
||
NoGpsStartUp: 721
|
||
STATIONARY MODE
|
||
Enabled LNB ODU 18V
|
||
GPS Not Found
|
||
```
|
||
|
||
## Homing Sequence
|
||
|
||
After boot, the dish homes both motors (EL first, then AZ) using stall detection:
|
||
|
||
```
|
||
MotorHome:1 timeout:2000 ← EL motor homing
|
||
Home TwelInch El Velocity: 4500
|
||
EL Stall Timeout
|
||
El Home Angle: 6500
|
||
|
||
MotorHome:0 timeout:8000 ← AZ motor homing
|
||
Home TwelInch Az
|
||
End MotorAzStall:part1
|
||
Antenna Facing Front
|
||
home:0 wrap_pos:0 wrap_min:-42333 wrap_max:2333
|
||
```
|
||
|
||
## Cable Wrap Limits
|
||
|
||
From homing output: `wrap_min:-42333 wrap_max:2333`
|
||
- In centidegrees: -423.33° to +23.33° from home position
|
||
- Total range: 446.66° (~1.24 full rotations)
|
||
|
||
## Motor Control
|
||
|
||
### Position Query
|
||
|
||
In the `MOT>` submenu, `a` returns position with 4-space indentation:
|
||
|
||
```
|
||
a
|
||
Angle[0] = 180.00 ← AZ (degrees)
|
||
Angle[1] = 45.00 ← EL (degrees)
|
||
MOT>
|
||
```
|
||
|
||
### Move Command
|
||
|
||
`a <id> <deg>` returns a confirmation (no array index) and the prompt immediately
|
||
while the motor moves in the background:
|
||
|
||
```
|
||
a 1 46
|
||
Angle = 46.00
|
||
MOT>
|
||
```
|
||
|
||
### Observed Motor Behavior
|
||
|
||
| Test | Command | Target | Actual | Overshoot |
|
||
|------|---------|--------|--------|-----------|
|
||
| EL move out | `a 1 46` | 46.00 | 46.05 | +0.05° |
|
||
| AZ move out | `a 0 181` | 181.00 | 181.01 | +0.01° |
|
||
| EL return | `a 1 45` | 45.00 | 44.94 | -0.06° |
|
||
| AZ return | `a 0 180` | 180.00 | 179.98 | -0.02° |
|
||
|
||
Direction-dependent overshoot: the motor consistently overshoots in the
|
||
direction of travel, undershooting on return. This is classic stepper
|
||
backlash + PID settling behavior and is what the leapfrog algorithm
|
||
compensates for.
|
||
|
||
### MOT Submenu — Full Command Reference
|
||
|
||
```
|
||
Available commands:
|
||
a Go to angle [[[motor] [[+|-]angle]]]
|
||
azscan Scan AZ from EL Min-Max Angle [az_rel_angle] [el_rel_angle] [delay]
|
||
azscanwxp Scan AZ from EL Min-Max with all transponders [motor] [span] [resolution] [num_xp]
|
||
e Engage motors
|
||
ela2s Elevation Law Test - Angle to Steps [angle]
|
||
elminmaxhome Display Min, Max & Home Elevation Angles
|
||
els2a Elevation Law Test - Steps to Angle [steps]
|
||
h Home Motors [motor num or * (both)]
|
||
l List Motors in System
|
||
life Az/El Life test [az_rel_angle] [el_rel_angle]
|
||
ma Set Max Acceleration [[motor] [deg/sec/sec]]
|
||
motorboth Both Motor Life test [AZ delta(0-25)] [EL delta(0-25)]
|
||
motorlife Motor Life Test [motor_id] [min_angle] [max_angle]
|
||
mv Set Max Velocity [motor] [deg/sec]
|
||
p Go To Position [motor] [pos]
|
||
pid Set PID Parameters [motor] [Kp] [Kv] [Ki]
|
||
r Release Motors
|
||
sd Stall Detect [motor] [dir] [timeout_ms] [iterations (0=forever)]
|
||
sp Set Position [motor] [pos]
|
||
sw Set Wrap Position [motor] [pos]
|
||
v Goto Velocity [motor] [deg/rev]
|
||
vms Goto Velocity For Milliseconds [motor] [deg/rev] [ms]
|
||
w Wrap Manager [motor] [ON/OFF]
|
||
```
|
||
|
||
### Relative Moves
|
||
|
||
`a` supports `+`/`-` prefix for **relative** moves:
|
||
|
||
```
|
||
a 0 +5 ← move AZ 5° CW from current
|
||
a 1 -2 ← move EL 2° down from current
|
||
```
|
||
|
||
This is undocumented in the upstream repos and very useful for incremental
|
||
positioning during tracking.
|
||
|
||
### Motor List
|
||
|
||
```
|
||
l
|
||
Motors:
|
||
0 - AZIMUTH: local
|
||
1 - ELEVATION: local
|
||
```
|
||
|
||
"local" means direct A3981 driver control (vs. a networked motor controller).
|
||
|
||
### Motor Dynamics
|
||
|
||
```
|
||
ma → Accel[0] = 400.0 Accel[1] = 400.0 (deg/sec²)
|
||
mv → Max Vel[0] = 65.0 Max Vel[1] = 45.0 (deg/sec)
|
||
```
|
||
|
||
Both axes have identical acceleration (400 deg/sec²). AZ max velocity is
|
||
faster (65 deg/sec) than EL (45 deg/sec) — different gear ratios and
|
||
mechanical loads.
|
||
|
||
### Step Position
|
||
|
||
`p` shows position in microsteps:
|
||
|
||
```
|
||
p → Position[0] = 19998 Position[1] = 3116
|
||
```
|
||
|
||
Cross-check with angle: AZ 179.98° × (40000/360) = 19998 steps. Linear
|
||
mapping for both axes (angle = steps × 360 / steps_per_rev).
|
||
|
||
### Elevation Limits
|
||
|
||
```
|
||
elminmaxhome → Min: 1800 Max: 6500 Home: 6500
|
||
```
|
||
|
||
All values in centidegrees: **Min=18.00°, Max=65.00°, Home=65.00°**. The
|
||
home position is at maximum elevation (stow position).
|
||
|
||
### Elevation Law Conversion
|
||
|
||
`ela2s` converts angle → steps, `els2a` converts steps → angle:
|
||
|
||
| Angle | Steps | Notes |
|
||
|-------|-------|-------|
|
||
| 0° | 1248 | Below min (warning: "Min: 1800") |
|
||
| 18° | 1248 | Minimum EL (same steps as 0°) |
|
||
| 45° | 3120 | |
|
||
| 65° | 4506 | Maximum EL |
|
||
| 90° | 4506 | Above max (warning: "Max: 6500") |
|
||
|
||
The mapping is linear: steps ≈ angle × (24960/360). The "law" is a simple
|
||
linear function for this dish — no non-linear linkage compensation.
|
||
|
||
### Engage / Release
|
||
|
||
- `e` — Engage motors (enable A3981 drivers, PID loop holds position)
|
||
- `r` — Release motors (disable drivers, dish can move freely by hand)
|
||
|
||
### Sky Scan Commands
|
||
|
||
**`azscan <az_rel> <el_rel> <delay>`** — Scan AZ while stepping EL from
|
||
min to max angle. Parameters are relative angles and dwell delay. Used for
|
||
basic signal surveys.
|
||
|
||
**`azscanwxp <motor> <span> <resolution> <num_xp>`** — Advanced sky scan
|
||
that steps in hundredths of a degree and checks all transponders at each
|
||
position. This is the core of Davidson's winegard-sky-scan project. The
|
||
`resolution` parameter in hundredths of a degree enables 0.01° precision
|
||
scanning — far finer than the standard `a` command.
|
||
|
||
### Stall Detection
|
||
|
||
`sd <motor> <dir> <timeout> [iterations]` — Run stall detection on a
|
||
motor. Default timeouts: AZ=10000ms, EL=2000ms. The firmware drives the
|
||
motor in the specified direction until it stalls (current spike from A3981).
|
||
Set iterations to 0 for continuous mode. Used during homing and calibration.
|
||
|
||
### Life / Durability Tests
|
||
|
||
Factory test commands that continuously exercise the motors:
|
||
|
||
- `life <az_rel> <el_rel>` — Oscillate both axes by relative angles
|
||
- `motorlife <id> <min> <max>` — Sweep a single motor between min/max angles
|
||
- `motorboth <az_delta> <el_delta>` — Exercise both motors, max 25° delta each
|
||
|
||
### Write-Only Commands
|
||
|
||
These commands require parameters — no read-only mode:
|
||
|
||
- `pid <motor> <Kp> <Kv> <Ki>` — Set PID gains (no read command)
|
||
- `sp <motor> <pos>` — Set step position counter (doesn't move motor)
|
||
- `sw <motor> <pos>` — Set wrap position
|
||
- `w <motor> ON/OFF` — Enable/disable wrap manager
|
||
|
||
## DVB Subsystem (BCM4515)
|
||
|
||
### Hardware
|
||
|
||
```
|
||
BCM Hardware= ID: 0x4515 VER: 0xB0
|
||
BCM Firmware= MAJOR VER: 0x71 (113) MINOR VER: 0x25 (37)
|
||
BCM Strap Config: 0x25018
|
||
```
|
||
|
||
### Channel Parameters (`dis`)
|
||
|
||
```
|
||
Power Mode: ON
|
||
Search Transponders: ON
|
||
Auto Search Mode: 1
|
||
Shuffle Mode: ON
|
||
Frequency List: Non-Stacked
|
||
|
||
Num Parameter Current Default
|
||
1 Frequency 1090640 (kHz) 974000 (kHz)
|
||
2 Symbol Rate 0 (PeakScanEnabled) 20000 (ksps)
|
||
3 Trans_Mod_CRate blind_scan blind_scan
|
||
4 Blind Scan Mode ___trb_dvb_dss_____ ___trb_dvb_dss_____
|
||
5 LNB Polarity ODU:13V ---
|
||
6 LNB Tone (ODU) off off
|
||
7 Roll-off 0.35 0.35
|
||
8 LPF Cutoff 0 (auto) 0 (MHz)
|
||
9 Carrier Offset 0 (kHz) 0 (kHz)
|
||
10 FreqSearchRange 5000 (kHz) 5000 (kHz)
|
||
11 DCII Mode dcii_qpsk_comb dcii_qpsk_comb
|
||
12 Spectral Inv scan scan
|
||
13 PScnSymRtRngMin 18000 (ksps) 18000 (ksps)
|
||
14 PScnSymRtRngMax 24000 (ksps) 24000 (ksps)
|
||
15 SignalDetectMode off off
|
||
```
|
||
|
||
### RSSI Response Format
|
||
|
||
```
|
||
rssi 5
|
||
iterations:5 interval(msec):20
|
||
Reads:5 RSSI[avg: 500 cur: 500]
|
||
DVB>
|
||
```
|
||
|
||
500 is the noise floor (no signal lock, dish pointed at arbitrary sky).
|
||
|
||
### LNB Voltage
|
||
|
||
`lnbdc odu` enables LNA at 13V. `lnbv` streams continuous voltage readings:
|
||
|
||
```
|
||
Reads:1 LNB Voltage (mV): 13239 ( ADC value: 119 )
|
||
Reads:2 LNB Voltage (mV): 13182 ( ADC value: 118 )
|
||
...
|
||
```
|
||
|
||
Stable at ~13.11V (ADC 117). Boot default is 18V; `lnbdc odu` switches to 13V.
|
||
13V = vertical polarization, 18V = horizontal polarization on a standard LNB.
|
||
|
||
### AGC (Streaming)
|
||
|
||
`agc` streams RF and IF automatic gain control plus SNR/NID:
|
||
|
||
```
|
||
Reads:1 RF_AGC[avg: 1327353088 cur: 1327353088] IF_AGC[avg: 2684354560 cur: 2684354560] SNR: 0.0 NID: FFFF/none
|
||
```
|
||
|
||
- RF_AGC values are raw BCM4515 32-bit register values
|
||
- IF_AGC constant at 0xA0000000 (fixed IF gain)
|
||
- SNR: 0.0 when no signal lock
|
||
- NID: FFFF/none = no DVB network ID detected
|
||
|
||
### SNR (Streaming)
|
||
|
||
`snr` streams signal-to-noise ratio readings:
|
||
|
||
```
|
||
Reads:1 SNR[avg: 0.0 cur: 0.0]
|
||
Reads:2 SNR[avg: 0.0 cur: 0.0]
|
||
...
|
||
Reads:223 SNR[avg: 0.0 cur: 3.1] ← transient RF spike
|
||
Reads:250 SNR[avg: 0.0 cur: 2.6] ← another transient
|
||
```
|
||
|
||
At noise floor, average stays 0.0 but occasional transient spikes appear in
|
||
the `cur` field — fleeting RF energy. Stays in DVB submenu when interrupted.
|
||
|
||
### Lock Status (`ls`) — Streaming
|
||
|
||
`ls` is a STREAMING command that continuously scans all 32 transponders, trying
|
||
multiple modulations per frequency. Output is a continuous scan log:
|
||
|
||
```
|
||
Xp:1 Freq:974000 SymRate:20000 Mode:blind_scan ... no_lock
|
||
Xp:1 Freq:974000 SymRate:20000 Mode:turbo_qpsk_... ... no_lock
|
||
...
|
||
```
|
||
|
||
**When interrupted with CR, `ls` prints "Terminating shell." and drops to
|
||
`TRK>` (exits DVB submenu entirely).** This is unique among DVB streaming
|
||
commands — all others stay in DVB submenu when interrupted.
|
||
|
||
### Quick Lock Status (`qls`) — Streaming
|
||
|
||
`qls` streams compact lock status at ~100ms intervals:
|
||
|
||
```
|
||
Lock:0 rssi:500 cnt:0
|
||
Lock:0 rssi:500 cnt:0
|
||
...
|
||
```
|
||
|
||
Stays in DVB submenu when interrupted. Ideal for real-time signal monitoring
|
||
during dish movement (low bandwidth, high update rate).
|
||
|
||
### Network ID (`nid`) — Streaming
|
||
|
||
`nid` streams network identification:
|
||
|
||
```
|
||
nid: FFFF/none
|
||
nid: FFFF/none
|
||
```
|
||
|
||
Uses CR-overwrite (carriage return without newline) for in-place updates.
|
||
FFFF = no DVB network detected. Can be difficult to interrupt cleanly —
|
||
may need multiple CR + flush cycles.
|
||
|
||
### Signal Statistics (`stats`) — Streaming
|
||
|
||
`stats` streams signal statistics. Produces no output when there is no signal
|
||
lock. Stays in DVB submenu when interrupted.
|
||
|
||
### Diagnostics (`diag`) — One-Shot
|
||
|
||
`diag` is a multi-block ONE-SHOT command that outputs detailed per-transponder
|
||
diagnostics for each transponder currently being tried:
|
||
|
||
```
|
||
SymRate: 18514984 Freq: 974000
|
||
Bit Rate: 29893160
|
||
SNR: 0.0 SymRateErr: -1258 CarrierOffset: 0 CarrierErr: 3295097
|
||
Tuner LPF: 12 RF_AGC: 2214707264
|
||
BER Errors: 0 MPEG Frm Errors: 0 MPEG Frm Count: 0
|
||
Reacquisitions: 7
|
||
RS Corr/Uncorr: 0 / 0 Pre-Vit: 0
|
||
sp inv: scan phase rotation: 0
|
||
Acq Time: 4259 msec
|
||
trans_mod_coderate: no_lock
|
||
Tuner PLL: LOCKED Internal BERT: not locked
|
||
Demod: not locked Timing Loop Lock: disabled
|
||
```
|
||
|
||
### Transponder Table (`table`) — One-Shot (Long)
|
||
|
||
`table` generates a full scan across all 32 transponders. Takes ~136 seconds
|
||
(~4.25s per transponder, matching `tabto` acquisition timeout of 4000ms).
|
||
|
||
The output starts with a configuration summary showing all modifiable parameters
|
||
with their current values and the commands to change them, then a detailed
|
||
per-transponder table with columns:
|
||
|
||
```
|
||
Xp Freq SigDet SymRate PeakPower SNR LPF RF_AGC AcqTime Mode
|
||
NID/SAT XpTime LNBVsens RSSI BitrateOut SymRateError CarrierOffset
|
||
CarrierError BER_Errors MPEG_Errors MPEG_Count Reacq
|
||
```
|
||
|
||
With shuffle mode ON, transponders scan in interleaved groups of 4:
|
||
1,2,3,4 → 17,18,19,20 → 5,6,7,8 → 21,22,23,24 → 9,10,11,12 → 25,26,27,28
|
||
→ 13,14,15,16 → 29,30,31,32.
|
||
|
||
LNB voltage alternates between ~13V (vertical polarization) and ~20V
|
||
(horizontal polarization) across transponder groups.
|
||
|
||
After scan completes: `Table Completion Time (seconds): 136 Transponders Locked: 0`
|
||
then auto-restores LNB to STB mode: `Enabled LNB STB`.
|
||
|
||
### Frequency List (`freqs`)
|
||
|
||
Returns the active frequency list name:
|
||
|
||
```
|
||
freqs → Non-Stacked
|
||
```
|
||
|
||
"Non-Stacked" means standard Ku-band IF frequencies without stacking
|
||
(stacked LNBs combine multiple bands into one cable).
|
||
|
||
### Transponder Range (`range`)
|
||
|
||
```
|
||
range → Transponder Range: [ 1 - 32 ]
|
||
```
|
||
|
||
### Power State (`pwr`)
|
||
|
||
```
|
||
pwr → SDS and DiSEqC core power enabled
|
||
```
|
||
|
||
Shows power state of the Satellite Detection System and DiSEqC subsystems.
|
||
|
||
### Search Mode (`srch_mode`)
|
||
|
||
```
|
||
srch_mode → Auto Search Mode: 1
|
||
```
|
||
|
||
Mode 1 = automatic transponder search with blind scan.
|
||
|
||
### Timeout Settings
|
||
|
||
Two separate timeout configurations:
|
||
|
||
**Table scan timeouts (`tabto`):**
|
||
```
|
||
Timeout (msec): Acq:4000 NID:20000 Signal Detect:0
|
||
```
|
||
|
||
**Single transponder tune timeouts (`to`):**
|
||
```
|
||
Timeout (msec): Acq:500 NID:12000
|
||
```
|
||
|
||
`tabto` takes arguments: `tabto <acq> <nid> <sd>` (set 0 to disable NID/SD).
|
||
`to` takes arguments: `to <acq> <nid>`.
|
||
|
||
### Toggle Commands
|
||
|
||
These commands toggle a mode and print the new state:
|
||
|
||
| Command | What it toggles |
|
||
|---------|----------------|
|
||
| `srch` | Search Transponders mode (on/off) |
|
||
| `shuf` | Transponder shuffle order (on/off) |
|
||
| `tablex` | Extended table mode (on/off) |
|
||
|
||
### Defaults Reset (`def`)
|
||
|
||
`def` silently resets all channel parameters to defaults. **No output, no
|
||
confirmation.** Use with caution — there is no undo.
|
||
|
||
### Modulation Switch (`msw`)
|
||
|
||
`msw` requires arguments but rejects all tested inputs (`msw 0`, `msw 1`,
|
||
`msw on`). Format unknown — possibly vestigial or requires a specific
|
||
modulation string.
|
||
|
||
### Channel Parameter Help (`h <n>`)
|
||
|
||
`h <n>` shows valid values for each of the 13+2 channel parameters:
|
||
|
||
| Param | Name | Range / Values |
|
||
|-------|------|---------------|
|
||
| 1 | Frequency | 250000–2150000 kHz (L-band IF) |
|
||
| 2 | Symbol Rate | 0 (Peak Scan) or 2000–45000 ksps |
|
||
| 3 | Trans_Mod_CRate | 30+ modes (see table below) |
|
||
| 4 | Blind Scan Mode | Bitmask: s2, trb, dvb, dss, dcii (see below) |
|
||
| 5 | LNB Polarity | 13V (vertical) / 18V (horizontal) |
|
||
| 6 | LNB Tone | off / on (22kHz for high-band switching) |
|
||
| 7 | Roll-off | 0.20 / 0.35 |
|
||
| 8 | LPF Cutoff | 0 (auto) or 1–40 MHz |
|
||
| 9 | Carrier Offset | -5000 to +5000 Hz |
|
||
| 10 | FreqSearchRange | 0–10000 kHz |
|
||
| 11 | DCII Mode | comb, i, q (QPSK) / ocomb, oi, oq (OQPSK) |
|
||
| 12 | Spectral Inversion | 0=normal, 1=q inv, 2=i inv, 3=scan |
|
||
| 13 | PScnSymRtRngMin | 2000–45000 ksps |
|
||
| 14 | PScnSymRtRngMax | (shown in `dis`, no `h 14` help) |
|
||
| 15 | SignalDetectMode | (shown in `dis`, no `h 15` help) |
|
||
|
||
#### Supported Modulations (Param 3)
|
||
|
||
```
|
||
DVB-S: dvbs_qpsk_1_2, dvbs_qpsk_2_3, dvbs_qpsk_3_4,
|
||
dvbs_qpsk_5_6, dvbs_qpsk_7_8
|
||
DSS: dss_qpsk_1_2, dss_qpsk_2_3, dss_qpsk_6_7
|
||
DCII: dcii_qpsk_1_2, dcii_qpsk_2_3, dcii_qpsk_3_4,
|
||
dcii_qpsk_5_11, dcii_qpsk_4_5
|
||
DVB-S2: s2_qpsk_1_2, s2_qpsk_3_5, s2_qpsk_2_3, s2_qpsk_3_4,
|
||
s2_qpsk_4_5, s2_qpsk_5_6, s2_qpsk_8_9, s2_qpsk_9_10,
|
||
s2_8psk_3_5, s2_8psk_2_3, s2_8psk_3_4
|
||
Turbo: turbo_qpsk_1_2, turbo_qpsk_2_3, turbo_qpsk_3_4,
|
||
turbo_qpsk_5_6, turbo_qpsk_7_8,
|
||
turbo_8psk_2_3, turbo_8psk_3_4, turbo_8psk_4_5,
|
||
turbo_8psk_5_6, turbo_8psk_8_9
|
||
Special: blind_scan
|
||
```
|
||
|
||
#### Blind Scan Mode Bitmask (Param 4)
|
||
|
||
Visual bitmask format: `s2_trb_dvb_dss_dcii`
|
||
|
||
| Value | Pattern | Standards enabled |
|
||
|-------|---------|-------------------|
|
||
| `s2` | `s2_______________` | DVB-S2 only |
|
||
| `trb` | `___trb___________` | Turbo FEC only |
|
||
| `dvb` | `_______dvb_______` | DVB-S only |
|
||
| `dss` | `___________dss___` | DSS (DirecTV) only |
|
||
| `dcii` | `_______________dcii` | DCII (DigiCipher) only |
|
||
| `all` | `s2_trb_dvb_dss_dcii` | All standards |
|
||
| `dish` | `___trb_dvb________` | DISH Network (turbo + DVB-S) |
|
||
| `3` | `___trb_dvb_dss___` | DirecTV 3-standard |
|
||
| `shaw` | `___trb_________dcii` | Shaw (turbo + DCII) |
|
||
| `nodcii` | `s2_trb_dvb_dss___` | All except DCII |
|
||
| `nos2` | `___trb_dvb_dss_dcii` | All except DVB-S2 |
|
||
|
||
### DiSEqC Commands
|
||
|
||
All DiSEqC 2.x read commands fail with `RxReplyTimeout` when no switch is
|
||
connected (expected — the G2 has a direct LNB without a multi-switch):
|
||
|
||
| Command | Function | Result (no switch) |
|
||
|---------|----------|--------------------|
|
||
| `di2id` | Read LNB hardware ID | `LNB Read HW ID FAIL` |
|
||
| `di2stat` | Read LNB status | `LNB Read Status FAIL` |
|
||
| `di2conf` | Read LNB config | `LNB Read Config FAIL` |
|
||
| `di2sc` | Short circuit test | `LNB Short Circuit FAIL` |
|
||
| `di2rcs` | Read switch state | `LNB Switch State FAIL` |
|
||
| `di2cs` | Configure switch | `No Parameters Specified` (needs args) |
|
||
| `send <3-6 bytes>` | Raw DiSEqC packet | (not tested — no switch) |
|
||
|
||
### DiSEqC Timing Parameters
|
||
|
||
| Command | Parameter | Default |
|
||
|---------|-----------|---------|
|
||
| `ovraddr` | LNB address | 0x11 (standard first LNB) |
|
||
| `rrto` | Receive reply timeout | 210 ms |
|
||
| `tdthresh` | Tone detect threshold | 110 (units: 0.16 counts/mV) |
|
||
| `pretx` | Pre-command TX delay | 15 ms |
|
||
|
||
### DVB Command Reference
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `rssi <n>` | One-shot | Average signal strength over n samples |
|
||
| `snr` | Streaming | SNR readings (avg + current) |
|
||
| `agc` | Streaming | RF/IF AGC + SNR + NID |
|
||
| `lnbdc odu` | One-shot | Enable LNB in ODU mode (13V) |
|
||
| `lnbv` | Streaming | Continuous LNB voltage monitoring |
|
||
| `ls` | Streaming | Full transponder lock scan (exits DVB on interrupt!) |
|
||
| `qls` | Streaming | Quick lock status (~100ms updates) |
|
||
| `nid` | Streaming | Network ID (CR-overwrite display) |
|
||
| `stats` | Streaming | Signal statistics (silent when no lock) |
|
||
| `config` | One-shot | BCM hardware/firmware version |
|
||
| `dis` | One-shot | Display all channel parameters |
|
||
| `diag` | One-shot | Multi-block per-transponder diagnostics |
|
||
| `table` | One-shot | Full 32-transponder scan (~136s) |
|
||
| `freqs` | One-shot | Frequency list name |
|
||
| `range` | One-shot | Transponder scan range |
|
||
| `pwr` | One-shot | SDS/DiSEqC power state |
|
||
| `srch_mode` | One-shot | Auto search mode value |
|
||
| `tabto` | Read/Write | Table scan timeouts (acq/nid/sd) |
|
||
| `to` | Read/Write | Single tune timeouts (acq/nid) |
|
||
| `t <n>` | Write | Select transponder |
|
||
| `e <n> <v>` | Write | Edit channel parameter |
|
||
| `h <n>` | Read | Parameter help (valid values for param n, 1-13) |
|
||
| `srch` | Toggle | Search transponders mode |
|
||
| `shuf` | Toggle | Transponder shuffle order |
|
||
| `tablex` | Toggle | Extended table mode |
|
||
| `def` | Write | Reset all params to defaults (silent, no undo!) |
|
||
| `msw <?>` | Write | Modulation switch (format unknown) |
|
||
| `ovraddr [addr]` | Read/Write | DiSEqC LNB address |
|
||
| `rrto [ms]` | Read/Write | DiSEqC receive reply timeout |
|
||
| `tdthresh [val]` | Read/Write | DiSEqC tone detect threshold |
|
||
| `pretx [ms]` | Read/Write | DiSEqC pre-TX delay |
|
||
| `di2id` | Read | DiSEqC 2.x: read LNB hardware ID |
|
||
| `di2stat` | Read | DiSEqC 2.x: read LNB status |
|
||
| `di2conf` | Read | DiSEqC 2.x: read LNB config |
|
||
| `di2sc` | Read | DiSEqC 2.x: short circuit test |
|
||
| `di2rcs` | Read | DiSEqC 2.x: read switch state |
|
||
| `di2cs <args>` | Write | DiSEqC 2.x: configure switch |
|
||
| `send <3-6 hex>` | Write | Raw DiSEqC packet |
|
||
|
||
**Streaming commands:** `snr`, `agc`, `lnbv`, `qls`, `nid`, `stats` run until
|
||
CR interrupts. All stay in DVB submenu except `ls` which drops to `TRK>`.
|
||
|
||
**Toggle commands:** `srch`, `shuf`, `tablex` alternate on/off and print new state.
|
||
|
||
## Satellite Configuration
|
||
|
||
```
|
||
DVB: id:0000, lon:101.00E ← DirecTV 101°W (stored as East longitude)
|
||
Primary Update: 10100 ← 101.00° in centidegrees
|
||
Alternate Update: 11900 ← 119.00°
|
||
Sat Provider Update: 1 ← Provider ID
|
||
Dipswitch Value: 101 ← DirecTV configuration
|
||
```
|
||
|
||
## A3981 Motor Driver IC
|
||
|
||
The Allegro A3981 is an automotive-grade programmable stepper motor driver
|
||
controlled by the K60 MCU via SPI. Two A3981 chips — one per axis (AZ, EL).
|
||
|
||
**Datasheet:** `docs/A3981-datasheet.pdf` (Allegro Microsystems)
|
||
**ECAD files:** `docs/A3981-ecad.kicad_sym`, `docs/A3981-ecad.pretty/`
|
||
|
||
### A3981 Commands (`A3981>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `diag` | Read | Fault diagnostics for both axes |
|
||
| `sm` | Read | Step size mode (AUTO/MANUAL) |
|
||
| `ss` | Read | Current step size (microstepping level) |
|
||
| `cm` | Read | Current control mode (AUTO/MANUAL) |
|
||
| `st <params>` | Write | Set torque/current parameters |
|
||
| `reset` | Write | Clear latched A3981 faults on both axes |
|
||
|
||
### Diagnostics
|
||
|
||
```
|
||
diag
|
||
AZ DIAG: OK
|
||
EL DIAG: OK
|
||
```
|
||
|
||
### Microstepping Configuration
|
||
|
||
```
|
||
ss
|
||
KEY: FULL-16, HALF-8, QTR-4, EIGHTH-2, SIXTEENTH-1
|
||
AZ Step Size:1
|
||
EL Step Size:1
|
||
```
|
||
|
||
Both axes at step size 1 = **1/16 microstepping** (finest available). The A3981
|
||
supports full, half, quarter, eighth, and sixteenth steps. The inverted key
|
||
(FULL=16, SIXTEENTH=1) is the firmware's internal representation — likely a
|
||
divisor applied to the full-step pulse count.
|
||
|
||
### Step Size and Current Modes
|
||
|
||
```
|
||
sm cm
|
||
AZ Step Size Mode = AUTO AZ: Mode = AUTO
|
||
EL Step Size Mode = AUTO EL: Mode = AUTO
|
||
```
|
||
|
||
AUTO mode means the driver dynamically adjusts microstepping resolution and
|
||
current level based on motor speed. At low speeds, fine microstepping (1/16)
|
||
provides smooth motion and precise positioning. At higher speeds, the driver
|
||
may switch to coarser steps to maintain torque.
|
||
|
||
### Fault Reset
|
||
|
||
```
|
||
reset
|
||
Az/El A3981 Faults Reset.
|
||
```
|
||
|
||
Clears latched fault conditions (overcurrent, open load, thermal). This is a
|
||
**write** operation — it actively clears the fault registers, not a read-only
|
||
status check. Use `diag` for non-destructive fault checking.
|
||
|
||
## ADC Subsystem (`ADC>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `m` | Streaming | Monitor RSSI continuously |
|
||
| `rssi` | One-shot | Read RSSI (same noise-floor value as DVB) |
|
||
| `scan` | Unknown | Scan ADC on azimuth axis |
|
||
| `bdid` | One-shot | Board identification string |
|
||
| `bdrevid` | One-shot | Board revision ID |
|
||
|
||
### Board Identification
|
||
|
||
```
|
||
bdid → STATIONARY
|
||
bdrevid → A
|
||
```
|
||
|
||
"STATIONARY" confirms this is the non-mobile (non-in-motion) variant. Board
|
||
revision "A" is the first production revision.
|
||
|
||
### RSSI via ADC
|
||
|
||
```
|
||
rssi → 500
|
||
```
|
||
|
||
Same noise floor value (500) as the DVB `rssi` command. The ADC subsystem reads
|
||
the same analog signal path — likely a baseband power detector output from the
|
||
BCM4515 routed to a K60 ADC input.
|
||
|
||
## Dipswitch (`DIPSWITCH>`)
|
||
|
||
```
|
||
dipswitch
|
||
val:ffffff01
|
||
app_dipswitch:101
|
||
```
|
||
|
||
The raw value `0xFFFFFF01` has the low byte = 0x01. The `app_dipswitch` value
|
||
101 corresponds to the DirecTV satellite configuration. Dipswitch values select
|
||
the satellite provider (DirecTV, DISH, Bell) and determine which transponder
|
||
frequencies the search algorithm tries.
|
||
|
||
## EEPROM (`EE>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `ee <idx>` | Read | Read EEPROM value at index |
|
||
| `ee <idx> <val>` | Write | Write EEPROM value at index |
|
||
| `inv [<idx>]` | Write | **Invalidate** EEPROM index (destructive!) |
|
||
| `def` | Write | Restore all EEPROM values to factory defaults |
|
||
|
||
EEPROM is a separate storage area from NVS. NVS holds operational parameters
|
||
(motor tuning, PID gains, satellite config). EEPROM appears to hold calibration
|
||
or factory data — likely stored in an external I2C EEPROM (AT24Cxx or similar)
|
||
rather than the K60's internal flash.
|
||
|
||
### EEPROM Structure
|
||
|
||
The EEPROM has exactly **17 indices (0-16)**. The firmware enforces bounds:
|
||
|
||
```
|
||
ee 17
|
||
Index out of bounds:17 Min:0 Max:16
|
||
```
|
||
|
||
Each index stores a 32-bit unsigned integer. Invalid entries return a sentinel
|
||
value of **65793 (0x00010101)** — three bytes of 0x01 in the low 24 bits. The
|
||
firmware distinguishes between valid and invalid reads:
|
||
|
||
- **Valid:** `Read value = <decimal>` — data is trusted
|
||
- **Invalid:** `Failed to read. val:<decimal>` — data exists but flagged invalid
|
||
|
||
### Complete EEPROM Dump
|
||
|
||
Dumped via `scripts/ee_dump.py` (pyserial script scanning all indices):
|
||
|
||
| Index | Decimal | Hex | Status | Notes |
|
||
|------:|--------:|-----|--------|-------|
|
||
| 0 | 65793 | 0x00010101 | INVALID | Accidentally invalidated (`inv 0`) |
|
||
| 1 | 0 | 0x00000000 | OK | |
|
||
| 2 | 22897 | 0x00005971 | OK | |
|
||
| 3 | 3748 | 0x00000EA4 | OK | |
|
||
| 4 | 4346 | 0x000010FA | OK | |
|
||
| 5 | 11637 | 0x00002D75 | OK | |
|
||
| 6 | 65793 | 0x00010101 | INVALID | Factory default (never written) |
|
||
| 7 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 8 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 9 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 10 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 11 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 12 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 13 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 14 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 15 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
| 16 | 65793 | 0x00010101 | INVALID | Factory default |
|
||
|
||
Only **6 indices** (0-5) were ever written with valid data. Indices 6-16 have
|
||
never been programmed — all contain the 0x00010101 sentinel. The EEPROM has
|
||
capacity for 17 values but only the first 6 are used by this firmware version.
|
||
|
||
### Value Analysis
|
||
|
||
The valid EEPROM values (indices 1-5) don't correspond to any obvious motor
|
||
positions, NVS indices, or physical constants. They may represent:
|
||
|
||
- **Factory calibration offsets** — motor encoder corrections, sensor trim
|
||
- **Manufacturing data** — serial number components, PCB revision, test results
|
||
- **Checksum/signature** — authentication for firmware/hardware pairing
|
||
|
||
Index 0 (originally valid, now invalidated) was likely a calibration value or
|
||
header byte. Its original value is unknown — `def` might restore it.
|
||
|
||
### Command Notes
|
||
|
||
**`inv [<idx>]`** — "Invalidate", not "inventory". Marks an index as invalid
|
||
by writing the 0x00010101 sentinel. The firmware still returns the raw value
|
||
on read but flags it as `Failed to read`. **Destructive and immediate** — no
|
||
confirmation prompt.
|
||
|
||
**`def`** — Restores all EEPROM indices to factory defaults. Not tested on this
|
||
unit (would overwrite the accidentally-invalidated index 0 but also reset any
|
||
user-modified values). Worth trying if index 0's missing value causes issues.
|
||
|
||
**`ee <idx> <val>`** — Write a value to an index. Accepts decimal integers.
|
||
Can be used to restore invalidated indices if the original value is known.
|
||
|
||
## GPIO Registers (`GPIO>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `regs` | Read | Dump all GPIO pin states (0/1) |
|
||
| `r <port> <pin>` | Read | Read single GPIO pin (e.g., `r A 5`) |
|
||
| `w <port> <pin>` | Write | Write to GPIO pin (toggle) |
|
||
| `dir <bit> <val>` | Write | Set pin direction (input/output) |
|
||
|
||
The `regs` command dumps all MCU GPIO pins across 5 ports (K60 144-pin).
|
||
Note: pins A20-A23 and B12-B15 are not enumerated (reserved or unbonded):
|
||
|
||
| Port | Pins Enumerated | High Pins (=1) |
|
||
|------|----------------|----------------|
|
||
| A | A0–A19, A24–A29 (26 pins) | A1, A3, A4, A5, A15, A16, A25–A29 |
|
||
| B | B0–B11, B16–B23 (20 pins) | B0, B1, B2, B3, B11 |
|
||
| C | C0–C19 (20 pins) | C10, C11, C12, C13, C18 |
|
||
| D | D0–D15 (16 pins) | D11, D12, D13 |
|
||
| E | E0–E12, E24–E29 (19 pins) | E0, E1, E2, E4, E5, E7, E9–E12, E24–E28 |
|
||
|
||
Total: 101 pins enumerated. "Unknown bit E29" logged by firmware — pin E29
|
||
is defined in hardware but not assigned a function (test point or reserved).
|
||
|
||
## LATLON (`LATLON>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `l <satlon1> <satlon2> <satel1> <satel2>` | Read | Calculate dish lat/lon from two satellite observations |
|
||
|
||
This is the dish's **self-localization algorithm** — it triangulates its own
|
||
geographic position by observing two known geostationary satellites. The four
|
||
parameters are longitude and elevation pairs for two satellites.
|
||
|
||
```
|
||
l -110 -119 40 38
|
||
anglesentered = -11000 -11900 4000 3800
|
||
Lat = 4295 Lon = 25655
|
||
```
|
||
|
||
Output is in centidegrees: Lat 4295 = 42.95°N, Lon 25655 = 256.55°E (= 103.45°W).
|
||
This is a reasonable US mid-latitude position given DISH Network satellites at
|
||
110°W and 119°W with elevation angles of 40° and 38°.
|
||
|
||
The firmware uses this for automatic satellite look-angle computation when no
|
||
GPS is available (the G2 has no GPS module — "GPS Not Found" at boot).
|
||
|
||
## PEAK Subsystem (`PEAK>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `ts` | **Streaming (DANGEROUS)** | EchoStar/DiSEqC switch toggle — runs forever, can't be interrupted |
|
||
| `pw <az> <el>` | Motor+Signal | Peak wide — sweep around AZ/EL to find signal peak |
|
||
| `psnr <az> <el>` | Motor+Signal | Peak SNR — sweep around AZ/EL optimizing for SNR |
|
||
| `pxy1 [<n>]` | Motor+Signal | Peak XY1 — 2D cross-pattern peak search, repeat n times (default 1) |
|
||
| `stb` | One-shot | STB control test — toggles LNB polarity and compares RSSI |
|
||
| `rssits` | **Streaming** | RSSI test — prints every 1 minute (exits submenu on interrupt!) |
|
||
|
||
### EchoStar Switch Toggle (`ts`) — DANGEROUS!
|
||
|
||
The `ts` command runs **indefinitely**, probing for a DiSEqC/EchoStar switch
|
||
by toggling LNB voltage and reading the switch response. It cannot be stopped
|
||
by sending `q` — the running command consumes all input. The only escape is to
|
||
close and reopen the serial port.
|
||
|
||
```
|
||
ts
|
||
(14000+ reads, all showing: 0b0000 0)
|
||
```
|
||
|
||
All reads returned `0b0000 0` — no switch connected (expected, since the G2's
|
||
LNB is directly connected without a multi-switch).
|
||
|
||
### STB Control Test (`stb`)
|
||
|
||
Toggles LNB polarization and compares RSSI at each polarity:
|
||
|
||
```
|
||
stb
|
||
Enabled LNB ODU 18V
|
||
Even_sig = 504
|
||
Enabled LNB STB
|
||
Odd_sig = 232
|
||
Enabled LNB STB
|
||
Odd_sig = 233 Ctr = 0
|
||
```
|
||
|
||
- `Enabled LNB ODU 18V` → horizontal polarization (18V), `Even_sig = 504`
|
||
- `Enabled LNB STB` → vertical polarization (13V), `Odd_sig = 232`
|
||
- `Ctr = 0` → no DiSEqC switch response detected
|
||
- The 504 vs 232 difference (~2x) reflects the polarization-dependent noise
|
||
floor. "Even" = H-pol transponders (18V), "Odd" = V-pol (13V) — DBS convention.
|
||
|
||
### RSSI Test (`rssits`)
|
||
|
||
Starts a background RSSI monitoring task that prints every 1 minute. When
|
||
interrupted, **exits the PEAK submenu entirely** (drops to `TRK>` root),
|
||
similar to DVB `ls` behavior.
|
||
|
||
## STEP Subsystem (`STEP>`) — Low-Level Motor Control
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `e` | Write | Engage motor (enable driver) |
|
||
| `r` | Write | Release motors (disable driver, coast to stop) |
|
||
| `p` | Read/Write | Go to position (absolute, in microsteps), or read current position |
|
||
| `v` | Write | Go to velocity (continuous rotation) |
|
||
| `ma` | Read/Write | Set/get max acceleration (ustep/sec/msec) |
|
||
| `mv` | Read/Write | Set/get max velocity (ustep/sec) |
|
||
| `pid` | Read/Write | Set/get PID tuning values |
|
||
|
||
This is the raw stepper motor interface — below the `mot` menu's degree-based
|
||
abstraction. Commands operate in **microsteps** rather than degrees. The
|
||
relationship between microsteps and degrees depends on:
|
||
|
||
- Gear ratio (NVS 49, currently 0x00000000)
|
||
- Steps per revolution (NVS 83: AZ=40000, NVS 88: EL=24960)
|
||
- Microstepping level (A3981: both at 1/16)
|
||
|
||
### Current Values (read mode)
|
||
|
||
```
|
||
p → Step Pos[0] = 19998 Step Pos[1] = 3116
|
||
ma → Accel[0] = 44 Accel[1] = 28
|
||
mv → Max Vel [0] = 7222 Max Vel [1] = 3120
|
||
pid → Kp=250 Kv=50
|
||
```
|
||
|
||
### MOT↔STEP Conversion Table
|
||
|
||
| Parameter | STEP (microsteps) | MOT (degrees) | Factor |
|
||
|-----------|-------------------|---------------|--------|
|
||
| AZ position | 19998 | 179.98° | 111.11 steps/° |
|
||
| EL position | 3116 | 44.94° | 69.33 steps/° |
|
||
| AZ max vel | 7222 ustep/s | 65.0°/s | ÷111.11 |
|
||
| EL max vel | 3120 ustep/s | 45.0°/s | ÷69.33 |
|
||
| AZ accel | 44 ustep/s/ms | ~396°/s² | ×1000÷111.11 |
|
||
| EL accel | 28 ustep/s/ms | ~404°/s² | ×1000÷69.33 |
|
||
|
||
### PID Tuning
|
||
|
||
`pid` returns `Kp=250 Kv=50` — proportional and velocity gains. No Ki term,
|
||
indicating a PD (proportional-derivative) position loop. This is typical for
|
||
stepper motors which don't drift under holding torque. Matches NVS indices
|
||
128-129. Note: `pid` is write-only in `MOT>` but **readable in `STEP>`**.
|
||
|
||
The `e`/`r` commands engage and release the A3981 motor drivers. When released,
|
||
the motors are unpowered and the dish can be moved by hand (useful for manual
|
||
positioning or emergency stow). When engaged, the PID loop holds position.
|
||
|
||
## ADC Subsystem (`ADC>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `bdid` | Read | Board ID — returns `STATIONARY` |
|
||
| `bdrevid` | Read | Board revision ID — returns `A` |
|
||
| `rssi` | Read | Single RSSI reading (ADC value, not DVB RSSI) |
|
||
| `m` | Toggle? | Monitor RSSI — returns immediately, may enable background monitoring |
|
||
| `scan` | **Streaming** | Continuous ADC scan with position, RSSI, Lock, SNR, and delta |
|
||
|
||
### Board Identity
|
||
|
||
- **Board ID:** `STATIONARY` — distinguishes from mobile/in-motion antenna variants
|
||
- **Board Rev ID:** `A` — PCB revision
|
||
|
||
### RSSI (ADC)
|
||
|
||
`rssi` returns a single ADC reading: `232` at noise floor. This is the raw
|
||
ADC value from an analog RSSI detector (separate from the DVB tuner's digital
|
||
RSSI). The ADC RSSI baseline (~232) corresponds to the DVB `Odd_sig` in the
|
||
PEAK `stb` test, suggesting both measure the same RF path at V-pol.
|
||
|
||
### Scan (Streaming)
|
||
|
||
`scan` performs a continuous RF scan at the current position:
|
||
|
||
```
|
||
Starting position AZ:17998 EL:4494 Stop at:0
|
||
Motor:0 Angle:17998 RSSI:232 Lock:0 SNR: 0.0 Scan Delta:0
|
||
Motor:0 Angle:17998 RSSI:238 Lock:0 SNR: 0.0 Scan Delta:0
|
||
Motor:0 Angle:17998 RSSI:233 Lock:0 SNR: 0.4 Scan Delta:0
|
||
...
|
||
```
|
||
|
||
Positions are in centidegrees (17998 = 179.98°). `Scan Delta:0` indicates no
|
||
motor movement — the scan reads RSSI at the fixed position. `Stop at:0` suggests
|
||
it scans until manually interrupted. Occasional SNR transients (0.1–0.4 dB)
|
||
appear from fleeting RF energy. The scan likely moves the motor when used with
|
||
the `azscanwxp` sky-scan command from the MOT menu.
|
||
|
||
## Dipswitch Subsystem (`DIPSWITCH>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `dipswitch` | Read | Read physical DIP switch state and interpreted value |
|
||
|
||
```
|
||
dipswitch
|
||
val:ffffff01
|
||
app_dipswitch:101
|
||
```
|
||
|
||
- `val: ffffff01` — raw GPIO register reading. The `0x01` LSB indicates one
|
||
switch position is active; `0xFF` bytes are pulled-up (inactive) switches.
|
||
- `app_dipswitch: 101` — firmware-interpreted value. Matches NVS index 113
|
||
("Dipswitch Value: 101"), which encodes a DirecTV satellite configuration.
|
||
|
||
The physical DIP switch on the PCB selects the satellite provider's transponder
|
||
list for TV search mode. NVS index 112 ("Disable Dipswitch?") controls whether
|
||
the firmware reads the physical switch or uses the NVS-stored value. Since
|
||
we've disabled the tracker (NVS 20 = TRUE), the DIP switch setting is ignored.
|
||
|
||
## A3981 Motor Driver (`A3981>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `diag` | Read | Read AZ/EL diagnostic pins (fault status) |
|
||
| `sm` | Read/Write | Get/set step size mode (AUTO, manual) |
|
||
| `ss` | Read/Write | Get/set step size (microstepping divisor) |
|
||
| `st` | Read/Write | Get/set torque level (HIGH/LOW current) |
|
||
| `cm` | Read/Write | Get/set current control mode (AUTO, manual) |
|
||
| `reset` | Write | Reset AZ/EL A3981 diagnostic/fault registers |
|
||
|
||
### Current State
|
||
|
||
```
|
||
diag → AZ DIAG: OK EL DIAG: OK
|
||
sm → AZ: Step Size Mode = AUTO EL: Step Size Mode = AUTO
|
||
ss → AZ: Step Size:1 EL: Step Size:1
|
||
st → AZ Torq:LOW EL Torq:LOW
|
||
cm → AZ: Mode = AUTO EL: Mode = AUTO
|
||
```
|
||
|
||
### Step Size Key
|
||
|
||
The `ss` value is a microstepping **divisor**, not multiplier:
|
||
|
||
| Value | Mode | Microsteps per full step |
|
||
|-------|------|------------------------|
|
||
| 16 | FULL | 1 (full step) |
|
||
| 8 | HALF | 2 |
|
||
| 4 | QTR | 4 |
|
||
| 2 | EIGHTH | 8 |
|
||
| 1 | SIXTEENTH | 16 (finest) |
|
||
|
||
Both motors are at `1` (1/16 microstepping — finest resolution). In `AUTO`
|
||
mode, the A3981 IC automatically selects the step size based on speed: finer
|
||
steps at low speed for smooth positioning, coarser steps at high speed for
|
||
torque.
|
||
|
||
### Torque and Current Control
|
||
|
||
`st` shows torque is `LOW` (motors idle/holding). `cm` shows current control
|
||
is `AUTO` — the firmware switches between high current (moving) and low current
|
||
(holding) automatically. This reduces power consumption and heat when the dish
|
||
is stationary.
|
||
|
||
The `diag` pins expose A3981 fault conditions: overcurrent, overtemperature,
|
||
open-load (disconnected motor winding), or short-to-ground. `OK` means no
|
||
faults detected. Use `reset` to clear latched fault flags.
|
||
|
||
## OS Subsystem (`OS>`)
|
||
|
||
| Command | Type | Description |
|
||
|---------|------|-------------|
|
||
| `id` | Read | Full MCU and firmware identification |
|
||
| `reboot` | Write | Reboot microcontroller (confirmed — full boot cycle ~10s) |
|
||
|
||
### System Identification (`id`)
|
||
|
||
```
|
||
NVS Version: 1.02.13
|
||
System ID: TWELINCH
|
||
K60-144pin
|
||
Silicon Rev 2.4
|
||
Mask Set 4N22D
|
||
512 kBytes of P-flash
|
||
P-flash only
|
||
128 kBytes of RAM
|
||
Board Rev ID: A
|
||
Board ID: STATIONARY
|
||
Ant ID: 12-IN G2
|
||
Software version: 02.02.48
|
||
CCLK: 96000000
|
||
BCLK: 48000000
|
||
Flash Base Address: 65536
|
||
Flash Size: 458752
|
||
```
|
||
|
||
Key details:
|
||
- **System ID:** `TWELINCH` — "Twelve Inch" (12" dish diameter)
|
||
- **Ant ID:** `12-IN G2` — Carryout G2 model identifier
|
||
- **Silicon:** K60-144pin, Rev 2.4, Mask 4N22D — NXP MK60DN512VLQ10
|
||
- **Clocks:** CCLK=96 MHz (core), BCLK=48 MHz (bus)
|
||
- **Flash:** Base at 0x10000 (64KB), size 458752 bytes (448KB usable firmware space)
|
||
- **NVS Version:** 1.02.13 — the non-volatile storage schema version
|
||
|
||
Note: `tasks` and `kill` commands (available on other variants like HAL 0.0.00)
|
||
are **not present** in the G2's OS submenu. On the G2, the satellite search is
|
||
disabled permanently via NVS index 20 instead of killing a running task.
|
||
|
||
## Firmware Command Behavior Notes
|
||
|
||
### Command Types
|
||
|
||
- **One-shot:** Executes once, returns result, shows prompt (`>`). Safe.
|
||
- **Streaming:** Runs indefinitely until interrupted. Some accept `q` to stop,
|
||
others require closing the serial port. The `ts`, `agc`, and `lnbv` commands
|
||
are known streamers.
|
||
- **Write:** Modifies state (motor position, NVS values, fault registers). Use
|
||
with caution.
|
||
|
||
### Serial Protocol Notes
|
||
|
||
- Firmware expects ASCII CR (`0x0D`) as line terminator
|
||
- Response terminates with `>` prompt character (ASCII 62)
|
||
- Console does not support backspace — press Enter to clear on typo
|
||
- Streaming commands consume all serial input while running
|
||
- Some commands (e.g., `st`) are setters that return "Invalid params" when
|
||
called without arguments — they are not read-only despite appearing in
|
||
help listings without obvious setter syntax
|
||
|
||
## TODO: Physical Board Inspection
|
||
|
||
Tasks for when the dome housing is opened and the control PCB is accessible.
|
||
|
||
### USB Port Investigation
|
||
|
||
- [ ] Inspect LQFP-144 package pins 19-22 (USB0_DP, USB0_DM, VOUT33, VREGIN)
|
||
— these are on the corner near pin 1. Look for traces routing to a
|
||
connector, test pads, or unpopulated header
|
||
- [ ] Look for a USB mini/micro/Type-A connector anywhere on the PCB (may be
|
||
behind a panel, under a shield can, or on the back side)
|
||
- [ ] Check for a VBUS sense GPIO trace — the K60 needs a GPIO pin to detect
|
||
USB cable insertion (ref manual Section 3.9.2)
|
||
- [ ] If USB pads found: probe with multimeter for continuity to K60 pins 19-22
|
||
|
||
### Debug / Programming Interface
|
||
|
||
- [ ] Look for SWD/JTAG debug header (K60 has dedicated SWD pins: SWDIO on
|
||
PTA3/pin 50, SWDCLK on PTA0/pin 46, SWO on PTA2/pin 49, RESET on pin 74).
|
||
Could be a 10-pin Cortex Debug connector, 2x5 shrouded header, or
|
||
unpopulated pads
|
||
- [ ] Check for a UART boot mode pin — K60 supports serial bootloader via
|
||
UART if NMI/FOPT bits are configured. Look for jumpers or DIP switches
|
||
near the MCU
|
||
- [ ] Identify the boot flash at 0x00000-0x0FFFF — is it internal to the K60
|
||
or an external SPI flash? Check for small SOIC-8 flash chips near MCU
|
||
|
||
### Firmware Extraction via SWD
|
||
|
||
Serial bootloader has no interactive mode (confirmed: no interrupt window,
|
||
no baud rate trick, binary-only status bytes `01 00` and `98 80 96`). SWD
|
||
is the primary extraction path.
|
||
|
||
**Equipment:** SWD probe (ST-Link V2, J-Link, or similar) + 4 jumper wires.
|
||
|
||
**Connections (minimum 3 wires + GND):**
|
||
|
||
| Signal | K60 Pin | LQFP-144 | Notes |
|
||
|--------|---------|----------|-------|
|
||
| SWDIO | PTA3 | Pin 50 | Bidirectional data |
|
||
| SWDCLK | PTA0 | Pin 46 | Clock (probe drives) |
|
||
| GND | — | Multiple | Common ground with probe |
|
||
| RESET | — | Pin 74 | Optional but recommended |
|
||
| SWO | PTA2 | Pin 49 | Optional trace output |
|
||
|
||
**Step 1: Check flash security (CRITICAL — do this first)**
|
||
|
||
```bash
|
||
# pyocd (recommended)
|
||
pyocd cmd -t mk60dn512xxx10 -c "read32 0x40C"
|
||
|
||
# or openocd
|
||
openocd -f interface/stlink.cfg -f target/k60.cfg \
|
||
-c "init; halt; mdw 0x40C; exit"
|
||
```
|
||
|
||
The Flash Security register (FTFL_FSEC) at `0x40C`:
|
||
- Bits [1:0] = `10` → **SECURED** — SWD reads blocked, need EzPort fallback
|
||
- Bits [1:0] = `00` or `11` → **UNSECURED** — full flash dump possible
|
||
|
||
Also check `0x400` (FTFL_FOPT / Flash Configuration Field at 0x400-0x40F):
|
||
```bash
|
||
pyocd cmd -t mk60dn512xxx10 -c "read8 0x400 16"
|
||
```
|
||
This 16-byte field (programmed into flash at 0x400) controls boot security,
|
||
backdoor key, mass erase enable, and other flash protection settings.
|
||
|
||
**Step 2: Dump firmware (if unsecured)**
|
||
|
||
```bash
|
||
# Full 512KB flash dump (bootloader + application)
|
||
pyocd flash -t mk60dn512xxx10 -r firmware_full.bin \
|
||
--address 0x00000 --size 0x80000
|
||
|
||
# Or just the application (448KB)
|
||
pyocd flash -t mk60dn512xxx10 -r firmware_app.bin \
|
||
--address 0x10000 --size 0x70000
|
||
|
||
# Also dump the 128KB RAM (may contain runtime state)
|
||
pyocd cmd -t mk60dn512xxx10 \
|
||
-c "savemem 0x1FFF0000 0x20020000 sram_dump.bin"
|
||
```
|
||
|
||
**Step 3: If flash is secured — EzPort fallback**
|
||
|
||
EzPort is an SPI-based flash interface activated by holding PTA4 (pin 51)
|
||
low during reset. It may bypass flash security for reads on some K60 silicon
|
||
revisions (Rev 2.4 / mask 4N22D — check errata).
|
||
|
||
```
|
||
EzPort SPI wiring:
|
||
EZP_CS = PTA4 (pin 51) — hold LOW during reset to enter EzPort
|
||
EZP_CLK = PTA0 (pin 46) — same pin as SWDCLK!
|
||
EZP_DOUT = PTA2 (pin 49) — same pin as SWO
|
||
EZP_DIN = PTA1 (pin 47)
|
||
```
|
||
|
||
EzPort commands: `0x03` = Read, `0x05` = Read Status, `0x0B` = Fast Read.
|
||
Use an SPI master (ESP32, RPi, FTDI MPSSE) at ≤ 4 MHz.
|
||
|
||
**Flash layout (from `os id`):**
|
||
|
||
```
|
||
0x00000 - 0x0FFFF Bootloader v1.01 (64KB)
|
||
0x10000 - 0x7FFFF Application v02.02.48 (448KB)
|
||
Total: 512KB (0x80000)
|
||
```
|
||
|
||
**Boot sequence bytes (from serial capture):**
|
||
|
||
```
|
||
reboot echo → 0x01 0x00 (binary status) → "Bootloader version: 1.01"
|
||
→ "Application is running..." → 0x98 0x80 0x96 (binary, meaning unknown)
|
||
→ "Application Starting Kinetis PCB..."
|
||
```
|
||
|
||
The `0x01 0x00` and `0x98 0x80 0x96` are binary protocol bytes between
|
||
bootloader and application — possibly a handshake or integrity check.
|
||
Understanding these requires disassembling the bootloader.
|
||
|
||
### Component Identification
|
||
|
||
- [ ] Photograph both sides of the PCB (high-res, good lighting)
|
||
- [ ] Read markings on the BCM4515 DVB tuner IC — confirm package, check for
|
||
additional Broadcom support ICs nearby
|
||
- [ ] Identify the two A3981 stepper driver ICs (TSSOP-28 with exposed pad,
|
||
should be near motor connectors). Note their orientation and surrounding
|
||
passives (sense resistors for current measurement)
|
||
- [ ] Read crystal oscillator marking — frequency determines PLL configuration
|
||
(K60 accepts 3-32 MHz, likely 8 MHz or 16 MHz for clean 96 MHz PLL)
|
||
- [ ] Check for external EEPROM (separate from K60 internal flash) — likely
|
||
I2C EEPROM near MCU, possibly AT24Cxx or M24Cxx series
|
||
- [ ] Look for LNB voltage regulator circuit (13V/18V switching) — probably
|
||
near the coax F-connector
|
||
|
||
### Gyro / IMU Investigation
|
||
|
||
- [ ] NVS indices 72-77 configure gyro parameters (sensitivity, filter, mount
|
||
type) but boot log says nothing about a gyro. Check if there's an
|
||
onboard MEMS gyro or an unpopulated footprint for one
|
||
- [ ] If present, identify the gyro IC (likely single-axis rate gyro given
|
||
the NVS parameters — "Gyro Mount Type: 1" suggests a specific axis)
|
||
- [ ] If unpopulated: the G2 may share a PCB design with a larger model
|
||
(Trav'ler SK-1000?) that includes a gyro for in-motion tracking
|
||
|
||
### GPS Investigation
|
||
|
||
- [ ] Boot log says "GPS Not Found" — look for a GPS module footprint
|
||
(populated or empty). NVS 63-64 configure GPS heading/moving thresholds
|
||
- [ ] Check for a GPS antenna connector (SMA or U.FL) or ceramic patch antenna
|
||
on the PCB
|
||
- [ ] If unpopulated: same shared-PCB theory as the gyro — the G2 firmware
|
||
has GPS support but the hardware may be DNP (Do Not Populate)
|
||
|
||
### Motor / Drive Train
|
||
|
||
- [ ] Trace SPI bus from K60 to A3981 drivers — identify which DSPI peripheral
|
||
(DSPI0, DSPI1, or DSPI2) connects to which axis (AZ vs EL)
|
||
- [ ] Identify motor sense resistors near A3981 chips — value determines
|
||
current limit calibration. Compare with NVS current limit hex values
|
||
(indices 95-98, 110-111)
|
||
- [ ] Check motor connectors — are they direct stepper connections (4-wire) or
|
||
do they go through additional driver stages?
|
||
- [ ] Look for limit switches or optical encoders (the G2 uses stall detection
|
||
for homing, but there may be unused provisions for position feedback)
|
||
|
||
### RF Signal Path
|
||
|
||
- [ ] Trace signal path: F-connector → LNB bias tee → BCM4515 RF input
|
||
- [ ] Identify any bandpass filters, LNAs, or frequency conversion stages
|
||
between the coax and the BCM4515
|
||
- [ ] Check if the ADC RSSI signal is a dedicated analog output from BCM4515
|
||
or if it's derived from an AGC control voltage
|
||
|
||
### Power Supply
|
||
|
||
- [ ] Identify main voltage rails — the board likely has 12V input (from
|
||
RP-SK87 PSU), 5V (for logic), 3.3V (K60 core), and motor supply
|
||
- [ ] Check if the USB VREG (K60 pins 21-22) is connected to anything or
|
||
if VOUT33 is tied to the board's 3.3V rail directly
|
||
- [ ] Identify motor power supply — A3981 supports up to 28V, the board
|
||
likely runs motors at 12V from the main supply
|
||
|
||
## TODO: Firmware Exploration (Serial Console)
|
||
|
||
Remaining commands to test via the RS-422 console.
|
||
|
||
### DVB Submenu (Task #13) — COMPLETE
|
||
|
||
- [x] `ls` — streaming transponder scan (exits DVB submenu on interrupt!)
|
||
- [x] `qls` — streaming quick lock status (~100ms: `Lock:0 rssi:500 cnt:0`)
|
||
- [x] `snr` — streaming SNR readings (transient spikes in noise floor)
|
||
- [x] `diag` — multi-block one-shot per-transponder diagnostics
|
||
- [x] `table` — full 32-transponder scan (~136s), detailed per-xp data
|
||
- [x] `freqs` — frequency list name ("Non-Stacked")
|
||
- [x] `stats` — streaming, silent when no lock
|
||
- [x] `nid` — streaming network ID (FFFF/none), CR-overwrite display
|
||
- [x] `di2id` / `di2stat` / `di2conf` / `di2sc` / `di2rcs` — all fail (no switch)
|
||
- [x] `di2cs` — needs parameters (switch config)
|
||
- [x] `send` — needs 3-6 hex bytes (raw DiSEqC packet)
|
||
- [x] `h 1-13` — full parameter help documented
|
||
- [x] `tabto` / `to` — timeout configs (table vs single tune)
|
||
- [x] `ovraddr` / `rrto` / `tdthresh` / `pretx` — DiSEqC timing params
|
||
- [x] `srch` / `shuf` / `tablex` — toggle commands
|
||
- [x] `pwr` — power state, `srch_mode` — search mode, `range` — scan range
|
||
- [x] `def` — silent defaults reset (dangerous!), `msw` — format unknown
|
||
- [ ] `e <n> <v>` — edit channel params (not tested — would modify state)
|
||
- [ ] `send <hex>` — raw DiSEqC (not tested — no switch connected)
|
||
|
||
### MOT Submenu (Task #14) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 25 commands discovered (see Motor Control section)
|
||
- [x] `a` supports relative moves with `+`/`-` prefix (undocumented upstream!)
|
||
- [x] `h *` homes both motors simultaneously
|
||
- [x] `l` — lists 2 motors: 0=AZIMUTH (local), 1=ELEVATION (local)
|
||
- [x] `ma` / `mv` — read motor dynamics (400 deg/s², 65/45 deg/s AZ/EL)
|
||
- [x] `p` — read step positions (19998 AZ, 3116 EL)
|
||
- [x] `elminmaxhome` — EL min=18°, max=65°, home=65°
|
||
- [x] `ela2s` / `els2a` — angle↔step conversion (linear mapping confirmed)
|
||
- [x] `e` / `r` — engage/release motors
|
||
- [x] `azscan` / `azscanwxp` — sky scan commands documented
|
||
- [x] `sd` — stall detection documented
|
||
- [x] `life` / `motorlife` / `motorboth` — factory life test commands
|
||
- [x] `pid`, `sp`, `sw`, `w`, `v`, `vms` — write-only commands documented
|
||
- [ ] `g <az> <el>` — NOT available on G2 (not in help listing)
|
||
- [ ] Test `h 0` and `h 1` homing (requires clear space around dish)
|
||
- [ ] Test `azscanwxp` with real scan parameters (RF imaging)
|
||
|
||
### NVS Experiments (Caution)
|
||
|
||
- [ ] NVS 2 ("Debug 2nd Console Port") — try setting to 1, check if USB
|
||
console activates. **Save original value first, restore after test**
|
||
- [ ] NVS 4 ("Debug Port Connection") — similar test
|
||
- [ ] NVS 112 ("Disable Dipswitch?") — what happens if dipswitch is disabled?
|
||
- [ ] NVS 38 ("Sleep Mode Timer") — currently 420s (7 min). Set higher to
|
||
prevent sleep during long tracking sessions
|
||
|
||
### A3981 Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 6 commands: `diag`, `sm`, `ss`, `st`, `cm`, `reset`
|
||
- [x] `diag` — AZ/EL both OK (no faults)
|
||
- [x] `sm` — step size mode: both AUTO
|
||
- [x] `ss` — step size: both 1 (1/16 microstepping, finest)
|
||
- [x] `st` — torque: both LOW (idle)
|
||
- [x] `cm` — current control mode: both AUTO
|
||
- [ ] Test `diag` output under motor load (move motor, read diag simultaneously)
|
||
- [ ] Test changing step mode from AUTO to manual
|
||
- [ ] `reset` — clear fault flags (no faults to clear currently)
|
||
|
||
### ADC Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 5 commands: `bdid`, `bdrevid`, `rssi`, `m`, `scan`
|
||
- [x] `bdid` → STATIONARY, `bdrevid` → A
|
||
- [x] `rssi` → 232 (noise floor baseline)
|
||
- [x] `scan` — streaming: position + RSSI + Lock + SNR + delta per sample
|
||
- [x] `m` — returns immediately (toggle for background monitoring?)
|
||
|
||
### Dipswitch Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 1 command: `dipswitch`
|
||
- [x] `dipswitch` → val:ffffff01, app_dipswitch:101
|
||
|
||
### GPIO Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 4 commands: `regs`, `r`, `w`, `dir`
|
||
- [x] `regs` — full 101-pin dump (5 ports, all pin states)
|
||
- [x] `r <port> <pin>` / `w <port> <pin>` / `dir <bit> <val>` — help documented
|
||
- [ ] Map specific GPIO pins to hardware functions (SPI→A3981, UART, I2C, etc.)
|
||
|
||
### LATLON Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 1 command: `l <satlon1> <satlon2> <satel1> <satel2>`
|
||
- [x] Tested with satellite positions — self-localization algorithm confirmed
|
||
|
||
### OS Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 2 commands: `id`, `reboot` (no `tasks`/`kill` on G2!)
|
||
- [x] `id` — full system identification including NVS version, MCU details, clock speeds
|
||
- [x] Deep probe: `go`/`date`/`time` initially appeared as hidden commands but were
|
||
confirmed as **false positives** — boot sequence output captured after `reboot`
|
||
caused a system restart mid-probe. All three return "Invalid command" post-boot.
|
||
|
||
### PEAK Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 6 commands: `ts`, `pw`, `psnr`, `pxy1`, `stb`, `rssits`
|
||
- [x] `stb` — LNB polarity switching test (18V=504 RSSI, 13V=232 RSSI)
|
||
- [x] `rssits` — streaming every 1 min, exits submenu on interrupt
|
||
- [x] `pw` / `psnr` help — both take `<az_deg> <el_deg>` (signal peaking algorithms)
|
||
- [x] `pxy1` help — takes `<n>` repeat count (2D cross-pattern peak search)
|
||
- [ ] Test `pw` / `psnr` / `pxy1` with a real satellite signal
|
||
|
||
### EEPROM Submenu (Task #15) — COMPLETE
|
||
|
||
- [x] Full `?` help listing — 3 commands: `ee`, `inv`, `def`
|
||
- [x] Complete EEPROM dump (all 17 indices, 0-16) via `scripts/ee_dump.py`
|
||
- [x] Bounds discovery: firmware enforces Min:0 Max:16
|
||
- [x] Sentinel value: 0x00010101 for invalid/uninitialized entries
|
||
- [x] Only 6 indices (0-5) ever written; 6-16 factory default (invalid)
|
||
- [ ] `def` — restore factory defaults (not tested — would reset all values)
|
||
- [ ] Determine meaning of valid EEPROM values (indices 1-5)
|
||
- [ ] Restore index 0 via `def` or `ee 0 <value>` if original value is discovered
|
||
|
||
### STEP Submenu (Task #16) — COMPLETE
|
||
|
||
- [x] `e` — engage motors ("Motors engaged"), verified via MOT
|
||
- [x] `r` — release motors (documented via MOT, not tested to avoid losing position)
|
||
- [x] `p` — read step positions (AZ=19998, EL=3116)
|
||
- [x] `ma` / `mv` — read accel and velocity in raw microstep units
|
||
- [x] `pid` — **readable in STEP** (write-only in MOT): Kp=250, Kv=50
|
||
- [x] MOT↔STEP conversion table verified (linear mapping)
|
||
- [ ] `p <motor> <pos>` — test absolute microstep move (40000 steps/rev AZ, 24960 EL)
|
||
- [ ] `v <motor> <vel>` — test continuous velocity mode
|
||
|
||
### Hidden Command Deep Probe — COMPLETE
|
||
|
||
Systematic brute-force probe of 415 candidate commands across all 13 menu levels
|
||
(root + 12 submenus). Script: `scripts/hidden_menu_probe.py --deep`
|
||
|
||
**Results by submenu:**
|
||
|
||
| Submenu | Probed | Hits | Known | New | Notes |
|
||
|---------|--------|------|-------|-----|-------|
|
||
| TRK> | 415 | 3 | 3 | 0 | Only q, Q, help |
|
||
| OS> | 415 | 7 | 4 | 0 | `go`/`date`/`time` were false positives (see below) |
|
||
| MOT> | 415 | 22 | 22 | 0 | All in help listing already |
|
||
| DVB> | 415 | 12 | 12 | 0 | All previously discovered |
|
||
| STEP> | 415 | 12 | 12 | 0 | Mirrors MOT (engage/release/pos/vel) |
|
||
| A3981> | 415 | 5 | 5 | 0 | All in help listing already |
|
||
| ADC> | 415 | 7 | 7 | 0 | |
|
||
| GPIO> | 415 | 7 | 7 | 0 | |
|
||
| PEAK> | 415 | 3 | 3 | 0 | |
|
||
| NVS> | 415 | 412 | n/a | 0 | False positives: auto-advance cursor |
|
||
| EE> | 415 | 3 | 3 | 0 | |
|
||
| LATLON> | 415 | 5 | 5 | 0 | |
|
||
| DIPSWITCH> | 415 | 3 | 3 | 0 | |
|
||
|
||
**OS false positives explained:** The probe hit `reboot` early in the OS
|
||
sequence, causing a full system restart (~10s). The probe script continued
|
||
sending commands into the boot stream. `go`, `date`, and `time` appeared as
|
||
"hits" because their responses contained non-error text — but this text was
|
||
**unsolicited boot output**, not command responses:
|
||
|
||
- `go` "response" = SPI2 initialization output (BCM4515 firmware transfer at boot)
|
||
- `date` "response" = BCM4515 hardware init (AP RAM FW VERIFIED, chip IDs)
|
||
- `time` "response" = DVB channel init (dvbPrvChangeChannelInit Complete)
|
||
|
||
All three return "Invalid command" when tested manually in the OS submenu after
|
||
boot completes. The boot output is still valuable — it reveals the SPI2 clock
|
||
(6,857,142 Hz = 48 MHz / 7), SPI mode 3 (CPOL=1, CPHA=1), and the full
|
||
BCM4515 bring-up sequence.
|
||
|
||
**NVS false positives:** The NVS submenu returned 412 hits because its parser
|
||
treats any unrecognized input as "read next entry" — an internal cursor
|
||
auto-advances through the NVS table. These are NOT hidden commands, just the
|
||
fallthrough behavior of the NVS `e` (edit/read) command parser.
|
||
|
||
**Conclusion:** Zero genuinely hidden commands found across all 13 menu levels.
|
||
The G2 firmware shell is well-scoped — no memory access, no flash read/dump,
|
||
no hidden debug backdoors. Firmware extraction requires physical access
|
||
(SWD or EzPort).
|