bl1nky

package module
v0.0.0-...-ead1854 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 25, 2025 License: LGPL-2.1 Imports: 4 Imported by: 2

README

bl1nky

A LED controller for the YaCTF2025 badge, featuring a Go library, CLI tool, and CH552 firmware.

Overview

bl1nky provides USB HID-based control for the 3 LEDs on the YaCTF2025 badge. The project includes:

  • Go Library: Full-featured library for LED control via USB HID
  • CLI Tool: Command-line interface for LED operations and pattern animations
  • Firmware: CH552 microcontroller firmware for the YaCTF2025 badge

Installation

CLI Tool
go install github.com/buglloc/bl1nky/cmd/bl1nky@latest

Or build from source:

cd cmd/bl1nky
go build
Go Library
go get github.com/buglloc/bl1nky
Linux udev Rules

For non-root access on Linux, install the udev rules:

sudo cp udev/70-bl1nky.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger

CLI Usage

The bl1nky CLI provides three main commands: get, set, and pattern.

Get LED State

Get the current state of all LEDs:

# Get current LED state
bl1nky get

# Get current LED state in binary format
bl1nky get --binary

The LED state is represented in left-to-right order: 0b[LED1][LED2][LED3]

  • 1 = LED is on
  • 0 = LED is off
Set LED State

Set the state of all LEDs using binary notation:

# Turn on all LEDs
bl1nky set --state 0b111

# Turn on only LED 1 and LED 3
bl1nky set --state 0b101

# Turn off all LEDs
bl1nky set --state 0b000

# Turn on only LED 1 and LED 2 (0b prefix is optional)
bl1nky set --state 110
Pattern Animations

Execute LED patterns with timing control:

# Use predefined patterns
bl1nky pattern blink
bl1nky pattern wave
bl1nky pattern pulse
bl1nky pattern bounce
bl1nky pattern loop

# Use custom pattern file
bl1nky pattern mypattern.txt

# Use pattern from stdin
echo -e "set 0b111\nwait 500ms\nset 0b000\nwait 500ms" | bl1nky pattern
Pattern Language

Pattern files support the following commands:

  • Set LED state: set 0b101 (turns on LEDs 1 and 3)
  • Wait commands: wait 100ms
  • Repeat blocks: repeat 3 ... end (repeats commands 3 times)
  • Comments: Lines starting with # are ignored

Example pattern file:

# Blink pattern
repeat 5
    set 0b111
    wait 500ms
    set 0b000
    wait 500ms
end

Go Library Usage

Basic Example
package main

import (
    "fmt"
    "log"
    "time"
    
    "github.com/buglloc/bl1nky"
)

func main() {
    // Create a new blinker instance
    blinker, err := bl1nky.NewHIDBl1nky()
    if err != nil {
        log.Fatalf("Failed to create blinker: %v", err)
    }
    
    // Open connection to the device
    if err := blinker.Open(); err != nil {
        log.Fatalf("Failed to open blinker: %v", err)
    }
    defer blinker.Close()
    
    // Turn on all LEDs
    if err := blinker.SetLEDs(bl1nky.Led1 | bl1nky.Led2 | bl1nky.Led3); err != nil {
        log.Fatalf("Failed to set LEDs: %v", err)
    }
    time.Sleep(1 * time.Second)
    
    // Turn off all LEDs
    if err := blinker.SetLEDs(0); err != nil {
        log.Fatalf("Failed to set LEDs: %v", err)
    }
    
    // Get current LED state
    state, err := blinker.GetLEDs()
    if err != nil {
        log.Fatalf("Failed to get LEDs: %v", err)
    }
    fmt.Printf("Current LED state: %s\n", state)
}

Firmware

The firmware is designed for the CH552 microcontroller used in the YaCTF2025 badge.

Building Firmware

Requirements:

Build&&Flash the firmware:

cd firmware
make flash
Firmware Features
  • USB HID interface (VID: 0x1209, PID: 0xF600)
  • Supports 3 LEDs on the YaCTF2025 badge
  • Commands:
    • 0x01: Set LED state
    • 0x02: Get LED state
  • No external dependencies beyond the CH552 SDK
Hardware Configuration

The firmware controls 3 LEDs:

  • LED 1: Controlled via bit 2 (leftmost)
  • LED 2: Controlled via bit 1
  • LED 3: Controlled via bit 0

Technical Details

USB HID Descriptors
  • Vendor ID: 0x1209
  • Product ID: 0xF600
  • Usage Page: 0xFF (Vendor-defined)
  • Usage: 0xCF
Protocol

The device uses USB HID output reports for commands and feature reports for responses.

Set LED State

Send output report:

[0x01, LED_STATE]

Where LED_STATE is a byte with bits representing LED states (1 = on, 0 = off).

Get LED State

Send output report:

[0x02, 0x00]

Receive feature report:

[0x02, LED_STATE]

