Skip to content

API Reference: LED & Button Control

📌 After reading this page: You will be able to control all three onboard LEDs and three buttons using both polling and event-driven approaches. ⏱️ Estimated reading time: 15 minutes 🧰 Prerequisites: Ex.01 (polling) + Ex.02 (event-driven) + Ex.03 (long press) 🎯 Key functions: XM_SetLedState / XM_SetLedEffect / XM_GetButtonState / XM_GetButtonEvent / XM_SetChannelLedRGB (Rev2.0)

This is the detailed reference for the onboard UI (LED, Button) control API defined in xm_api_led_btn.h. The XM10 firmware lets you implement advanced input/output features — Blink, Click, Long Press, and more — with simple function calls, so you never need to write timer interrupts or debouncing logic yourself.


1. How It Works

This module is time-driven. Behind the scenes, internal Managers run continuously in the background to make everything work.

The Core Engine: XM_IO_Update()

  • Role: This is the engine that calculates LED blink timing, analyzes button signals, removes noise (debouncing), and generates events.
  • Execution: Called automatically by the system at a 1 ms (1 kHz) interval. You do not need to call it yourself, but understanding its role is important.
  • Flow:
    1. User calls XM_SetLedEffect → settings are stored.
    2. XM_IO_Update runs periodically → toggles the LED ON/OFF as time passes.
    3. User presses a button → XM_IO_Update measures elapsed time → determines "click" or "long press" and stores the result in the event queue.
    4. User calls XM_GetButtonEvent → retrieves the event from the queue and returns it.

2. Data Structures (Enumerations)

All identifiers and state values are defined as enums for ease of use. Use these named constants instead of raw numbers (0, 1, 2...).

2.1. Identifiers

XmLedId_t

Identifies the Function LED to control.

typedef enum {
    XM_LED_1 = 1, /**< Left LED */
    XM_LED_2 = 2, /**< Center LED */
    XM_LED_3 = 3  /**< Right LED */
} XmLedId_t;

XmBtnId_t

Identifies the Function Button to read.

typedef enum {
    XM_BTN_1 = 1, /**< Left button */
    XM_BTN_2 = 2, /**< Center button */
    XM_BTN_3 = 3  /**< Right button */
} XmBtnId_t;

2.2. State Types

XmState_t

Represents the logical ON/OFF state of an LED or similar output.

typedef enum {
    XM_OFF = 0, /**< Off (Logic Low) */
    XM_ON  = 1  /**< On (Logic High) */
} XmState_t;

XmBtnState_t

