seveibar/f1c1990s-dev-board

This code manages the entire PCB assembly process for a computer hardware module, including component placement, schematic integration, automated routing, copper pouring, and design rule checks, focused on a four-layer carrier board with integrated support components and connectors.

Version
1.8.0
License
unset
Stars
0

firmware/rgb-demo.py

#!/usr/bin/env python3
"""SK9822-A indicator, using libgpiod 2.x and Linux GPIO character devices.

PE2 = data, PE3 = clock. This exact SK9822-A variant transmits GRB, not
APA102's usual BGR order; see its Rev.01 datasheet, page 6.
"""
import argparse
import time


def frame(red, green, blue, brightness=2):
    if not all(isinstance(x, int) and 0 <= x <= 255 for x in (red, green, blue)):
        raise ValueError("RGB channels must be integers in 0..255")
    if not isinstance(brightness, int) or not 0 <= brightness <= 2:
        raise ValueError("Indicator brightness is limited to 0..2 of 31")
    # Start, one pixel (111 + five brightness bits + G/R/B), end frame.
    # Extra zeros also provide the reset/latch clocks required by SK9822 variants.
    return bytes(4) + bytes([0xE0 | brightness, green, red, blue]) + b'\xff'*4 + bytes(4)


def main():
    p = argparse.ArgumentParser(description=__doc__)
    p.add_argument('--chip', default='/dev/gpiochip0', help='PIO GPIO chip from gpioinfo')
    p.add_argument('--rgb', nargs=3, type=int, default=[255, 0, 0], metavar=('R', 'G', 'B'))
    p.add_argument('--brightness', type=int, choices=range(3), default=2)
    p.add_argument('--seconds', type=float, default=3)
    p.add_argument('--demo', action='store_true', help='cycle red, green, blue and white')
    p.add_argument('--dry-run', action='store_true', help='print frame without using GPIO')
    args = p.parse_args()
    try:
        data = frame(*args.rgb, args.brightness)
    except ValueError as e:
        p.error(str(e))
    if args.seconds < 0:
        p.error('--seconds must be nonnegative')
    if args.dry_run:
        print(data.hex(' '))
        return
    import gpiod
    from gpiod.line import Direction, Value
    low, high = Value.INACTIVE, Value.ACTIVE
    # Names prevent silently targeting different GPIOs if chip numbering changes.
    with gpiod.request_lines(args.chip, consumer='sk9822-indicator', config={
        ('PE2', 'PE3'): gpiod.LineSettings(direction=Direction.OUTPUT, output_value=low)
    }) as req:
        def send(payload):
            for byte in payload:
                for bit in range(7, -1, -1):
                    req.set_value('PE3', low)
                    req.set_value('PE2', high if byte & (1 << bit) else low)
                    time.sleep(0.00001)
                    req.set_value('PE3', high)
                    time.sleep(0.00001)
            req.set_value('PE3', low)
            req.set_value('PE2', low)
        try:
            send(frame(0, 0, 0, 0))
            colors = [(255,0,0),(0,255,0),(0,0,255),(255,255,255)] if args.demo else [args.rgb]
            for color in colors:
                send(frame(*color, args.brightness))
                time.sleep(args.seconds)
        finally:
            send(frame(0, 0, 0, 0))


if __name__ == '__main__':
    main()