Skip to content

Segment display and clock face

Hardware interface

The Mini has a 30-element monochrome display driven through /dev/is31fl32xx. Logically it is four seven-element digit groups plus two colon indicators: indices 0–6, 7–13, 14–20, and 21–27 form the four digit positions; indices 28–29 are the colon. Animations also use these segments for eyes, icons, and loading effects.

Decompiled: both voice-agent (0x14c6d4, constructor body) and check-factory-reset (sub_10C00) open /dev/is31fl32xx and issue ioctl 0x80046b02 to query the element count. The expected count is exactly 30. Frame updates use LEDS_IS31FL32XX_CONTROL_IOCTL_SET (check-factory-reset:0x17264; normal agent 0x2b9910).

The separate RGB ring uses /dev/topleds; do not confuse the two interfaces.

JSON-to-hardware index map

voice-agent:0x2b9910 does not write JSON indices directly. It applies the 30-byte permutation at file offset 0xa1a218 before the ioctl. The complete logical-index → driver-index map is:

JSON indices Driver indices in the same order
0–9 1, 28, 21, 17, 22, 29, 24, 26, 25, 19
10–19 18, 23, 27, 20, 16, 15, 0, 2, 7, 5
20–29 6, 4, 3, 10, 12, 11, 14, 13, 8, 9

Use this table when capturing physical glyphs or writing a new animation. The JSON schema remains the canonical userspace representation.

JSON format and timing

Display animations are arrays under /usr/share/voice-agent/led/:

[
  {
    "duration": 0.0166,
    "brightness": [0, 3, 22, 54, 85]
  }
]

The example is abbreviated; real Mini frames have 30 brightness entries, 0–255. duration is seconds. seconds is an alternative timestamp form: the next frame duration is computed from the timestamp difference. A caller supplying an FPS argument overrides per-frame durations. The shared parser accepts up to 72 monochrome values and up to 24 RGB colors, logging too many values above those limits.

Decompiled: led_animation_parser.cpp stores each parsed frame in a 96-byte internal structure. The reset renderer waits with pthread_cond_clockwait.

State/resource map

The following associations are observed from filenames and direct string references in voice-agent.

State Display resources
Ready/idle ready_digits.json, eyesReady_digits.json
Intro/blink eyesIntro_digits.json, eyesBlink1_digits.json, eyesBlink2_digits.json, eyesHappy_digits.json
Setup settingsEnter_digits.json, settings_intro and related RGB sequences
OTA download downloadIconLoop_digits.json
Bluetooth btWaiting_digits.json, btConnected_digits.json, btDisconnected_digits.json
Track navigation nextTrack_digits.json, prevTrack_digits.json
Factory reset resetIconLoop_digits.json, factoryResetEnter_digits.json
Hidden reset joke factoryResetJoke_digits.json
Demonstration Demo_Digits.json, Demo_Digits_frame_1.json through frame_8

Additional monochrome eye/loader/demo assets include Eyes_*.json, Loader-4.json, Loader-5.json, One_eye_open.json, Tennis.json, and Thinking_warms.json.

Reset-specific rendering

Decompiled from check-factory-reset:sub_10C00:

  1. During the five-second combo window, resetIconLoop_digits.json is repeated to fill the requested duration.
  2. If the combo completes, factoryResetEnter_digits.json plays once as the final display sequence.
  3. Both display and RGB updates stop by writing an all-zero frame afterward.

The normal agent has a separate hidden-joke path. voice-agent:0x1442e0 (doFun) handles more than 19 activations by selecting factoryResetJoke_digits.json, factoryResetJoke_diodes.json, and 30_reset_v3.flac; this is an Easter egg, not the actual wipe trigger.

Ambient-light brightness

voice-agent:0x27bf20 reads the IIO illuminance channel and maps it to 0–100%:

  • below 5.0: 0%;
  • above 3000.0: 100%;
  • otherwise int(19.937704 * ln(0.05 * lux + 0.75)).

Updates are suppressed when the percentage changes by five or fewer points unless the difference crosses the configured dead band. Clock settings separately expose clock_brightness, clock_night_brightness, and day_clock_brightness; adjustCapsulaMiniClockBrightness clamps manual adjustment to 0–100.

The live read-only sample was 0.239 in the sensor's raw units. No unit conversion to lux is claimed; the formula above uses the binary's lux variable name for its input.