Represents the current physical press state of a button. (Abstracted away from the circuit's Active-High/Low polarity.)

typedef enum {
    XM_RELEASED = 0, /**< Button is not pressed */
    XM_PRESSED  = 1  /**< Button is pressed */
} XmBtnState_t;

2.3. Modes & Events

XmLedMode_t

Determines the LED behavior pattern.

Mode Description
XM_LED_OFF Turns the LED off.
XM_LED_SOLID Keeps the LED on continuously.
XM_LED_BLINK Blinks at a fixed period (50% duty cycle).
XM_LED_HEARTBEAT Flashes twice in quick succession, like a heartbeat.
XM_LED_ONESHOT Turns on for a set duration, then turns off automatically. (Useful for notifications.)

XmBtnEvent_t

High-level events generated by analyzing button input.

Event Description
XM_BTN_NONE No event detected
XM_BTN_PRESSED Button was just pressed (rising edge)
XM_BTN_RELEASED Button was just released (falling edge)
XM_BTN_CLICK Short press and release (click)
XM_BTN_LONG_PRESS Held for 1 second or more (use for mode changes, etc.)

3. Function Reference

3.1. LED Control Functions

XM_SetLedState

Turns an LED on or off directly. This is the most straightforward control function.

  • Syntax
    void XM_SetLedState(XmLedId_t led_id, XmState_t state);
    
  • Parameters
    • led_id: The LED to control (XM_LED_1 \~ 3)
    • state: Target state (XM_ON, XM_OFF)
  • Example
    // Turn LED 1 on
    XM_SetLedState(XM_LED_1, XM_ON);
    

XM_SetLedEffect

Applies a special effect (such as blinking) to an LED. Once set, XM_IO_Update() drives the effect automatically — no timer code required.

  • Syntax
    void XM_SetLedEffect(XmLedId_t led_id, XmLedMode_t mode, uint32_t period_ms);
    
  • Parameters
    • led_id: The LED to control
    • mode: Behavior mode (XM_LED_BLINK, XM_LED_HEARTBEAT, etc.)
    • period_ms: Period or duration of the effect, in milliseconds
      • BLINK: Blink period (e.g., 500 = blink every 0.5 s)
      • ONESHOT: On-time duration (e.g., 200 = stay on for 0.2 s then turn off)
      • SOLID/OFF: Ignored (pass 0)
  • Example
    // Blink LED 2 every 0.5 s
    XM_SetLedEffect(XM_LED_2, XM_LED_BLINK, 500);
    
    // Set LED 3 to heartbeat mode with a 1 s period
    XM_SetLedEffect(XM_LED_3, XM_LED_HEARTBEAT, 1000);
    

3.2. Button Control Functions

XM_GetButtonState

Reads the current physical state of a button in real time. (Polling approach.)

  • Syntax
    XmBtnState_t XM_GetButtonState(XmBtnId_t btn_id);
    
  • Parameters
    • btn_id: The button to read (XM_BTN_1 \~ 3)
  • Returns: XM_PRESSED (pressed) or XM_RELEASED (not pressed)
  • Example
    // Execute only while button 1 is held down
    if (XM_GetButtonState(XM_BTN_1) == XM_PRESSED) {
        // ... perform action ...
    }
    

XM_GetButtonEvent

Retrieves the latest event generated by a button. (Event-driven approach.) Each event is consumed once it is read — it is removed from the internal queue (Read-Clear). Store the return value in a variable or use it directly in a switch statement.

  • Syntax
    XmBtnEvent_t XM_GetButtonEvent(XmBtnId_t btn_id);
    
  • Parameters
    • btn_id: The button to read
  • Returns: The detected event (XM_BTN_CLICK, XM_BTN_LONG_PRESS, etc.)
  • Example
    XmBtnEvent_t evt = XM_GetButtonEvent(XM_BTN_1);
    
    if (evt == XM_BTN_CLICK) {
        // Fires once when button 1 is clicked
        XM_SendUsbDebugMessage("Button 1 Clicked!\r\n");
    } 
    else if (evt == XM_BTN_LONG_PRESS) {
        // Fires once when button 1 is long-pressed
        XM_SendUsbDebugMessage("Button 1 Long Pressed!\r\n");
    }
    

3.3. Channel LED (Rev2.0 Only)

XM_SetChannelLedRGB

Rev2.0 only — Not available on Rev1.1.

Controls per-channel RGB LEDs driven by the PCA9957. Use this to visually indicate the connection status of sensor modules.

  • Syntax
    void XM_SetChannelLedRGB(XmChannelLed_t ch, uint8_t r, uint8_t g, uint8_t b);
    
  • Parameters

    Name Description
    ch Channel identifier (XM_CH_LED_EMG, XM_CH_LED_FES, XM_CH_LED_IMU, XM_CH_LED_HMMG, XM_CH_LED_GRF_L, XM_CH_LED_GRF_R, XM_CH_LED_USB)
    r Red brightness (0–255)
    g Green brightness (0–255)
    b Blue brightness (0–255)
  • Note: Setting r=0, g=0, b=0 restores automatic system control.

  • Example

    XM_SetChannelLedRGB(XM_CH_LED_IMU, 255, 0, 0);  // Set IMU LED to red
    XM_SetChannelLedRGB(XM_CH_LED_IMU, 0, 0, 0);     // Restore automatic system control
    


3.4. System Functions

XM_IO_Update

[System-managed] The driving function that updates LED and button states. This must be called periodically from the control-loop task (Control_Loop) — in Control_Loop or inside XM_TSM_Run — for Blink and Long Press to work correctly.

  • Syntax
    void XM_IO_Update(void);
    
  • Note: The system calls this automatically while it collects inputs, so end users do not normally need to call it directly.

⚠️ Common Mistakes

Symptom Cause Fix
LED blink mode is set but nothing happens XM_IO_Update is not being called (the control-loop task (Control_Loop) has stalled, or XM_TSM_Run is missing) The system calls it automatically — check that your user code is not stuck in an infinite loop
GetButtonEvent returns the same event multiple times GetButtonEvent is being called in more than one place inside Run_Loop (concurrent Read-Clear consumers) Read each event channel from exactly one place
XM_BTN_LONG_PRESS never triggers Hold time is less than 1 second Hold the button for at least 1 second
SetLedState has no effect after SetLedEffect Effect mode takes priority — SetLedState is ignored or overwritten Call SetLedEffect(LED, XM_LED_OFF, 0) to cancel the effect first
Center/right button presses are not detected, or map to the wrong XM_BTN_N Built with a ZIP for the wrong board revision — the onboard button MCU pins are shifted by one position between Rev1.1 (PC10/11/12) and Rev2.0 (PC11/12/13) Confirm your board revision from the board label, then re-import using the correct revision's ZIP (Board Revision Comparison)
Channel LED RGB does nothing Using Rev1.1 — PCA9957 is not populated Rev2.0 only — Rev1.1 has three onboard LEDs only
ONESHOT LED does not re-fire after the first time This is by design (one-shot) To re-trigger it, call SetLedEffect again on each event

Example Difficulty LED / Button Usage
00_Quick_Start Beginner Boot sequence + toggle
01_Button_LED_Basic Beginner Polling state mirror
02_Button_LED_Event Beginner Event-driven + ONESHOT
03_Button_LED_FSM Intermediate Long press + Heartbeat/Blink
18_Debug_Monitor Intermediate Diagnostic LED patterns