Predefined Patterns

The CLI includes several built-in patterns:

  • blink: Simple on/off blinking of all LEDs
  • loop: Sequential LED loop
  • wave: Smooth wave effect across LEDs
  • bounce: Bouncing LED effect
  • chase: Chasing LED pattern
  • pulse: Pulsing effect

License

This project is licensed under the GNU Lesser General Public License v2.1. See the LICENSE file for details.

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.

Troubleshooting

Device Not Found
  1. Check if the device is connected: lsusb | grep 1209:f600
  2. Ensure udev rules are installed (Linux)
  3. Try running with sudo (if udev rules aren't set up)
Permission Denied

On Linux, install the udev rules (see Installation section) and replug the device.

Multiple Devices

If you have multiple bl1nky devices, use the --serial flag to specify which device to control.

See Also

Documentation

Index

Examples

Constants

View Source
const (
	LedC = 1 << (3 - iota)
	LedT
	LedF
)
View Source
const (
	ErrorCodeNoDev = iota
	ErrorCodeDevBusy
)
View Source
const (
	VID          = 0x1209
	PID          = 0xF600
	HIDUsagePage = 0xFF
	HIDUsage     = 0xCF
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Blinker

type Blinker interface {
	Open() error
	Close() error
	SetLEDs(LedSet) error
	GetLEDs() (LedSet, error)
}

type ErrCode

type ErrCode uint8

type Error

type Error struct {
	Code ErrCode
	Msg  string
}

func NewError

func NewError(code ErrCode, msg string) *Error

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(err error) bool

func (*Error) IsPermanent

func (e *Error) IsPermanent() bool

type HIDBl1nky

type HIDBl1nky struct {
	// contains filtered or unexported fields
}

func NewHIDBl1nky

func NewHIDBl1nky(opts ...Option) (*HIDBl1nky, error)
Example
package main

import (
	"log"

	"github.com/buglloc/bl1nky"
)

func main() {
	h, err := bl1nky.NewHIDBl1nky()
	if err != nil {
		log.Fatalf("create bl1nky: %v\n", err)
	}

	if err := h.Open(); err != nil {
		log.Fatalf("open device: %v\n", err)
	}
	defer h.Close()

	// Turn on LED C and LED F
	err = h.SetLEDs(bl1nky.LedC | bl1nky.LedF)
	if err != nil {
		log.Fatalf("set LEDs: %v\n", err)
	}

	// Read current LED state
	leds, err := h.GetLEDs()
	if err != nil {
		log.Fatalf("get LEDs: %v\n", err)
	}
	log.Printf("Current LED state: 0b%08b\n", leds)
}

func (*HIDBl1nky) Close

func (h *HIDBl1nky) Close() error

func (*HIDBl1nky) GetLEDs

func (h *HIDBl1nky) GetLEDs() (LedSet, error)

func (*HIDBl1nky) Location

func (h *HIDBl1nky) Location() string

func (*HIDBl1nky) Open

func (h *HIDBl1nky) Open() error

func (*HIDBl1nky) SetLEDs

func (h *HIDBl1nky) SetLEDs(leds LedSet) error

type HIDDevice

type HIDDevice struct {
	// contains filtered or unexported fields
}

func FirstHIDDevice

func FirstHIDDevice() (*HIDDevice, error)

func HIDEnumerate

func HIDEnumerate(filters ...func(d *usbhid.Device) bool) ([]*HIDDevice, error)

func (*HIDDevice) Close

func (d *HIDDevice) Close() error

func (*HIDDevice) GetFeatureReport

func (d *HIDDevice) GetFeatureReport() ([]byte, error)

func (*HIDDevice) IsOpen

func (d *HIDDevice) IsOpen() bool

func (*HIDDevice) Location

func (d *HIDDevice) Location() string

func (*HIDDevice) Open

func (d *HIDDevice) Open() error

func (*HIDDevice) Path

func (d *HIDDevice) Path() string

func (*HIDDevice) SetOutputReport

func (d *HIDDevice) SetOutputReport(report []byte) error

type LedSet

type LedSet byte

func (LedSet) String

func (l LedSet) String() string

type NopBl1nky

type NopBl1nky struct{}

func NewNopBl1nky

func NewNopBl1nky() *NopBl1nky

func (*NopBl1nky) Close

func (*NopBl1nky) Close() error

func (*NopBl1nky) GetLEDs

func (*NopBl1nky) GetLEDs() (LedSet, error)

func (*NopBl1nky) Open

func (*NopBl1nky) Open() error

func (*NopBl1nky) SetLEDs

func (*NopBl1nky) SetLEDs(LedSet) error

type Option

type Option interface {
	// contains filtered or unexported methods
}

func WithDevice

func WithDevice(dev *HIDDevice) Option

func WithDeviceSerial

func WithDeviceSerial(serial string) Option

Directories

Path Synopsis
cmd
bl1nky module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL