<commit_before>// Copyright 2016 <NAME>. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// Packages the static files in a .go file.
//go:generate go run ../package/main.go -out static_files_gen.go ../../../web

// dlibox drives the dlibox LED strip on a Raspberry Pi. It runs a web server
// for remote control.
package main

import (
	"io"
	"log"
	"os"
	"runtime"
	"strconv"
	"sync"

	"github.com/maruel/dlibox/go/donotuse/conn/spi"
	"github.com/maruel/dlibox/go/donotuse/devices"
	"github.com/maruel/dlibox/go/donotuse/devices/apa102"
	"github.com/maruel/dlibox/go/donotuse/host"
	"github.com/maruel/dlibox/go/modules"
	"github.com/maruel/dlibox/go/screen"
)

// APA102 contains light specific settings.
type APA102 struct {
	sync.Mutex
	// BusNumber is the SPI bus number to use, defaults to -1.
	BusNumber int
	// Speed of the transfer.
	SPIspeed int64
	// Number of lights controlled by this device. If lower than the actual
	// number of lights, the remaining lights will flash oddly.
	NumberLights int
}

func (a *APA102) ResetDefault() {
	a.Lock()
	defer a.Unlock()
	a.BusNumber = -1
	a.SPIspeed = 10000000
	a.NumberLights = 150
}

func (a *APA102) Validate() error {
	a.Lock()
	defer a.Unlock()
	return nil
}

// initLEDs initializes the LED strip.
func initLEDs(b modules.Bus, fake bool, config *APA102) (*leds, error) {
	var l *leds
	var fakeBytes []byte
	num := config.NumberLights
	if fake {
		// Output (terminal with ANSI codes or APA102).
		// Hardcode to 100 characters when using a terminal output.
		// TODO(maruel): Query the terminal and use its width.
		num = 100
		fakeBytes = []byte("1")
		l = &leds{Display: screen.New(num), b: b, fps: 30}
	} else {
		fps := 60
		if host.MaxSpeed() < 900000 || runtime.NumCPU() < 4 {
			// Use 30Hz on slower devices because it is too slow.
			fps = 30
		}
		s, err := spi.New(config.BusNumber, 0)
		if err != nil {
			return nil, err
		}
		if err = s.Speed(config.SPIspeed); err != nil {
			return nil, err
		}
		a, err := apa102.New(s, config.NumberLights, 255, 6500)
		if err != nil {
			return nil, err
		}
		l = &leds{Display: a, b: b, s: s, fps: fps}
	}
	c, err := b.Subscribe("leds/#", modules.ExactlyOnce)
	if err != nil {
		l.Close()
		return nil, err
	}
	if err := b.Publish(modules.Message{"leds/fake", fakeBytes}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/fps", []byte(strconv.Itoa(l.fps))}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/num", []byte(strconv.Itoa(num))}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/temperature", []byte("255")}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/intensity", []byte("6500")}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	go func() {
		for msg := range c {
			l.onMsg(msg)
		}
	}()
	return l, nil
}

type leds struct {
	devices.Display<commit_msg>Fix LED publish.<commit_after>// Copyright 2016 <NAME>. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// Packages the static files in a .go file.
//go:generate go run ../package/main.go -out static_files_gen.go ../../../web

// dlibox drives the dlibox LED strip on a Raspberry Pi. It runs a web server
// for remote control.
package main

import (
	"io"
	"log"
	"os"
	"runtime"
	"strconv"
	"sync"

	"github.com/maruel/dlibox/go/donotuse/conn/spi"
	"github.com/maruel/dlibox/go/donotuse/devices"
	"github.com/maruel/dlibox/go/donotuse/devices/apa102"
	"github.com/maruel/dlibox/go/donotuse/host"
	"github.com/maruel/dlibox/go/modules"
	"github.com/maruel/dlibox/go/screen"
)

// APA102 contains light specific settings.
type APA102 struct {
	sync.Mutex
	// BusNumber is the SPI bus number to use, defaults to -1.
	BusNumber int
	// Speed of the transfer.
	SPIspeed int64
	// Number of lights controlled by this device. If lower than the actual
	// number of lights, the remaining lights will flash oddly.
	NumberLights int
}

func (a *APA102) ResetDefault() {
	a.Lock()
	defer a.Unlock()
	a.BusNumber = -1
	a.SPIspeed = 10000000
	a.NumberLights = 150
}

func (a *APA102) Validate() error {
	a.Lock()
	defer a.Unlock()
	return nil
}

// initLEDs initializes the LED strip.
func initLEDs(b modules.Bus, fake bool, config *APA102) (*leds, error) {
	var l *leds
	var fakeBytes []byte
	num := config.NumberLights
	if fake {
		// Output (terminal with ANSI codes or APA102).
		// Hardcode to 100 characters when using a terminal output.
		// TODO(maruel): Query the terminal and use its width.
		num = 100
		fakeBytes = []byte("1")
		l = &leds{Display: screen.New(num), b: b, fps: 30}
	} else {
		fps := 60
		if host.MaxSpeed() < 900000 || runtime.NumCPU() < 4 {
			// Use 30Hz on slower devices because it is too slow.
			fps = 30
		}
		s, err := spi.New(config.BusNumber, 0)
		if err != nil {
			return nil, err
		}
		if err = s.Speed(config.SPIspeed); err != nil {
			return nil, err
		}
		a, err := apa102.New(s, config.NumberLights, 255, 6500)
		if err != nil {
			return nil, err
		}
		l = &leds{Display: a, b: b, s: s, fps: fps}
	}
	c, err := b.Subscribe("leds/#", modules.ExactlyOnce)
	if err != nil {
		l.Close()
		return nil, err
	}
	if err := b.Publish(modules.Message{"leds/fake", fakeBytes}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/fps", []byte(strconv.Itoa(l.fps))}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/num", []byte(strconv.Itoa(num))}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/intensity", []byte("255")}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	if err := b.Publish(modules.Message{"leds/temperature", []byte("6500")}, modules.MinOnce, true); err != nil {
		log.Printf("leds: publish failed: %v", err)
	}
	go func() {
		for msg := range c {
			l.onMsg(msg)
		}
	}()
	return l, nil
}

type leds struct {
	devices.Display
{'fraction_non_alphanumeric': 0.15335907335907337, 'fraction_numerical': 0.02532818532818533, 'mean_word_length': 3.3994565217391304, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5285795', 'n_tokens_mistral': 2627, 'n_tokens_neox': 2416, 'n_words': 717}